这样做,只能自己写图片加载工具类,完全抛弃了第三方的图片加载框架
知识点:
1)Runtime类(运行时类):Runtime类封装了运行时的环境,每个应用程序都有一个Runtime类实例,使应用程序能够与其运行的环境相连接。可以通过getRuntime 方法获取当前Runtime运行时对象的引用,旦得到了一个当前的Runtime对象的引用,就可以调用Runtime对象的方法去控制虚拟机的状态和行为。
Runtime.getRuntime().totalMemory()获取的值是动态的,是虚拟机从系统那里获取的,可以进行内存管理。
2)LruCache类:主要用于内存优化,核心是LinkedHashMap,用Lru算法+数据结构实现,把近期最少使用的数据从缓存中移除,保留使用最频繁的数据(近期最少使用的,使用频率)LruCache以键值对的形式存储数据。
主要用法:构造函数的使用,添加缓存,根据url获取缓存的方法
//1)构造函数要传入一个int类型值,表示缓存的最大值,一般是虚拟机的几分之一。
int maxSize = (int) (Runtime.getRuntime().maxMemory() / 4);
LruCache cacheMap = new LruCache(maxSize);
//2)添加缓存
cacheMap.put("key", bitmap);
//3)根据key获取缓存
Bitmap bit = cacheMap.get("key");
3)BitmapUtils和大多数图片加载框架一样,都是基于内存-文件-网络三级缓存。也就是加载图片的时候首先从内存缓存中取,如果没有再从文件缓存中取,如果文件缓存没有取到,就从网络下载图片并且加入内存和文件缓存。
BitmapUtils内存缓存是如何实现的?BitmapUtils内存缓存的核心类LruMemoryCache,LruMemoryCache代码和v4包的LruCache一样。
4)Executors线程池类的使用:ExecutorService executorService = Executors.newFixedThreadPool(5); 创建一个包含五个线程的线程池,主要是为了重复利用线程。ExecutorService是一个线程池的管理工具。
案例:在ListView中,使用LruCache缓存图片(去掉了sdcard缓存,相当于抄了一遍代码)
Activity中的代码:
package com.crs.demo.ui.lrucache;
import android.graphics.Bitmap;
import android.os.Bundle;
import android.os.Handler;
import android.support.v4.util.LruCache;
import android.widget.ListView;
import com.crs.demo.R;
import com.crs.demo.adapter.LruCacheAdapter;
import com.crs.demo.base.BaseActivity;
import java.util.ArrayList;
/**
* Created on 2016/10/9.
* Author:crs
* Description:LruCache的使用
*/
public class LruCacheActivity extends BaseActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_lrucache);
initViews();
}
private void initViews() {
ArrayList list = new ArrayList<>();
list.add("http://img5.imgtn.bdimg.com/it/u=2296402476,2057547975&fm=21&gp=0.jpg");
list.add("http://img.sdchina.com/news/20100604/c01_2e9c516d-cf8e-468b-a9a5-bc78bc277e71_3.jpg");
list.add("http://p.ishowx.com/uploads/allimg/160823/415-160R3095959.jpg");
ListView lv_test_lru_cache = findView(R.id.lv_test_lru_cache);
LruCacheAdapter lruCacheAdapter = new LruCacheAdapter(this, list);
lv_test_lru_cache.setAdapter(lruCacheAdapter);
}
}
package com.crs.demo.adapter;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import com.crs.demo.R;
import com.crs.demo.ui.lrucache.BitmapUtil;
import java.util.ArrayList;
/**
* Created on 2016/10/9.
* Author:crs
* Description:LruCacheAdapter主要用于测试内存优化
*/
public class LruCacheAdapter extends BaseAdapter {
private LayoutInflater mInflater;
private ArrayList list;
private final BitmapUtil mBitmapUtils;
public LruCacheAdapter(Context mContext, ArrayList list) {
mInflater = LayoutInflater.from(mContext);
this.list = list;
mBitmapUtils = new BitmapUtil(mContext);
}
@Override
public int getCount() {
return list.size();
}
@Override
public Object getItem(int position) {
return null;
}
@Override
public long getItemId(int position) {
return 0;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View view = mInflater.inflate(R.layout.item_viewpager_lrucache, null);
ImageView iv = (ImageView) view.findViewById(R.id.iv_item_viewpager_lrucache);
mBitmapUtils.display(iv,list.get(position));
return view;
}
}
BitmapUtil中的代码:
package com.crs.demo.ui.lrucache;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Handler;
import android.os.Message;
import android.support.v4.util.LruCache;
import android.widget.ImageView;
import com.crs.demo.utils.ToastUtils;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* Created on 2016/10/9.
* Author:crs
* Description:封装LruCache的使用
*/
public class BitmapUtil {
private Context mContext;
private static final int SUCCESS_LOAD_DATA = 0;
private static final int FAILURE_LOAD_DATA = 1;
//LruCache实例,用于存储Bitmap
private LruCache mLruCache;
//线程池管理类
private ExecutorService executorService = Executors.newFixedThreadPool(5);
//创建主线程的消息对象
private BitmapUtil.InnerHandler mHandler = new BitmapUtil.InnerHandler();
public BitmapUtil(Context context) {
this.mContext = context;
//总的可用内存
int mTotalSize = (int) Runtime.getRuntime().totalMemory();
mLruCache = new LruCache(mTotalSize / 8) {
@Override
protected int sizeOf(String key, Bitmap value) {
return value.getRowBytes() * value.getHeight();
}
};
}
public void display(ImageView iv, String url) {
Bitmap bitmap = getBitmapFromMemory(url);
if (bitmap != null) {
iv.setImageBitmap(bitmap);
} else {
getBitmapFromInternet(iv, url);
}
}
private void getBitmapFromInternet(ImageView iv, String url) {
executorService.submit(new BitmapUtil.DownloadImageTask(iv, url));
}
private Bitmap getBitmapFromMemory(String url) {
return mLruCache.get(url);
}
//加载网络图片的线程类
private class DownloadImageTask implements Runnable {
private String imageUrl;
//如何把此ImageView对象传递到Handler中
private ImageView iv;
private HttpURLConnection conn;
public DownloadImageTask(ImageView iv, String url) {
this.imageUrl = url;
this.iv = iv;
}
@Override
public void run() {
try {
URL url = new URL(imageUrl);
conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
conn.setConnectTimeout(3000);
if (conn.getResponseCode() == 200) {
InputStream is = conn.getInputStream();
//此时bitmap对象在子线程里面
Bitmap bitmap = BitmapFactory.decodeStream(is);
//使用LruCache执行内存缓存
mLruCache.put(imageUrl, bitmap);
//封装对象进行传递
BitmapUtil.ImageViewBitmap imageViewBitmap = new BitmapUtil.ImageViewBitmap();
imageViewBitmap.bitmap = bitmap;
imageViewBitmap.iv = iv;
Message message = mHandler.obtainMessage(SUCCESS_LOAD_DATA, imageViewBitmap);
message.sendToTarget();
is.close();
} else {
mHandler.sendEmptyMessage(FAILURE_LOAD_DATA);
}
} catch (Exception e) {
e.printStackTrace();
mHandler.sendEmptyMessage(FAILURE_LOAD_DATA);
} finally {
if (conn != null) {
conn.disconnect();
}
}
}
}
//传递消息的类
private class InnerHandler extends Handler {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what) {
case SUCCESS_LOAD_DATA: {
BitmapUtil.ImageViewBitmap imageViewBitmap = (BitmapUtil.ImageViewBitmap) msg.obj;
Bitmap bitmap = imageViewBitmap.bitmap;
ImageView iv = imageViewBitmap.iv;
iv.setImageBitmap(bitmap);
}
break;
case FAILURE_LOAD_DATA: {
ToastUtils.showShort(mContext, "图片加载异常");
}
break;
}
}
}
//把两者封装成一个对象进行传递
private static class ImageViewBitmap {
ImageView iv;
Bitmap bitmap;
}
}