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,效果也是每次请求一次第二次直接从缓存中提取出来不用再次请求网络

/**
	 * 缓存json数据
	 */
	private LruCache<Integer, String> mJsonCache;
	/**
	 * 缓存图片信息
	 */
	private LruCache<Integer, Bitmap> mBitmapCache;

	public Util() {
		mJsonCache = new LruCache<Integer, String>(1 * 1024 * 1024);
		mBitmapCache = new LruCache<Integer, Bitmap>(2 * 1024 * 1024);
	}

	/**
	 * 添加进入缓存列表
	 *
	 * @param key
	 * @param value
	 */
	public void addJsonLruCache(Integer key, String value) {
		mJsonCache.put(key, value);
	}

	public void addBitmapLruCache(Integer key, Bitmap value) {
		mBitmapCache.put(key, value);
	}

	/**
	 * 从缓存列表中拿出来
	 *
	 * @param key
	 * @return
	 */
	public String getJsonLruCache(Integer key) {
		return mJsonCache.get(key);
	}

	public Bitmap getBitmapLruCache(Integer key) {
		return mBitmapCache.get(key);
	}

可以看到我们准备缓存Bitmap与String,只需要拿到信息的时候put进缓存中,需要的时候get出来,是不是非常简单,我们为我们String分配了1m为我们的Bitmap分配了2m空间,这只是我们的demo为了简单这样使用,实际上我们应该更加详细的考虑到底应该为缓存分配多大的空间

    // 获取到可用内存的最大值,使用内存超出这个值会引起OutOfMemory异常。
    // LruCache通过构造函数传入缓存值,以KB为单位。
    int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024); 

一般来说最大值的1/8左右就可以了。

public class MainActivity extends Activity implements OnItemClickListener {
	private static final String LIST_DATA = "http://api.yi18.net/top/list";
	private ListView mListView;
	private ArrayAdapter<String> mAdapter;
	private ArrayList<Integer> mListId;
	private Util util;

	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		util = new Util();
		mListView = (ListView) findViewById(R.id.list);
		mListId = new ArrayList<Integer>();
		mAdapter = new ArrayAdapter<String>(this,
				android.R.layout.simple_list_item_1);
		mListView.setAdapter(mAdapter);
		mListView.setOnItemClickListener(this);
		new DownLoadJson().execute(LIST_DATA);
	}

这一段就是普通的请求数据添加到ListView中。

