转载请注明出处: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
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; } }; // 初始化
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币打赏给小的我吧~)
结束语:
我所了解的缓存到这里就说完了,后续肯定还会有补充,也希望你多帮我提一些好的想法。