文件缓存
文件缓存(把图片存入文件中)
向文件中存:
void BitmapUtils.save(bitmap,file){}
从文件中取:
Bitmap BitmapUtils.loadBitmap(File file){}
BitmapUtils增加如下方法
/**
* 用jpeg格式存储bitmap
*
* @param bitmap
* @param file
*/
public static void save(Bitmap bitmap, File file) throws IOException {
if (!file.getParentFile().exists()) {//父目录不存在
file.getParentFile().mkdirs();
}
FileOutputStream fos = new FileOutputStream(file);
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, fos);
}
/**
* 从文件中加载一个Bitmap
*
* @param file
* @return
*/
public static Bitmap bitmap(File file) {
if (!file.exists()) {
return null;
}
Bitmap b = BitmapFactory.decodeFile(file.getAbsolutePath());
return b;
}
MusicAdapter修改如下
/**
* 音乐列表适配器
*/
public class MusicAdapter extends BaseAdapter {
......
private ListView listView;
private HashMap<String,SoftReference<Bitmap>> cache = new HashMap<>();
......
/**
* 通过url地址 发送http请求 获取图片
* @param url
* @return
*/
private Bitmap loadBitmap(String url){
try {
InputStream is = HttpUtils.getInputStream(url);
//执行压缩算法,获取合适尺寸的图片
Bitmap bitmap = BitmapUtils.loadBitmap(is,50,50);
//Bitmap bitmap = BitmapFactory.decodeStream(is);
//把bitmap放入内存缓存
cache.put(url,new SoftReference<Bitmap>(bitmap));
//把bitmap存入文件中
//data/data/包名/cache文件夹 内部存储的缓存目录
String fileName = url.substring(url.lastIndexOf("/")+1);
Log.d("IMAGES",fileName);
File file = new File(context.getCacheDir(),"images/"+fileName);
BitmapUtils.save(bitmap,file);
return bitmap;
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
......
@Override
public View getView(int i, View view, ViewGroup viewGroup) {
ViewHolder holder = null;
......
//图片在服务器,本来该起线程显示的,但是,这是adapter.getView()方法
//每次图片显示时,都要启线程的话,手机会炸的...
//给holder.imgPic设置图片
//先去内存缓存中看有没有
SoftReference<Bitmap> ref = cache.get(music.getPic_small());
if(ref!=null){//以前存过
Bitmap bitmap = ref.get();
if(bitmap!=null){//以前存的还没有被清掉
holder.imgPic.setImageBitmap(bitmap);
return view;
}
}
//去文件缓存中读取
String url = music.getPic_small();
String fileName = url.substring(url.lastIndexOf("/")+1);
File file = new File(context.getCacheDir(),"images/"+fileName);
Bitmap bitmap = BitmapUtils.bitmap(file);
if(bitmap!=null){
//一旦从文件中读取出来,先存入内存缓存
//内存是最快的
cache.put(url,new SoftReference<Bitmap>(bitmap));
holder.imgPic.setImageBitmap(bitmap);
return view;
}
//向任务集合中一个图片下载任务
......
return view;
}
......
}
查看data/data/包名/cache可以看到下载的图片
封装
新增图片加载类 ImageLoader
/**
* 异步批量加载图片的工具类
*/
public class ImageLoader {
private HashMap<String, SoftReference<Bitmap>> cache = new HashMap<>();
private Context context;
private List<ImageLoaderTask> tasks = new ArrayList<ImageLoaderTask>();
private Thread workThread;
private boolean isLoop = true;
private ListView listView;
private Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case HANDLER_IMAGE_LOAD_SUCCESS:
//给相应的Imageview设置bitmap
ImageLoaderTask task = (ImageLoaderTask) msg.obj;
Bitmap bitmap = task.bitmap;
ImageView imageView = (ImageView) listView.findViewWithTag(task.path);
if (imageView != null) {
if (bitmap != null) {
imageView.setImageBitmap(bitmap);
} else {
imageView.setImageResource(R.mipmap.ic_launcher);
}
}
break;
}
}
};
public static final int HANDLER_IMAGE_LOAD_SUCCESS = 1;
public ImageLoader(Context context, ListView listView) {
this.context = context;
this.listView = listView;
//启动工作线程,轮循任务集合
//匿名内部类持有外部类对象引用
//在匿名内部类中可以使用MusicAdapter.this
workThread = new Thread() {
@Override
public void run() {
while (isLoop) {
if (!tasks.isEmpty()) {//不是空集合
ImageLoaderTask task = tasks.remove(0);//remove的同时返回该数据
String url = task.path;
//发送http请求 下载图片
Bitmap bitmap = loadBitmap(url);
task.bitmap = bitmap;
//更新界面 发消息给Handler
Message message = new Message();
message.what = HANDLER_IMAGE_LOAD_SUCCESS;
message.obj = task;
handler.sendMessage(message);
} else {//空集合 等待
try {
//锁
synchronized (workThread) {
workThread.wait();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
};
workThread.start();
}
public void stopThread() {
//isLoop为false,循环停止
isLoop = false;
//当我们按返回键时,线程在wait(),应先唤醒
synchronized (workThread) {
workThread.notify();
}
}
public void displayImage(String url, ImageView imageView) {
//先去内存缓存中看有没有
SoftReference<Bitmap> ref = cache.get(url);
if (ref != null) {//以前存过
Bitmap bitmap = ref.get();
if (bitmap != null) {//以前存的还没有被清掉
imageView.setImageBitmap(bitmap);
return;
}
}
//去文件缓存中读取
String fileName = url.substring(url.lastIndexOf("/") + 1);
File file = new File(context.getCacheDir(), "images/" + fileName);
Bitmap bitmap = BitmapUtils.bitmap(file);
if (bitmap != null) {
//一旦从文件中读取出来,先存入内存缓存
//内存是最快的
cache.put(url, new SoftReference<Bitmap>(bitmap));
imageView.setImageBitmap(bitmap);
return;
}
//向任务集合中一个图片下载任务
imageView.setTag(url);
ImageLoaderTask task = new ImageLoaderTask();
task.path = url;
tasks.add(task);
//唤醒工作线程,起来干活
synchronized (workThread) {
workThread.notify();
}
}
class ImageLoaderTask {
String path;//保存图片下载路径
Bitmap bitmap;//下载成功后的图片
}
/**
* 通过url地址 发送http请求 获取图片
*
* @param url
* @return
*/
private Bitmap loadBitmap(String url) {
try {
InputStream is = HttpUtils.getInputStream(url);
//执行压缩算法,获取合适尺寸的图片
Bitmap bitmap = BitmapUtils.loadBitmap(is, 50, 50);
//Bitmap bitmap = BitmapFactory.decodeStream(is);
//把bitmap放入内存缓存
cache.put(url, new SoftReference<Bitmap>(bitmap));
//把bitmap存入文件中
//data/data/包名/cache文件夹 内部存储的缓存目录
String fileName = url.substring(url.lastIndexOf("/") + 1);
Log.d("IMAGES", fileName);
File file = new File(context.getCacheDir(), "images/" + fileName);
BitmapUtils.save(bitmap, file);
return bitmap;
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
}
MusicAdapter 可以修改为
/**
* 音乐列表适配器
*/
public class MusicAdapter extends BaseAdapter {
private Context context;
private List<MusicItem> musics;
private LayoutInflater inflater;
private ImageLoader imageLoader;
public MusicAdapter(Context context, List<MusicItem> musics, ListView listView) {
super(context, musics);
this.context = context;
this.musics = musics;
this.inflater = LayoutInflater.from(context);
this.imageLoader = new ImageLoader(context, listView);
}
@Override
public int getCount() {
return musics.size();
}
@Override
public MusicItem getItem(int i) {
return musics.get(i);
}
@Override
public long getItemId(int i) {
return i;
}
@Override
public View getView(int i, View view, ViewGroup viewGroup) {
ViewHolder holder = null;
if (view == null) {
view = inflater.inflate(R.layout.item_lv_music, null);
holder = new ViewHolder();
holder.imgPic = view.findViewById(R.id.img_Pic);
holder.tvName = view.findViewById(R.id.tv_name);
holder.tvAlbum = view.findViewById(R.id.tv_album);
view.setTag(holder);
}
holder = (ViewHolder) view.getTag();
//给控件赋值
MusicItem music = getItem(i);
holder.tvName.setText(music.name);
holder.tvAlbum.setText(music.albumName);
//图片在服务器,本来该起线程显示的,但是,这是adapter.getView()方法
//每次图片显示时,都要启线程的话,手机会炸的...
//给holder.imgPic设置图片
imageLoader.displayImage(music.albumPic, holder.imgPic);
return view;
}
public void stopThread() {
imageLoader.stopThread();
}
class ViewHolder {
ImageView imgPic;
TextView tvName;
TextView tvAlbum;
}
}