本文是在上文android-async-http使用例子http://my.oschina.net/penngo/blog/488128的基础上增加缓存处理。
为了加快页面显示,每次请求时先从本地缓存中取数据并显示在UI上,然后再进行网络请求,并把请求结果更新到本地缓存,可以让用户觉得app加载数据很快,给用户更好的体验。
例子代码是把网络请求的缓存数据保存SharedPreferences,另外也可以保存在sqlite或文件。
package com.penngo.http;
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import com.loopj.android.http.RequestParams;
import org.apache.http.Header;
import java.io.File;
public class MainActivity extends Activity {
private final static String tag = "MainActivity-->";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button getBtn = (Button)this.findViewById(R.id.getBtn);
getBtn.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
testGet();
}
});
Button downloadBtn = (Button)this.findViewById(R.id.downloadBtn);
downloadBtn.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
testDownloadFile();
}
});
}
private void testGet(){
RequestParams parame = getParames();
final String url = HttpUtil.BASE_URL + "test/android.php?" + parame.toString();
TextCacheHttpResponseHandler responseHandler = new TextCacheHttpResponseHandler(){
@Override
public void onStart() {
Log.e(tag, "onStart====");
}
@Override
public void onSuccess(int statusCode, Header[] headers, String response) {
String key = HttpUtil.getMD5(url.getBytes());
String cache = String.valueOf(SPUtils.get(MainActivity.this, key, ""));
if(cache.equals("") == true){
//缓存不存在,并且网络请求数据成功时处理
Log.e(tag, "onSuccess=== " + "statusCode:" + statusCode + " response:" + response);
}
SPUtils.put(MainActivity.this, key, response);
}
@Override
public void onFailure(int statusCode, Header[] headers, String errorResponse, Throwable e) {
Log.e(tag, "onFailure====");
}
public void onCache(String responseString){
// 缓存存在时处理
Log.e(tag, "onCache====" + responseString);
}
};
HttpUtil.get(this.getBaseContext(), url, parame, responseHandler);
}
private RequestParams getParames(){
RequestParams params = new RequestParams();
params.put("user", "penngo");
params.put("psw", "penngo");
return params;
}
private void testDownloadFile(){
final String url = HttpUtil.BASE_URL + "test/fa.mp3";
String mp3 = this.getExternalCacheDir().getAbsolutePath() + "/fa.mp3";
File mp3File = new File(mp3);
FileCacheAsyncHttpResponseHandler fileHandler = new FileCacheAsyncHttpResponseHandler(mp3File){
public void onSuccess(int statusCode, Header[] headers, File file){
String key = HttpUtil.getMD5(url.getBytes());
SPUtils.put(MainActivity.this, key, file.getAbsolutePath());
Log.e(tag, "onSuccess====, statusCode:" + " file:" + file.getAbsolutePath());
}
public void onFailure(int statusCode, Header[] headers, Throwable throwable, File file){
Log.e(tag, "onSuccess====, statusCode:" + " file:" + file.getAbsolutePath());
}
public void onCache(File file){
Log.e(tag, "onCache====" + file.getAbsolutePath());
}
};
HttpUtil.download(this.getBaseContext(), "test/fa.mp3", null, fileHandler);
}
}
package com.penngo.http;
import android.content.Context;
import com.loopj.android.http.AsyncHttpClient;
import com.loopj.android.http.RequestParams;
import java.io.File;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
public class HttpUtil {
public static final String BASE_URL = "http://192.168.17.99/";
private static AsyncHttpClient client = new AsyncHttpClient();
public static void setTimeout() {
client.setTimeout(60000);
}
public static void get(Context context, String url, RequestParams params, TextCacheHttpResponseHandler responseHandler) {
// 检查缓存是否存在,存在再调用responseHandler的onCache方法
getPreferencesCacheData(context, url, responseHandler);
client.get(url, params, responseHandler);
}
public static void post(Context context, String url, RequestParams params, TextCacheHttpResponseHandler responseHandler) {
getPreferencesCacheData(context, url, responseHandler);
client.post(url, params, responseHandler);
}
public static void download(Context context, String url, RequestParams params, FileCacheAsyncHttpResponseHandler fileAsyncHttpResponseHandler) {
// 检查文件是否存在,存在再调用fileAsyncHttpResponseHandler的onCache方法
getFileCacheData(context, url,fileAsyncHttpResponseHandler);
client.get(url, params, fileAsyncHttpResponseHandler);
}
private static boolean getPreferencesCacheData(Context context, String key,TextCacheHttpResponseHandler responseHandler){
key = getMD5(key.getBytes());
String cache = String.valueOf(SPUtils.get(context, key, ""));
if (!cache.equals("")) {
responseHandler.onCache(cache);
return true;
}
else{
return false;
}
}
private static boolean getFileCacheData(Context context, String key,FileCacheAsyncHttpResponseHandler responseHandler){
key = getMD5(key.getBytes());
String filePath = String.valueOf(SPUtils.get(context, key, ""));
if (!filePath.equals("")) {
File file = new File(filePath);
if(file.exists() == true){
responseHandler.onCache(file);
return true;
}
}
return false;
}
public static String getMD5(byte[] src) {
StringBuffer sb = new StringBuffer();
try {
java.security.MessageDigest md = MessageDigest.getInstance("MD5");
md.update(src);
for (byte b : md.digest()) {
sb.append(Integer.toString(b >>> 4 & 0xF, 16)).append(Integer.toString(b & 0xF, 16));
}
} catch (NoSuchAlgorithmException e) {
}
return sb.toString();
}
}
package com.penngo.http;
import com.loopj.android.http.FileAsyncHttpResponseHandler;
import java.io.File;
// 扩展FileAsyncHttpResponseHandler ,增加缓存方法调用
public abstract class FileCacheAsyncHttpResponseHandler extends FileAsyncHttpResponseHandler {
public FileCacheAsyncHttpResponseHandler(File file) {
super(file);
}
public void onCache(File file){
}
}
package com.penngo.http;
import com.loopj.android.http.TextHttpResponseHandler;
// 扩展TextHttpResponseHandler,增加缓存方法调用
public abstract class TextCacheHttpResponseHandler extends TextHttpResponseHandler {
public void onCache(String responseString){
}
}
package com.penngo.http;
import android.content.Context;
import android.content.SharedPreferences;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Map;
/**
* Created by Administrator on 2015/8/5.
*/
public class SPUtils {
/**
* 保存在手机里面的文件名
*/
public static final String FILE_NAME = "share_data";
/**
* 保存数据的方法,我们需要拿到保存数据的具体类型,然后根据类型调用不同的保存方法
*
* @param context
* @param key
* @param object
*/
public static void put(Context context, String key, Object object) {
SharedPreferences sp = context.getSharedPreferences(FILE_NAME,
Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sp.edit();
if (object instanceof String) {
editor.putString(key, (String) object);
} else if (object instanceof Integer) {
editor.putInt(key, (Integer) object);
} else if (object instanceof Boolean) {
editor.putBoolean(key, (Boolean) object);
} else if (object instanceof Float) {
editor.putFloat(key, (Float) object);
} else if (object instanceof Long) {
editor.putLong(key, (Long) object);
} else {
editor.putString(key, object.toString());
}
SharedPreferencesCompat.apply(editor);
}
/**
* 得到保存数据的方法,我们根据默认值得到保存的数据的具体类型,然后调用相对于的方法获取值
*
* @param context
* @param key
* @param defaultObject
* @return
*/
public static Object get(Context context, String key, Object defaultObject) {
SharedPreferences sp = context.getSharedPreferences(FILE_NAME,
Context.MODE_PRIVATE);
if (defaultObject instanceof String) {
return sp.getString(key, (String) defaultObject);
} else if (defaultObject instanceof Integer) {
return sp.getInt(key, (Integer) defaultObject);
} else if (defaultObject instanceof Boolean) {
return sp.getBoolean(key, (Boolean) defaultObject);
} else if (defaultObject instanceof Float) {
return sp.getFloat(key, (Float) defaultObject);
} else if (defaultObject instanceof Long) {
return sp.getLong(key, (Long) defaultObject);
}
return null;
}
/**
* 移除某个key值已经对应的值
*
* @param context
* @param key
*/
public static void remove(Context context, String key) {
SharedPreferences sp = context.getSharedPreferences(FILE_NAME,
Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sp.edit();
editor.remove(key);
SharedPreferencesCompat.apply(editor);
}
/**
* 清除所有数据
*
* @param context
*/
public static void clear(Context context) {
SharedPreferences sp = context.getSharedPreferences(FILE_NAME,
Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sp.edit();
editor.clear();
SharedPreferencesCompat.apply(editor);
}
/**
* 查询某个key是否已经存在
*
* @param context
* @param key
* @return
*/
public static boolean contains(Context context, String key) {
SharedPreferences sp = context.getSharedPreferences(FILE_NAME,
Context.MODE_PRIVATE);
return sp.contains(key);
}
/**
* 返回所有的键值对
*
* @param context
* @return
*/
public static Map<String, ?> getAll(Context context) {
SharedPreferences sp = context.getSharedPreferences(FILE_NAME,
Context.MODE_PRIVATE);
return sp.getAll();
}
/**
* 创建一个解决SharedPreferencesCompat.apply方法的一个兼容类
*
* @author zhy
*/
private static class SharedPreferencesCompat {
private static final Method sApplyMethod = findApplyMethod();
/**
* 反射查找apply的方法
*
* @return
*/
@SuppressWarnings({"unchecked", "rawtypes"})
private static Method findApplyMethod() {
try {
Class clz = SharedPreferences.Editor.class;
return clz.getMethod("apply");
} catch (NoSuchMethodException e) {
}
return null;
}
/**
* 如果找到则使用apply执行,否则使用commit
*
* @param editor
*/
public static void apply(SharedPreferences.Editor editor) {
try {
if (sApplyMethod != null) {
sApplyMethod.invoke(editor);
return;
}
} catch (IllegalArgumentException e) {
} catch (IllegalAccessException e) {
} catch (InvocationTargetException e) {
}
editor.commit();
}
}
}