Android缓存策略——打造最全的缓存

Android缓存策略——打造最全的缓存

转载请注明出处:hao54216的博客

前言:

本篇介绍Android中的各种缓存机制和缓存框架,同样借鉴网上的一些知识总结分享给大家。


HR经常问到的缓存机制?

客户端缓存机制是android应用开发中非常重要的一项工作了,使用缓存机制不仅可以为客户节省流量,同时提高了用户体验,比如今日头条的离线模式,就是通过缓存机制实现的,那么缓存机制分为2种。文字缓存和多媒体文件缓存。


咱们先来说文字缓存:

1、将于服务器交互得到的json数据或者xml数据存入sd卡中,并在数据库添加该数据的记录。添加数据库记录时,可以提供2个字段,请求到的Url和本地保存后的文件地址,每次加载数据之前都会根据Url在数据库中检索。


ps:本段中提到存入sd卡,可能有的小伙伴不知道,这里说一下~


首先获取sdcard路径:

Environment.getExternalStorageDirectory()

判断sdcard状态:

Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)

保存到sd卡: filename 文件名 content内容

public void saveToSDCard(String filename,String content) throws Exception{          File file=new File(Environment.getExternalStorageDirectory(), filename);          OutputStream out=new FileOutputStream(file);          out.write(content.getBytes());          out.close();      }  
相关权限添加:
<!-- 在SDCard中创建于删除文件的权限 -->  <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>  <!-- 往SDCard中写入数据的权限 -->  <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>  

2、将Json数据解析后装入List<Map>对象中,然后遍历List,将数据全部写入相应的数据库表结构中,以后每次想服务器发起请求之前可以现在数据库中检索,如果有直接返回。


ps:这里没有保存到文件,是先保存到list<Map<>>中,写入数据库,每次查询数据库获取数据;


之后就是多媒体_图片缓存了(本地缓存):

缓存图片可以根据当前日期、时间为名字缓存到sd卡中的指定图片缓存目录,同时数据库中左相应记录,记录办法可以采用俩个关键字段控制,一个字段是该图片的URL地址,另一个是该字段的图片本机地址,取图片时根据URL在数据中检索,如果没有则连接服务器下载,下载之后再服务器中做出相应记录。


ps:如何缓存到sd卡中呢?其实和文字缓存一样的思路;

/** 保存方法 */ public void saveBitmap(Bitmap bm, String <span >picName</span>) {  Log.e(TAG, "保存图片");  File f = new File(<span >Environment.getExternalStorageDirectory()</span>, picName);//保存路径和图片名称(上文说的日期和时间可以作为)  if (f.exists()) {   f.delete();  }  try {   FileOutputStream out = new FileOutputStream(f);   bm.compress(Bitmap.CompressFormat.PNG, 90, out);   out.flush();   out.close();   Log.i(TAG, "已经保存");  } catch (FileNotFoundException e) {   // TODO Auto-generated catch block   e.printStackTrace();  } catch (IOException e) {   // TODO Auto-generated catch block   e.printStackTrace();  } }
同样存入数据库,检索数据库。同时推荐我的另一篇文章: 点击打开链接


相关的图片框架:


1) Picasso

picasso-强大的Android图片下载缓存库

2) Glide

Google推荐的图片加载库Glide介绍

3) Fresco

Fresco使用教程

4) ImageLoader

Android UI-开源框架ImageLoader的完美例子


他们说的三级缓存:

内存缓存(从内存中获取图片显示)、本地缓存(内存中没有从sd卡获取)、网络缓存(从网络下载并保存入本地和内存);


ps:从sd卡获取图片是放在子线程里面执行的,否则快速滑屏的话不够流畅!



这里我想提一下Lrucache缓存:

核心的类是LruCache (此类在android-support-v4的包中提供) 。这个类非常适合用来缓存图片,

它的主要算法原理是把最近使用的对象用强引用存储在 LinkedHashMap 中,并且把最近最少

使用的对象在缓存值达到预设定值之前从内存中移除。


实现思路:

(1).要先设置缓存图片的内存大小,基本上设置为手机内存的1/8,
手机内存的获取方式:int MAXMEMONRY = (int) (Runtime.getRuntime() .maxMemory() / 1024);
(2).LruCache里面的键值对分别是URL和对应的图片;
(3).重写了一个叫做sizeOf的方法,返回的是图片数量。


它的使用:

1、初始化Lrucache

