gpt4 book ai didi

java - 使用 volley 避免 Android 设备旋转时的冗余网络调用

转载 作者:行者123 更新时间:2023-11-30 00:36:11 26 4
gpt4 key购买 nike

我创建了一个简单的 android 应用程序,它只解析来自苹果网站的 XML。它有解析前 10 名“歌曲”、“付费应用程序”或“免费应用程序”的菜单。

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

我的问题:

  1. 我把 processXml() 放错地方了吗?如果是这样,避免冗余网络调用的正确位置在哪里?
  2. 因为我使用 volley,有什么方法可以缓存响应并在设备旋转时使用它?我想我在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 上的源代码公共(public)类 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 使用缓存

公共(public)类 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. am I put processXml() on a wrong place? If so, where is the correct place to avoid redundant network call?

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

  1. since I use volley, is there any way to cache response and use it when device rotate? I think I've write the cache on VolleySingleton, but I don't know if my implementation is correct

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

关于java - 使用 volley 避免 Android 设备旋转时的冗余网络调用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43382700/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com