Volley 缓存机制的问题
Issues with Volley caching mechanism
我有一个每天发布新闻的网站。
现在,我发送 JsonArrayRequest 来检索和解析网站上发布的每条新闻的标题和摘要。解析后的项目然后用于填充 RecyclerView。
我遇到的问题是 volley 实现缓存的方式。
让我们来看看这个场景:安装、启动应用程序并填充 RecyclerView。用户阅读新闻而忘记了应用程序
稍后,用户启动应用并获取项目并填充 RecyclerView。
在第一次和第二次发布之间,网站上发布了新消息。但是在第二次启动时,这些新项目并没有显示出来。但是,如果用户手动转到应用程序设置并清除应用程序的缓存,然后重新启动,则会显示新项目。
你明白我的意思了吗?
虽然我不想禁用 Volley 缓存,但如何让它始终获取新项目?
编辑
MainActivity
public class MainActivity extends AppCompatActivity {
private final String TAG = "MainActivity";
//Creating a list of newss
private List<NewsItems> mNewsItemsList;
//Creating Views
private RecyclerView recyclerView;
private RecyclerView.Adapter adapter;
private RecyclerView.LayoutManager layoutManager;
private ProgressDialog mProgressDialog;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.d(TAG, "onCreate called");
//Initializing Views
recyclerView = (RecyclerView) findViewById(R.id.news_recycler);
LinearLayoutManager layoutManager = new LinearLayoutManager(this);
recyclerView.setLayoutManager(layoutManager);
//Initializing the newslist
mNewsItemsList = new ArrayList<>();
adapter = new NewsAdapter(mNewsItemsList, this);
recyclerView.setAdapter(adapter);
if (NetworkCheck.isAvailableAndConnected(this)) {
//Calling method to get data
getData();
} else {
//Codes for building Alert Dialog
alertDialogBuilder.setPositiveButton(R.string.alert_retry, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
if (!NetworkCheck.isAvailableAndConnected(mContext)) {
alertDialogBuilder.show();
} else {
getData();
}
}
});
alertDialogBuilder.setNegativeButton(R.string.alert_cancel, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
finish();
}
});
alertDialogBuilder.show();
}
}
//This method will get data from the web api
private void getData(){
Log.d(TAG, "getData called");
//Codes for Showing progress dialog
//Creating a json request
JsonArrayRequest jsonArrayRequest = new JsonArrayRequest(ConfigNews.GET_URL + getNumber(),
new Response.Listener<JSONArray>() {
@Override
public void onResponse(JSONArray response) {
Log.d(TAG, "onResponse called");
//Dismissing the progress dialog
if (mProgressDialog != null) {
mProgressDialog.hide();
}
//calling method to parse json array
parseData(response);
}
},
new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
}
});
//Creating request queue
RequestQueue requestQueue = Volley.newRequestQueue(this);
//Adding request to the queue
requestQueue.add(jsonArrayRequest);
}
//This method will parse json data
private void parseData(JSONArray array){
Log.d(TAG, "Parsing array");
for(int i = 0; i<array.length(); i++) {
NewsItems newsItem = new NewsItems();
JSONObject jsonObject = null;
try {
jsonObject = array.getJSONObject(i);
newsItem.setNews_title(jsonObject.getString(ConfigNews.TAG_VIDEO_TITLE));
newsItem.setNews_body(jsonObject.getString(ConfigNews.TAG_VIDEO_BODY));
} catch (JSONException w) {
w.printStackTrace();
}
mNewsItemsList.add(newsItem);
}
adapter.notifyItemRangeChanged(0, adapter.getItemCount());
}
@Override
public void onDestroy() {
super.onDestroy();
Log.d(TAG, "onDestroy called");
if (mProgressDialog != null){
mProgressDialog.dismiss();
Log.d(TAG, "mProgress dialog dismissed");
}
}
}
选项 1) 删除缓存
在拨打电话之前,您可以通过 myDiskBasedCache.clear()
删除整个缓存或通过 myDiskBasedCache.remove(entryUrl)
删除特定条目
选项 2) 自定义 CacheParser(在请求中)
@Override
protected Response<Bitmap> parseNetworkResponse(NetworkResponse response) {
Response<Bitmap> resp = super.parseNetworkResponse(response);
if(!resp.isSuccess()) {
return resp;
}
long now = System.currentTimeMillis();
Cache.Entry entry = resp.cacheEntry;
if(entry == null) {
entry = new Cache.Entry();
entry.data = response.data;
entry.responseHeaders = response.headers;
entry.ttl = now + 60 * 60 * 1000; //keeps cache for 1 hr
}
entry.softTtl = 0; // will always refresh
return Response.success(resp.result, entry);
}
选项 3) 发送不缓存的请求
myRequest.setShouldCache(false);
选项 4) 使用自定义缓存实现
更新:
您的代码示例:
//Creating a json request
JsonArrayRequest jsonArrayRequest = new JsonArrayRequest(ConfigNews.GET_URL + getNumber(),
new Response.Listener<JSONArray>() {
@Override
public void onResponse(JSONArray response) {
Log.d(TAG, "onResponse called");
//Dismissing the progress dialog
if (mProgressDialog != null) {
mProgressDialog.hide();
}
//calling method to parse json array
parseData(response);
}
},
new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
}
}) {
@Override
protected Response<JSONArray> parseNetworkResponse(NetworkResponse response) {
Response<JSONArray> resp = super.parseNetworkResponse(response);
if(!resp.isSuccess()) {
return resp;
}
long now = System.currentTimeMillis();
Cache.Entry entry = resp.cacheEntry;
if(entry == null) {
entry = new Cache.Entry();
entry.data = response.data;
entry.responseHeaders = response.headers;
entry.ttl = now + 60 * 60 * 1000; //keeps cache for 1 hr
}
entry.softTtl = 0; // will always refresh
return Response.success(resp.result, entry);
}
};
更新 2
Http 协议缓存 支持多种方式来定义客户端如何缓存响应以及何时更新它们。 Volley 将这些规则简化为:
- entry.ttl(以毫秒为单位的生存时间)如果大于当前时间则可以使用缓存,否则需要重新请求
和
entry.softTtl(软时间以ms为单位:)如果大于当前时间
缓存是绝对有效的,不需要向服务器发出请求,否则仍然会发出新请求(即使 ttl 是好的),如果有变化,将传递新的响应。
请注意,如果 ttl 有效而 softTtl 无效,您可以收到 2 个 onResponse 调用
我有一个每天发布新闻的网站。
现在,我发送 JsonArrayRequest 来检索和解析网站上发布的每条新闻的标题和摘要。解析后的项目然后用于填充 RecyclerView。
我遇到的问题是 volley 实现缓存的方式。
让我们来看看这个场景:安装、启动应用程序并填充 RecyclerView。用户阅读新闻而忘记了应用程序
稍后,用户启动应用并获取项目并填充 RecyclerView。
在第一次和第二次发布之间,网站上发布了新消息。但是在第二次启动时,这些新项目并没有显示出来。但是,如果用户手动转到应用程序设置并清除应用程序的缓存,然后重新启动,则会显示新项目。
你明白我的意思了吗?
虽然我不想禁用 Volley 缓存,但如何让它始终获取新项目?
编辑
MainActivity
public class MainActivity extends AppCompatActivity {
private final String TAG = "MainActivity";
//Creating a list of newss
private List<NewsItems> mNewsItemsList;
//Creating Views
private RecyclerView recyclerView;
private RecyclerView.Adapter adapter;
private RecyclerView.LayoutManager layoutManager;
private ProgressDialog mProgressDialog;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.d(TAG, "onCreate called");
//Initializing Views
recyclerView = (RecyclerView) findViewById(R.id.news_recycler);
LinearLayoutManager layoutManager = new LinearLayoutManager(this);
recyclerView.setLayoutManager(layoutManager);
//Initializing the newslist
mNewsItemsList = new ArrayList<>();
adapter = new NewsAdapter(mNewsItemsList, this);
recyclerView.setAdapter(adapter);
if (NetworkCheck.isAvailableAndConnected(this)) {
//Calling method to get data
getData();
} else {
//Codes for building Alert Dialog
alertDialogBuilder.setPositiveButton(R.string.alert_retry, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
if (!NetworkCheck.isAvailableAndConnected(mContext)) {
alertDialogBuilder.show();
} else {
getData();
}
}
});
alertDialogBuilder.setNegativeButton(R.string.alert_cancel, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
finish();
}
});
alertDialogBuilder.show();
}
}
//This method will get data from the web api
private void getData(){
Log.d(TAG, "getData called");
//Codes for Showing progress dialog
//Creating a json request
JsonArrayRequest jsonArrayRequest = new JsonArrayRequest(ConfigNews.GET_URL + getNumber(),
new Response.Listener<JSONArray>() {
@Override
public void onResponse(JSONArray response) {
Log.d(TAG, "onResponse called");
//Dismissing the progress dialog
if (mProgressDialog != null) {
mProgressDialog.hide();
}
//calling method to parse json array
parseData(response);
}
},
new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
}
});
//Creating request queue
RequestQueue requestQueue = Volley.newRequestQueue(this);
//Adding request to the queue
requestQueue.add(jsonArrayRequest);
}
//This method will parse json data
private void parseData(JSONArray array){
Log.d(TAG, "Parsing array");
for(int i = 0; i<array.length(); i++) {
NewsItems newsItem = new NewsItems();
JSONObject jsonObject = null;
try {
jsonObject = array.getJSONObject(i);
newsItem.setNews_title(jsonObject.getString(ConfigNews.TAG_VIDEO_TITLE));
newsItem.setNews_body(jsonObject.getString(ConfigNews.TAG_VIDEO_BODY));
} catch (JSONException w) {
w.printStackTrace();
}
mNewsItemsList.add(newsItem);
}
adapter.notifyItemRangeChanged(0, adapter.getItemCount());
}
@Override
public void onDestroy() {
super.onDestroy();
Log.d(TAG, "onDestroy called");
if (mProgressDialog != null){
mProgressDialog.dismiss();
Log.d(TAG, "mProgress dialog dismissed");
}
}
}
选项 1) 删除缓存
在拨打电话之前,您可以通过 myDiskBasedCache.clear()
删除整个缓存或通过 myDiskBasedCache.remove(entryUrl)
选项 2) 自定义 CacheParser(在请求中)
@Override
protected Response<Bitmap> parseNetworkResponse(NetworkResponse response) {
Response<Bitmap> resp = super.parseNetworkResponse(response);
if(!resp.isSuccess()) {
return resp;
}
long now = System.currentTimeMillis();
Cache.Entry entry = resp.cacheEntry;
if(entry == null) {
entry = new Cache.Entry();
entry.data = response.data;
entry.responseHeaders = response.headers;
entry.ttl = now + 60 * 60 * 1000; //keeps cache for 1 hr
}
entry.softTtl = 0; // will always refresh
return Response.success(resp.result, entry);
}
选项 3) 发送不缓存的请求
myRequest.setShouldCache(false);
选项 4) 使用自定义缓存实现
更新:
您的代码示例:
//Creating a json request
JsonArrayRequest jsonArrayRequest = new JsonArrayRequest(ConfigNews.GET_URL + getNumber(),
new Response.Listener<JSONArray>() {
@Override
public void onResponse(JSONArray response) {
Log.d(TAG, "onResponse called");
//Dismissing the progress dialog
if (mProgressDialog != null) {
mProgressDialog.hide();
}
//calling method to parse json array
parseData(response);
}
},
new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
}
}) {
@Override
protected Response<JSONArray> parseNetworkResponse(NetworkResponse response) {
Response<JSONArray> resp = super.parseNetworkResponse(response);
if(!resp.isSuccess()) {
return resp;
}
long now = System.currentTimeMillis();
Cache.Entry entry = resp.cacheEntry;
if(entry == null) {
entry = new Cache.Entry();
entry.data = response.data;
entry.responseHeaders = response.headers;
entry.ttl = now + 60 * 60 * 1000; //keeps cache for 1 hr
}
entry.softTtl = 0; // will always refresh
return Response.success(resp.result, entry);
}
};
更新 2
Http 协议缓存 支持多种方式来定义客户端如何缓存响应以及何时更新它们。 Volley 将这些规则简化为:
- entry.ttl(以毫秒为单位的生存时间)如果大于当前时间则可以使用缓存,否则需要重新请求
和
entry.softTtl(软时间以ms为单位:)如果大于当前时间 缓存是绝对有效的,不需要向服务器发出请求,否则仍然会发出新请求(即使 ttl 是好的),如果有变化,将传递新的响应。
请注意,如果 ttl 有效而 softTtl 无效,您可以收到 2 个 onResponse 调用