import android.app.ActivityManager;import android.app.Application;import android.content.Context;/** * application * @author hao * */public class MyApplication extends Application{@Overridepublic void onCreate() {// TODO Auto-generated method stubsuper.onCreate();}/** * @description  * * @param context * @return 得到需要分配的缓存大小,这里用八分之一的大小来做 */public int getMemoryCacheSize() {// Get memory class of this device, exceeding this amount will throw an// OutOfMemory exception.final int memClass = ((ActivityManager)getSystemService(Context.ACTIVITY_SERVICE)).getMemoryClass();// Use 1/8th of the available memory for this memory cache.return 1024 * 1024 * memClass / 8;}}
ps:这个方法可以说就是获取系统分配缓存的大小/8 说明我们用其中的八分之一来做缓存,建议配置在application里面,方便调用。

2、初始化类

final int memoryCache = ((KaleApplication) getApplication()).getMemoryCacheSize();        Log.d(TAG, "cache size = " + memoryCache / 1024 / 1024 + "M");        mMemoryCache = new LruCache<String, Bitmap>(memoryCache) {            @Override            protected int sizeOf(String key, Bitmap bitmap) {                // 重写此方法来衡量每张图片的大小,默认返回图片数量。                return bitmap.getByteCount() / 1024;            }        }; // 初始化


ps:获取全局配置的内存, 我通过缓存的值来初始化了cache对象,然后重写了sizeOf()方法。(返回数量)

3、添加删除和添加操作

    /**     * @description 将bitmap添加到内存中去     *     * @param key     * @param bitmap     */    public void addBitmapToMemoryCache(String key, Bitmap bitmap) {        if (getBitmapFromMemCache(key) == null) {            mMemoryCache.put(key, bitmap);        }    }    /**     * @description 通过key来从内存缓存中获得bitmap对象     *     * @param key     * @return     */    private Bitmap getBitmapFromMemCache(String key) {        return mMemoryCache.get(key);    }

4、从网络上缓存并添加入缓存

<span ></span>/** * @description 将bitmap加载到imageview中去 * * @param resId * @param imageView */public void loadBitmapToImageView(String url, ImageView imageView) {final Bitmap bitmap = getBitmapFromMemCache("img"); // 先看这个资源在不在内存中,如果在直接读取为bitmap,否则返回nullif (bitmap != null) {Log.d(TAG, "in memory");imageView.setImageBitmap(bitmap);} else {Log.d(TAG, "not in memory");imageView.setImageResource(R.drawable.ic_launcher); // 如果没有在内存中,先显示默认的图片,然后启动线程去下载图片BitmapWorkerTask task = new BitmapWorkerTask(imageView);task.execute(url); // 启动线程,从网络下载图片,下载后加入缓存}}

ps:判断图片是否已经进行了缓存操作。图片如果在内存中就直接赋值,没有启动线程重新获取。

import java.io.IOException;import java.net.HttpURLConnection;import java.net.MalformedURLException;import java.net.URL;import android.graphics.Bitmap;import android.graphics.BitmapFactory;import android.os.AsyncTask;import android.widget.ImageView;public class BitmapWorkerTask extends AsyncTask<String, Void, Bitmap>{private MainActivity mActivity;private ImageView mImageView;public BitmapWorkerTask(ImageView imageView) {mImageView = imageView;mActivity = (MainActivity) imageView.getContext();}/** * 下载图片 */@Overrideprotected Bitmap doInBackground(String... params) {Bitmap bitmap = null;          HttpURLConnection con = null;          try {              URL url = new URL(params[0]);              con = (HttpURLConnection) url.openConnection();              con.setConnectTimeout(10 * 1000);              con.setReadTimeout(10 * 1000);              bitmap = BitmapFactory.decodeStream(con.getInputStream());              //添加到内存            mActivity.addBitmapToMemoryCache("img", bitmap);        } catch (MalformedURLException e) {              e.printStackTrace();          } catch (IOException e) {              e.printStackTrace();          } finally {              if (con != null) {                  con.disconnect();              }          } return bitmap;}@Overrideprotected void onPostExecute(Bitmap result) {super.onPostExecute(result);if (result != null) {mImageView.setImageBitmap(result); }}}
ps: 得到后将bitmap放入缓存中,最后在imageview中展示。

让我们最后看一下效果吧!!!


点击下载图片,小机器人加载中,然后下载从网络下载成功!再次点击则不会加载,从内存中获取!

最后在这附上这个的源码下载 Lrucache内存缓存下载(这里1币打赏给小的我吧~)

结束语:

我所了解的缓存到这里就说完了,后续肯定还会有补充,也希望你多帮我提一些好的想法。

推荐阅读