Android早已经在4.0版本添加了缓存支持,以下内容是对Android官方文档的一个总结。
(一) HttpResponseCache 类在Android 4.0 版本添加支持,支持 HttpURLConnection 和 HttpsURLConnection,但不支持DefaultHttpClient和AndroidHttpClient。
HttpResponseCache的好处:
1.明显一点节约电,减少了网络请求。
2.开发者不用自己在去写cache机制了。
3.最根本的一点就是,如果开发者在开发中不是使用的HttpClient, HttpDefaultClient..., 而是用 HttpURLConnection的话, 你根本不用改本來的 Code。
(1).在程序开启的时候设定需要缓存,并设定缓存目录和缓存文件大小,例如:(最好把缓存目录设定在外部存储)
static volatile Object cache;
private static final Object lock = new Object();
private static final int MIN_DISK_CACHE_SIZE = 5 * 1024 * 1024; // 5MB
private static final int MAX_DISK_CACHE_SIZE = 50 * 1024 * 1024; // 50MB
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH)
{
installCacheIfNeeded(context);
}
private static void installCacheIfNeeded(Context context)
{
// DCL + volatile should be safe after Java 5.
if (cache == null)
{
try
{
synchronized (lock)
{
if (cache == null)
{
cache = install(context);
}
}
}
catch (IOException ignored)
{
}
}
}
public void install(Context context)
{
File cacheDir = createDefaultCacheDir(context);
HttpResponseCache cache = HttpResponseCache.getInstalled();
if (cache == null)
{
long maxSize = calculateDiskCacheSize(cacheDir);
cache = HttpResponseCache.install(cacheDir, maxSize);
}
}
static File createDefaultCacheDir(Context context)
{
File cache = new File(context.getApplicationContext().getCacheDir(), "Cache_Name");
if (!cache.exists())
{
// noinspection ResultOfMethodCallIgnored
cache.mkdirs();
}
return cache;
}
static long calculateDiskCacheSize(File dir)
{
long size = MIN_DISK_CACHE_SIZE;
try
{
StatFs statFs = new StatFs(dir.getAbsolutePath());
long available = ((long) statFs.getBlockCount()) * statFs.getBlockSize();
// Target 2% of the total space.
size = available / 50;
}
catch (IllegalArgumentException ignored)
{
}
// Bound inside min/max size for disk cache.
return Math.max(Math.min(size, MAX_DISK_CACHE_SIZE), MIN_DISK_CACHE_SIZE);
}
(2).根据请求需要设置缓存
a.例如点击“刷新”按钮,或者手动刷新,这时候要强制刷新,就需要添加“no-cache”指令
connection.addRequestProperty("Cache-Control","no-cache");
b.如果只需要强制缓存的响应由服务器进行验证,使用更高效的“max-age=0”指令来代替:
connection.addRequestProperty("Cache-Control","max-age=0");
c. 有时候,你只想加载缓存数据,你需要设定“ only-if-cached”指令
try{ connection.addRequestProperty("Cache-Control","only-if-cached"); InputStream cached = connection.getInputStream(); // the resource was cached! show it catch(FileNotFoundException e){ // the resource was not cached } }
d.你还可以设定缓存的有效时间
int maxStale =60*60*24*28;// tolerate 4-weeks stale
connection.addRequestProperty("Cache-Control","max-stale="+ maxStale);
个人理解会将http请求放在本地,如果有相同的请求,就不会再次调用网络请求,直接得到本地请求响应的值
- public class HttpCacheApplication extends Application {
- @Override
- public void onCreate() {
- super.onCreate();
- new Thread() {
- @Override
- public void run() {
- enableHttpResponseCache();
- }
- }.start();
- }
- private void enableHttpResponseCache() {
- try {
- long httpCacheSize = 10 * 1024 * 1024;// 10M
- File httpCacheDir = new File(getCacheDir(), "http");
- Class.forName("android.net.http.HttpResponseCache")
- .getMethod("install", File.class, long.class)
- .invoke(null, httpCacheDir, httpCacheSize);
- } catch (Exception e) {
- Log.e("===>", e.getMessage(), e);
- }
- }
- }
接下来我们来看看HttpUrlConnection是怎么处理的,怎么缓存的。
- public class MainActivity extends Activity {
- private final String TAG = getClass().getSimpleName();
- ImageView img;
- Button msg;
- TextView tv;
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- img = (ImageView) findViewById(R.id.imageView1);
- tv = (TextView)findViewById(R.id.textView1);
- msg = (Button) findViewById(R.id.button1);
- msg.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- new InternetTask().execute();
- }
- });
- findViewById(R.id.button2).setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- MainActivity.this.finish();
- }
- });
- }
- class InternetTask extends AsyncTask<String, String, Boolean> {
- Bitmap bitmap;
- String jsonStr;
- @Override
- protected void onPostExecute(Boolean result) {
- super.onPostExecute(result);
- img.setImageBitmap(bitmap);
- tv.setText(jsonStr);
- }
- @Override
- protected Boolean doInBackground(String... params) {
- // Test download image
- try {
- URL url = new URL("http://news.baidu.com/resource/img/logo_news_137_46.png");
- HttpURLConnection conn = (HttpURLConnection) (url
- .openConnection());
- conn.connect();
- InputStream is = conn.getInputStream();
- BitmapFactory.Options ops = new BitmapFactory.Options();
- bitmap = BitmapFactory.decodeStream(is, null, ops);
- is.close();
- conn.disconnect();
- } catch (Exception e) {
- Log.e(TAG, e.getMessage(), e);
- }
- // Test download JSON data
- try {
- URL url = new URL("http://www.baidu.com/");
- HttpURLConnection conn = (HttpURLConnection) (url
- .openConnection());
- conn.connect();
- BufferedReader reader = new BufferedReader(
- new InputStreamReader(conn.getInputStream(), "UTF-8"));
- jsonStr = reader.readLine();
- InputStream is = conn.getInputStream();
- is.close();
- conn.disconnect();
- } catch (Exception e) {
- Log.e(TAG, e.getMessage(), e);
- }
- return true;
- }
- }
- }
我们看下效果:
看下缓存文件,每个文件会产生两个文件,一个是数据文件,一个是http header 信息