使用volley避免在Android设备上轮换冗余网络呼叫

时间:2017-04-13 02:46:18

标签: java android networking android-volley

我创建了一个简单的Android应用程序,它只是从Apple网站解析XML。 它有解析前10首“歌曲”,“付费应用程序”或“免费应用程序”的菜单。

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

我的问题:

  1. 我把processXml()放在错误的地方?如果是,那么避免冗余网络呼叫的正确位置在哪里?
  2. 因为我使用凌空,有没有办法缓存响应并在设备旋转时使用它?我想我已经在VolleySingleton上写了缓存,但我不知道我的实现是否正确
  3. 非常感谢

    这是日志

    // 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;
    }
    

    }

1 个答案:

答案 0 :(得分:1)

  
      
  1. 我把processXml()放在错误的地方?如果是,那么避免冗余网络呼叫的正确位置在哪里?
  2.   

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

  
      
  1. 因为我使用凌空,有没有办法缓存响应并在设备旋转时使用它?我想我已经在VolleySingleton上写了缓存,   但我不知道我的实施是否正确
  2.   

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