Android 关于使用LruCache缓存你想缓存的数据

今天我们来一起学习一下缓存技术,相信大家做开发的时候都知道请求网络数据的重要,但是有一些只用请求一次就过时性的消息比如某些新闻信息,如果我们每次进入新闻界面就从新从网络上获取势必会给用户带来不好的体验,所以我们需要缓存技术来帮我们解决这一问题。

1,LruCache介绍

核心的类是LruCache (此类在android-support-v4的包中提供) 。这个类非常适合用来缓存图片,它的主要算法原理是把最近使用的对象用强引用存储在 LinkedHashMap 中,并且把最近最少使用的对象在缓存值达到预设定值之前从内存中移除。

在过去,我们经常会使用一种非常流行的内存缓存技术的实现,即软引用或弱引用 (SoftReference or WeakReference)。但是现在已经不再推荐使用这种方式了,因为从 Android 2.3 (API Level 9)开始,垃圾回收器会更倾向于回收持有软引用或弱引用的对象,这让软引用和弱引用变得不再可靠。另外,Android 3.0 (API Level 11)中,图片的数据会存储在本地的内存当中,因而无法用一种可预见的方式将其释放,这就有潜在的风险造成应用程序的内存溢出并崩溃。

2,LruCache使用 下面我们就来写一个简单的demo来学习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
33
34
35
36
37
38
39
40
41
/**
     * 缓存json数据
     */
    privateLruCache<integer, string=""> mJsonCache;
    /**
     * 缓存图片信息
     */
    privateLruCache<integer, bitmap=""> mBitmapCache;
 
    publicUtil() {
        mJsonCache =newLruCache<integer, string="">(1*1024*1024);
        mBitmapCache =newLruCache<integer, bitmap="">(2*1024*1024);
    }
 
    /**
     * 添加进入缓存列表
     *
     * @param key
     * @param value
     */
    publicvoidaddJsonLruCache(Integer key, String value) {
        mJsonCache.put(key, value);
    }
 
    publicvoidaddBitmapLruCache(Integer key, Bitmap value) {
        mBitmapCache.put(key, value);
    }
 
    /**
     * 从缓存列表中拿出来
     *
     * @param key
     * @return
     */
    publicString getJsonLruCache(Integer key) {
        returnmJsonCache.get(key);
    }
 
    publicBitmap getBitmapLruCache(Integer key) {
        returnmBitmapCache.get(key);
    }</integer,></integer,></integer,></integer,>

可以看到我们准备缓存Bitmap与String,只需要拿到信息的时候put进缓存中,需要的时候get出来,是不是非常简单,我们为我们String分配了1m为我们的Bitmap分配了2m空间,这只是我们的demo为了简单这样使用,实际上我们应该更加详细的考虑到底应该为缓存分配多大的空间
?
1
2
3
// 获取到可用内存的最大值,使用内存超出这个值会引起OutOfMemory异常。
// LruCache通过构造函数传入缓存值,以KB为单位。
intmaxMemory = (int) (Runtime.getRuntime().maxMemory() /1024);
一般来说最大值的1/8左右就可以了。
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
publicclassMainActivityextendsActivityimplementsOnItemClickListener {
    privatestaticfinalString LIST_DATA = http://api.yi18.net/top/list;
    privateListView mListView;
    privateArrayAdapter<string> mAdapter;
    privateArrayList<integer> mListId;
    privateUtil util;
 
    protectedvoidonCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        util =newUtil();
        mListView = (ListView) findViewById(R.id.list);
        mListId =newArrayList<integer>();
        mAdapter =newArrayAdapter<string>(this,
                android.R.layout.simple_list_item_1);
        mListView.setAdapter(mAdapter);
        mListView.setOnItemClickListener(this);
        newDownLoadJson().execute(LIST_DATA);
    }</string></integer></integer></string>
