我创建了一个简单的android应用程序,该应用程序仅从Apple网站解析XML。
它具有解析前十首“歌曲”,“付费应用程序”或“免费应用程序”的菜单。

对于网络通话,我使用凌空抽射。现在,当我看到旋转设备时的日志时,processXml()-从URL获取xml并将其放在列表视图中-多次调用,分别在onCreate()和onRestoreInstanceState()中。恕我直言,这可能是多余的下载。

我的问题 :


我将processXml()放在错误的地方吗?如果是这样,在哪里应该避免冗余网络呼叫?
由于我使用齐射,是否有任何方法可以缓存响应并在设备旋转时使用它?我想我已经在VolleySingleton上写了缓存,但是我不知道我的实现是否正确


非常感谢

这是日志

// start of app
04-13 09:14:36.456 MainActivity: onCreate: processXml() called

// select "songs" from menu
04-13 09:14:49.627 MainActivity: onOptionsItemSelected: processXml() called

// rotate device
04-13 09:14:55.758 MainActivity: onCreate: processXml() called


这是我在MainACtivity.java上的源代码
公共类MainActivity扩展了AppCompatActivity {

private static final String TAG = "MainActivity";
private static final String KEY_RSS_URL = "KEY_RSS_URL";
private static final String KEY_FEED_LIMIT = "KEY_FEED_LIMIT";
private String rssUrl = "http://ax.itunes.apple.com/WebObjects/MZStoreServices.woa/ws/RSS/topfreeapplications/limit=%d/xml";
private int feedLimit = 10;

private ListView xmlListView;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    this.xmlListView = (ListView) findViewById(R.id.xmlListView);

    if (savedInstanceState != null) {
        this.rssUrl = savedInstanceState.getString(KEY_RSS_URL);
        this.feedLimit = savedInstanceState.getInt(KEY_FEED_LIMIT);
    }

    // need to put it here because when app start, it should already display top 10 free aps
    processRss(String.format(this.rssUrl, this.feedLimit));
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
  ... create menu
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    int itemId = item.getItemId();

    switch (itemId) {
        case R.id.mnuFree:
            this.rssUrl = "http://ax.itunes.apple.com/WebObjects/MZStoreServices.woa/ws/RSS/topfreeapplications/limit=%d/xml";
            break;
        case R.id.mnuPaid:
            this.rssUrl = "http://ax.itunes.apple.com/WebObjects/MZStoreServices.woa/ws/RSS/toppaidapplications/limit=%d/xml";
            break;
        case R.id.mnuSongs:
            this.rssUrl = "http://ax.itunes.apple.com/WebObjects/MZStoreServices.woa/ws/RSS/topsongs/limit=%d/xml";
            break;
        default:
            return super.onOptionsItemSelected(item);
    }

    processRss(String.format(this.rssUrl, this.feedLimit));
    Log.d(TAG, "onOptionsItemSelected: processRss() called");

    return true;
}

@Override
protected void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);

    outState.putString(KEY_RSS_URL, this.rssUrl);
    outState.putInt(KEY_FEED_LIMIT, this.feedLimit);
}

@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
    super.onRestoreInstanceState(savedInstanceState);

    this.rssUrl = savedInstanceState.getString(KEY_RSS_URL);
    this.feedLimit = savedInstanceState.getInt(KEY_FEED_LIMIT);

    processRss(String.format(this.rssUrl, this.feedLimit));
    Log.d(TAG, "onRestoreInstanceState: processRss() called");
}

private void processRss(String rssUrl) {
    StringRequest stringRequest = new StringRequest(Request.Method.GET, rssUrl, new Response.Listener<String>() {
        @Override
        public void onResponse(String response) {
            ParseApplication parseApplication = new ParseApplication();
            if (parseApplication.parse(response)) {
                ArrayAdapter<FeedEntry> arrayAdapter = new FeedAdapter(
                        MainActivity.this,
                        R.layout.list_record,
                        parseApplication.getApplications(),
                        VolleySingleton.getInstance(MainActivity.this).getImageLoader());

                xmlListView.setAdapter(arrayAdapter);
            }
        }
    }, new Response.ErrorListener() {
        @Override
        public void onErrorResponse(VolleyError error) {
            Log.e(TAG, "onErrorResponse: from volley : " + error.getMessage());
        }
    });

    VolleySingleton.getInstance(this).addToRequestQueue(stringRequest);
}


}

对于VolleySingleton,我使用以下代码,而getRequestQueue使用缓存

公共课VolleySingleton {

private static VolleySingleton mInstance;
private static Context mCtx;
private RequestQueue mRequestQueue;
private ImageLoader mImageLoader;

private VolleySingleton(Context context) {
    mCtx = context;
    mRequestQueue = getRequestQueue();

    mImageLoader = new ImageLoader(mRequestQueue,
            new ImageLoader.ImageCache() {
                private final LruCache<String, Bitmap>
                        cache = new LruCache<String, Bitmap>(20);

                @Override
                public Bitmap getBitmap(String url) {
                    return cache.get(url);
                }

                @Override
                public void putBitmap(String url, Bitmap bitmap) {
                    cache.put(url, bitmap);
                }
            });
}

public static synchronized VolleySingleton getInstance(Context context) {
    if (mInstance == null) {
        mInstance = new VolleySingleton(context);
    }
    return mInstance;
}

private RequestQueue getRequestQueue() {
    if (mRequestQueue == null) {
        File cacheDir = new File(mCtx.getCacheDir(), "VOLLEY_CACHE_DIR");
        mRequestQueue = new RequestQueue(
                new DiskBasedCache(cacheDir, 512 * 512),
                new BasicNetwork(new HurlStack()));

        mRequestQueue.start();
    }
    return mRequestQueue;
}

public <T> void addToRequestQueue(Request<T> req) {
    getRequestQueue().add(req);
}

public ImageLoader getImageLoader() {
    return mImageLoader;
}


}

最佳答案

我将processXml()放在错误的地方吗?如果是这样,在哪里应该避免冗余网络呼叫?
  


是的,您要在两个地方调用该方法。不应在onRestoreInstanceState中重复相同的调用,而应保留对正在进行的请求的引用。有几种方法可以做到这一点。他们之中有一些是:


使用getLastNonConfigurationInstance
使用Service并广播对您的活动(http://www.truiton.com/2014/09/android-service-broadcastreceiver-example/)的网络响应
使用Loadershttps://medium.com/google-developers/making-loading-data-on-android-lifecycle-aware-897e12760832



  
  由于我使用齐射,是否有任何方法可以缓存响应并在设备旋转时使用它?我想我已经在VolleySingleton上写了缓存,
  但我不知道我的实现是否正确
  


您正在使用DiskBasedCache,它看起来与Android documentation中的示例相同。您可以通过关闭网络连接(数据和wifi)并旋转设备来轻松检查其是否正常工作。您还可以检查Volley代码以了解其如何使用缓存。

10-07 19:26
查看更多