离线缓存

前言:

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

HR经常问到的缓存机制?

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

咱们先来说文字缓存:

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

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

首先获取sdcard路径:

1
Environment.getExternalStorageDirectory()
判断sdcard状态:

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

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

1
2
3
4
5
6
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(); 
     }
相关权限添加:
1
2
3
4
<!-- 在SDCard中创建于删除文件的权限 --> 
<uses-permission android:name= "android.permission.MOUNT_UNMOUNT_FILESYSTEMS"
<!-- 往SDCard中写入数据的权限 --> 
<uses-permission android:name= "android.permission.WRITE_EXTERNAL_STORAGE" >  </uses-permission></uses-permission>
2、将Json数据解析后装入List对象中,然后遍历List,将数据全部写入相应的数据库表结构中,以后每次想服务器发起请求之前可以现在数据库中检索,如果有直接返回。

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

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

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

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
/** 保存方法 */
  public void saveBitmap(Bitmap bm, String <span style= "font-family: Arial, Helvetica, sans-serif;" >picName</span>) {
   Log.e(TAG, "保存图片" );
   File f = new File(<span style= "font-family: Arial, Helvetica, sans-serif;" >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();
   }
 
  }
同样存入数据库,检索数据库。

三级缓存:

内存缓存(从内存中获取图片显示)、==》本地缓存(内存中没有从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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
import android.app.ActivityManager;
import android.app.Application;
import android.content.Context;
 
/**
  * application
  * @author hao
  *
  */
public class MyApplication extends Application{
     
     @Override
     public void onCreate() {
         // TODO Auto-generated method stub
         super .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、初始化类

1
2
3
4
5
6
7
8
9
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 ;
             }
         }; // 初始化</string,>
ps:获取全局配置的内存,我通过缓存的值来初始化了cache对象,然后重写了sizeOf()方法。(返回数量)

3、添加删除和添加操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/**
  * @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、从网络上缓存并添加入缓存

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<span style= "white-space:pre" >  </span> /**
      * @description 将bitmap加载到imageview中去
      *
      * @param resId
      * @param imageView
      */
     public void loadBitmapToImageView(String url, ImageView imageView) {
         final Bitmap bitmap = getBitmapFromMemCache( "img" ); // 先看这个资源在不在内存中,如果在直接读取为bitmap,否则返回null
         if (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:判断图片是否已经进行了缓存操作。图片如果在内存中就直接赋值,没有启动线程重新获取。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
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, bitmap= "" >{
 
     private MainActivity mActivity;
     private ImageView mImageView;
     
     public BitmapWorkerTask(ImageView imageView) {
         mImageView = imageView;
         mActivity = (MainActivity) imageView.getContext();
     }
     
     /**
      * 下载图片
      */
     @Override
     protected 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;
     }
     
     @Override
     protected void onPostExecute(Bitmap result) {
         super .onPostExecute(result);
         if (result != null ) {
             mImageView.setImageBitmap(result);
         }
     }
}
</string,>
ps:得到后将bitmap放入缓存中,最后在imageview中展示。

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



猜你喜欢

转载自blog.csdn.net/qq_33540190/article/details/80756305