private void getJsonData(String json) {
		try {
			JSONObject jsonObject = new JSONObject(json);
			if (jsonObject.getBoolean("success")) {
				JSONArray jsonArray = jsonObject.getJSONArray("yi18");
				for (int i = 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();
		}
	}

	class DownLoadJson extends AsyncTask<String, Void, String> {

		@Override
		protected String doInBackground(String... params) {
			return util.downLoadJson(params[0]);
		}

		@Override
		protected void onPostExecute(String result) {
			if (result != null) {
				getJsonData(result);
			}
		}

	}

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

3,缓存

@Override
	public void onItemClick(AdapterView<?> arg0, View arg1, int arg2, long arg3) {
		// 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);
		}

	}

	public void intentNewsInfo(int arg2, String message, Bitmap bitmap) {
		Intent intent = new Intent(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);
	}

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

public class NewsinfoActivity extends Activity {

	private String NEWS_INFO = "http://api.yi18.net/top/show?id=";
	private String 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" };
	private Intent intent;
	private Util util;
	private int newId, index;
	private ImageView imageView;
	private TextView textView;
	private Bitmap bitmap;
	private String message;

	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_newsinfo);
		intent = getIntent();
		util = new Util();
		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 {
			new DownLoadJson().execute(NEWS_INFO + newId);
			new DownLoadBitmap().execute(imageRes[index]);
			Toast.makeText(this, "访问网络哦", 2000).show();
		}

	}

	@Override
	public void onBackPressed() {
		Intent dataIntent = new Intent();
		dataIntent.putExtra("message", message);
		dataIntent.putExtra("bitmap", bitmap);
		dataIntent.putExtra("newId", newId);
		setResult(20, dataIntent);
		finish();
		super.onBackPressed();
	}

	private void getJsonData(String json) {
		try {
			JSONObject jsonObject = new JSONObject(json);
			if (jsonObject.getBoolean("success")) {
				JSONObject jsonObject2 = new JSONObject(
						jsonObject.getString("yi18"));
				message = jsonObject2.getString("message");
				textView.setText(Html.fromHtml(jsonObject2.getString("message")));
			}
		} catch (JSONException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	class DownLoadJson extends AsyncTask<String, Void, String> {

		@Override
		protected String doInBackground(String... params) {
			return util.downLoadJson(params[0]);
		}

		@Override
		protected void onPostExecute(String result) {
			if (result != null) {
				getJsonData(result);
			}
		}

	}

	class DownLoadBitmap extends AsyncTask<String, Void, Bitmap> {

		@Override
		protected Bitmap doInBackground(String... params) {
			// TODO Auto-generated method stub
			return util.downLoadBitmap(params[0]);
		}

		@Override
		protected void onPostExecute(Bitmap result) {
			if (result != null) {
				bitmap = result;
				imageView.setImageBitmap(result);
			}
		}
	}

}

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

	@Override
	protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        int newId = 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,效果

项目源码

时间: 2024-10-06 23:03:52

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

Android中高效的显示图片之三——缓存图片

加载一张图片到UI相对比较简单,如果一次要加载一组图片,就会变得麻烦很多.像ListView,GridView,ViewPager等控件,需要显示的图片和将要显示的图片数量可能会很大. 为了减少内存使用,这类控件都重复利用移出屏幕的子视图,如果你没有持用引用,垃圾回收器也会回收你加载过的图片.这种做法很好,但是如果想要图片加载快速流畅且不想当控件拖回来时重新运算获取加载过的图片,通常会使用内存和磁盘缓存.这节主要介绍当加载多张图片时利用内存缓存和磁盘缓存使加载图片时更快. 一.使用内存缓存 内存

Android Bitmap 加载多张图片的缓存处理(精华二)

一般少量图片是很少出现OOM异常的,除非单张图片过~大~ 那么就可以用教程一里面的方法了通常应用场景是listview列表加载多张图片,为了提高效率一般要缓存一部分图片,这样方便再次查看时能快速显示~不用重新下载图片但是手机内存是很有限的~当缓存的图片越来越多,即使单张图片不是很大,不过数量太多时仍然会出现OOM的情况了~本篇则是讨论多张图片的处理问题 -----------------------------------------------------------------------

【转】图片缓存之内存缓存技术LruCache、软引用 比较

每当碰到一些大图片的时候,我们如果不对图片进行处理就会报OOM异常,这个问题曾经让我觉得很烦恼,后来终于得到了解决,那么现在就让我和大家一起分享一下吧.这篇博文要讲的图片缓存机制,我接触到的有两钟,一种是软引用,另一种是内存缓存技术.先来看下两者的使用方式,再来作比较.除了加载图片时要用到缓存处理,还有一个比较重要的步骤要做,就是要先压缩图片. 1.压缩图片至于要压缩到什么状态就要看自己当时的处境了,压缩图片的时候既要达到一个小的值,又不能让其模糊,更不能拉伸图片. /** * 加载内存卡图片

android内存优化之图片压缩和缓存

由于手机内存的限制和网络流量的费用现在,我们在加载图片的时候,必须要做好图片的压缩和缓存. 图片缓存机制一般有2种,软引用和内存缓存技术. 1.压缩图片:压缩图片要既不能模糊,也不能拉伸图片. 图片操作的时候,最常用的是BitmapFactory,现在看看如何压缩图片. Bitmapfactory.Options options= new BitmapFactory.Options(); options.inJustDecodeBounds = true;// 如果设置这个参数为ture,就不会

Android volley 解析(四)之缓存篇

这是 volley 的第四篇 blog 了,写完这篇,volley 的大部分用法也都算写了一遍,所以暂时不会写 volley 的文章了,如果想看我前面写的文章,可以点这里 Android volley 解析(三)之文件上传篇 为什么要用缓存 我们知道,当客户端在请求网络数据的时候,是需要消耗流量的,特别是对于移动端用户来说,对于流量的控制要求很高.所以在做网络请求的时候,如果对数据更新要求不是特别高,往往都会用到缓存机制,一方面能减少对服务端的请求,控制流量:另一方面,当客户端在没有网络的情况下

Android缓存机制&amp;一个缓存框架推荐

1.先推荐一个轻量级缓存框架--ACache(ASimpleCache) ACache介绍: ACache类似于SharedPreferences,但是比SharedPreferences功能更加强大,SharedPreferences只能保存一些基本数据类型.Serializable.Bundle等数据, 而Acache可以缓存如下数据: 普通的字符串.JsonObject.JsonArray.Bitmap.Drawable.序列化的java对象,和 byte数据. 主要特色: 1:轻,轻到只

【Android Studio】深入探究webView的缓存机制

最近一直都在搞webview,搞过Android的人可能会知道,webView本身自带了缓存机制,company的需求是不用webView 的缓存机制,写自己的缓存机制,哇哈哈,有挑战性咯.写这篇博客主要是记录一下我的学习过程.写的不好,勿喷. 首先我们要搞明白webView的缓存机制是什么? webView中有两种缓存: 一是网页数据缓存(即浏览网页中的资源),而是H5缓存(即appCache). webView的缓存目录: /data/data/package_name/cache/ web

android上的缓存、缓存算法和缓存框架

1.使用缓存的目的 缓存是存取数据的临时地,因为取原始数据代价太大了,加了缓存,可以取得快些.缓存可以认为是原始数据的子集,它是从原始数据里复制出来的,并且为了能被取回,被加上了标志. 在android开发中,经常要访问网络数据比如大量网络图片,如果每次需要同一张图片都去网络获取,这代价显然太大了.可以考虑设置本地文件缓存和内存 缓存,存储从网络取得的数据:本地文件缓存空间并非是无限大的,容量越大读取效率越低,可设置一个折中缓存容量比如10M,如果缓存已满,我们需要采用合 适的替换策略换掉一个已

Android艺术——Bitmap高效加载和缓存代码分析(2)

Bitmap的加载与缓存代码分析: 图片的压缩 比如有一张1024*768像素的图像要被载入内存,然而最终你要用到的图片大小其实只有128*96,那么我们会浪费很大一部分内存,这显然是没有必要的,下面是一个实例: public static int calculateInSampleSize(              BitmapFactory.Options options, int reqWidth, int reqHeight) {      // Raw height and widt