这一段就是普通的请求数据添加到ListView中。
?
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
privatevoidgetJsonData(String json) {
        try{
            JSONObject jsonObject =newJSONObject(json);
            if(jsonObject.getBoolean(success)) {
                JSONArray jsonArray = jsonObject.getJSONArray(yi18);
                for(inti =0; i < jsonArray.length(); i++) {
                    JSONObject jsonObject2 = (JSONObject) jsonArray.opt(i);
                    if(i <5) {
                        mAdapter.add(jsonObject2.getString(title));
                        mListId.add(jsonObject2.getInt(id));
                    }
                }
            }
        }catch(JSONException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
 
    classDownLoadJsonextendsAsyncTask<string, string=""> {
 
        @Override
        protectedString doInBackground(String... params) {
            returnutil.downLoadJson(params[0]);
        }
 
        @Override
        protectedvoidonPostExecute(String result) {
            if(result !=null) {
                getJsonData(result);
            }
        }
 
    }</string,>
data-cke-saved-src=http://www.2cto.com/uploadfile/Collfiles/20150207/20150207084912191.png

我们就简单的取了前五条数据用来模拟我们的新闻,用的是热点热词的Api。

 

3,缓存

 

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
@Override
    publicvoidonItemClick(AdapterView<!--?--> arg0, View arg1,intarg2,longarg3) {
        // TODO Auto-generated method stub
        String message = util.getJsonLruCache(mListId.get(arg2));
        Bitmap bitmap = util.getBitmapLruCache(mListId.get(arg2));
 
        if(message !=null) {
            intentNewsInfo(arg2, message, bitmap);
        }else{
            intentNewsInfo(arg2,null,null);
        }
 
    }
 
    publicvoidintentNewsInfo(intarg2, String message, Bitmap bitmap) {
        Intent intent =newIntent(MainActivity.this, NewsinfoActivity.class);
        intent.putExtra(message, message);
        intent.putExtra(bitmap, bitmap);
        intent.putExtra(index, arg2);
        intent.putExtra(id, mListId.get(arg2));
        startActivityForResult(intent,100);
    }

可以看到我们这里先是查找缓存中是否存在数据如果存在直接传给新闻详情界面,如果没有则在第二个界面获取再传回来。

 

 

?
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
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
publicclassNewsinfoActivityextendsActivity {
 
    privateString NEWS_INFO = http://api.yi18.net/top/show?id=;
    privateString imageRes[] = {
            http://d.hiphotos.baidu.com/image/h%3D360/sign=405b763459afa40f23c6c8db9b65038c/562c11dfa9ec8a13508c96e6f403918fa0ecc026.jpg,
            http://c.hiphotos.baidu.com/image/h%3D360/sign=798b4f82caea15ce5eeee60f86013a25/9c16fdfaaf51f3dece3f986397eef01f3a297923.jpg,
            http://f.hiphotos.baidu.com/image/h%3D360/sign=20a94e03940a304e4d22a6fce1c9a7c3/ac4bd11373f082028719ab3848fbfbedab641b29.jpg,
            http://b.hiphotos.baidu.com/image/h%3D360/sign=3a1af7349145d688bc02b4a294c37dab/4b90f603738da977c0f5b82cb351f8198718e3db.jpg,
            http://d.hiphotos.baidu.com/image/h%3D360/sign=75e596560f33874483c5297a610ed937/55e736d12f2eb9381891b2f4d6628535e5dd6f3c.jpg };
    privateIntent intent;
    privateUtil util;
    privateintnewId, index;
    privateImageView imageView;
    privateTextView textView;
    privateBitmap bitmap;
    privateString message;
 
    protectedvoidonCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_newsinfo);
        intent = getIntent();
        util =newUtil();
        imageView = (ImageView) findViewById(R.id.image);
        textView = (TextView) findViewById(R.id.message);
        newId = intent.getExtras().getInt(id);
        index = intent.getExtras().getInt(index);
        if(intent.getExtras().getString(message) !=null) {
            message = intent.getExtras().getString(message);
            bitmap = intent.getParcelableExtra(bitmap);
            textView.setText(Html.fromHtml(message));
            imageView.setImageBitmap(bitmap);
            Toast.makeText(this, 没有访问网络哦,2000).show();
        }else{
            newDownLoadJson().execute(NEWS_INFO + newId);
            newDownLoadBitmap().execute(imageRes[index]);
            Toast.makeText(this, 访问网络哦,2000).show();
        }
 
    }
 
    @Override
    publicvoidonBackPressed() {
        Intent dataIntent =newIntent();
        dataIntent.putExtra(message, message);
        dataIntent.putExtra(bitmap, bitmap);
        dataIntent.putExtra(newId, newId);
        setResult(20, dataIntent);
        finish();
        super.onBackPressed();
    }
 
    privatevoidgetJsonData(String json) {
        try{
            JSONObject jsonObject =newJSONObject(json);
            if(jsonObject.getBoolean(success)) {
                JSONObject jsonObject2 =newJSONObject(
                        jsonObject.getString(yi18));
                message = jsonObject2.getString(message);
                textView.setText(Html.fromHtml(jsonObject2.getString(message)));
            }
        }catch(JSONException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
 
    classDownLoadJsonextendsAsyncTask<string, string=""> {
 
        @Override
        protectedString doInBackground(String... params) {
            returnutil.downLoadJson(params[0]);
        }
 
        @Override
        protectedvoidonPostExecute(String result) {
            if(result !=null) {
                getJsonData(result);
            }
        }
 
    }
 
    classDownLoadBitmapextendsAsyncTask<string, bitmap=""> {
 
        @Override
        protectedBitmap doInBackground(String... params) {
            // TODO Auto-generated method stub
            returnutil.downLoadBitmap(params[0]);
        }
 
        @Override
        protectedvoidonPostExecute(Bitmap result) {
            if(result !=null) {
                bitmap = result;
                imageView.setImageBitmap(result);
            }
        }
    }
 
}</string,></string,>

这就比较清晰明白了,每次我们都把这个界面获取到的信息存到LruCache里面。

 

 

?
1
2
3
4
5
6
7
8
9
@Override
protectedvoidonActivityResult(intrequestCode,intresultCode, Intent data) {
    intnewId = data.getExtras().getInt(newId);
    String message = data.getExtras().getString(message);
    Bitmap bitmap = data.getParcelableExtra(bitmap);
    util.addJsonLruCache(newId, message);
    util.addBitmapLruCache(newId, bitmap);
    super.onActivityResult(requestCode, resultCode, data);
}

4,效果

 

data-cke-saved-src=http://www.2cto.com/uploadfile/Collfiles/20150207/20150207084914192.gif