原文出处——krelve.com
经过前面的几天,大部分功能已经完成了,今天再来添加一个实用的功能,就是离线缓存。
老规矩,先上图:
在没加缓存前,如果在没联网的情况下打开应用,就连侧滑的菜单都不会显示效果,界面上的文章列表和阅读文章就更不会显示了。
那让我们一点一点的来添加缓存。
1.侧滑菜单的缓存
首先思考一下,什么情况下要更新缓存?考虑到文章的实时性,决定在每次联网的时候都获取最新内容列表,放到缓存中,如果打开应用时判断没有网络,则从缓存中读取。
if (HttpUtils.isNetworkConnected(mActivity)) {
HttpUtils.get(Constant.THEMES, new JsonHttpResponseHandler() {
@Override
public void onSuccess(int statusCode, Header[] headers, JSONObject response) {
super.onSuccess(statusCode, headers, response);
String json = response.toString();
PreUtils.putStringToDefault(mActivity, Constant.THEMES, json);
parseJson(response);
}
});
} else {
String json = PreUtils.getStringFromDefault(mActivity, Constant.THEMES, "");
try {
JSONObject jsonObject = new JSONObject(json);
parseJson(jsonObject);
} catch (JSONException e) {
e.printStackTrace();
}
}
再贴出判断网络状态的代码:
public static boolean isNetworkConnected(Context context) {
if (context != null) {
ConnectivityManager mConnectivityManager = (ConnectivityManager) context
.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo mNetworkInfo = mConnectivityManager.getActiveNetworkInfo();
if (mNetworkInfo != null) {
return mNetworkInfo.isAvailable();
}
}
return false;
}
看到了吧,其实很简单,就是将url作为key,json字串作为value存入SharedPreferences,因为获取新闻类型的请求只有一条,所以没有必要用数据库来存,在后面缓存文章列表和文章内容的时候会用到数据库。
2.文章列表的缓存
文章列表的缓存就要考虑的多一些了,因为涉及到了图片。不过有了UniversalImageloader,就不用我们多做操心了,直接设置options:
options = new DisplayImageOptions.Builder()
.cacheInMemory(true)
.cacheOnDisk(true)
.build();
在所有需要缓存图片的地方,调用displayImage方法的时候都加上参数options。
由于今日热闻界面的数据加载涉及到第一次加载和更多加载,所以拿第一次加载来举例,完整代码请看源代码:
if (HttpUtils.isNetworkConnected(mActivity)) {
HttpUtils.get(Constant.LATESTNEWS, new TextHttpResponseHandler() {
@Override
public void onFailure(int statusCode, Header[] headers, String responseString, Throwable throwable) {
}
@Override
public void onSuccess(int statusCode, Header[] headers, String responseString) {
SQLiteDatabase db = ((MainActivity) mActivity).getCacheDbHelper().getWritableDatabase();
db.execSQL("replace into CacheList(date,json) values(" + Constant.LATEST_COLUMN + ",' " + responseString + "')");
db.close();
parseLatestJson(responseString);
}
});
} else {
SQLiteDatabase db = ((MainActivity) mActivity).getCacheDbHelper().getReadableDatabase();
Cursor cursor = db.rawQuery("select * from CacheList where date = " + Constant.LATEST_COLUMN, null);
if (cursor.moveToFirst()) {
String json = cursor.getString(cursor.getColumnIndex("json"));
parseLatestJson(json);
} else {
isLoading = false;
}
cursor.close();
db.close();
}
这里用到了数据库,建了一个很简单的表:
package krelve.app.kuaihu.db;
import android.content.Context;
import android.database.DatabaseErrorHandler;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
/**
* Created by wwjun.wang on 2015/8/19.
*/
public class CacheDbHelper extends SQLiteOpenHelper {
public CacheDbHelper(Context context, int version) {
super(context, "cache.db", null, version);
}
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL("create table if not exists CacheList (id INTEGER primary key autoincrement,date INTEGER unique,json text)");
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
}
使用replace into是为了防止重复插入,就是如果不存在则插入,存在即更新。
3.文章内容的缓存
本来以为文章内容的缓存是最费劲的,没想到WebView自带的缓存功能这么强大…
mWebView = (WebView) findViewById(R.id.webview);
mWebView.getSettings().setJavaScriptEnabled(true);
mWebView.getSettings().setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK);
// 开启DOM storage API 功能
mWebView.getSettings().setDomStorageEnabled(true);
// 开启database storage API功能
mWebView.getSettings().setDatabaseEnabled(true);
// 开启Application Cache功能
mWebView.getSettings().setAppCacheEnabled(true);
if (HttpUtils.isNetworkConnected(this)) {
HttpUtils.get(Constant.CONTENT + entity.getId(), new TextHttpResponseHandler() {
@Override
public void onFailure(int statusCode, Header[] headers, String responseString, Throwable throwable) {
}
@Override
public void onSuccess(int statusCode, Header[] headers, String responseString) {
SQLiteDatabase db = dbHelper.getWritableDatabase();
responseString = responseString.replaceAll("'", "''");
db.execSQL("replace into Cache(newsId,json) values(" + entity.getId() + ",'" + responseString + "')");
db.close();
parseJson(responseString);
}
});
} else {
SQLiteDatabase db = dbHelper.getReadableDatabase();
Cursor cursor = db.rawQuery("select * from Cache where newsId = " + entity.getId(), null);
if (cursor.moveToFirst()) {
String json = cursor.getString(cursor.getColumnIndex("json"));
parseJson(json);
}
cursor.close();
db.close();
}
这里将服务端返回的json串整体进行了保存,所以需要注意一下字符的转义问题。
responseString = responseString.replaceAll("'", "''");
这句很关键,如果不加,在文章内容中包含’时,会将sql语句隔断,导致应用崩溃。
文章内容中的那些图片,WebView会自动帮我们缓存,所以我们在断网的情况下直接将html代码传入WebView就可以全部显示出来。
今天的内容就这些,虽然看起来简单,但实际开发过程中会遇到各种各样的问题,要注意缓存的时机与缓存的清理。
高仿知乎日报