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,效果

技术分享


项目源码

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。