【达内课程】音乐播放器4.0(优化)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u010356768/article/details/83026260

最后可以对图片进行压缩,可以查看
https://blog.csdn.net/u010356768/article/details/83016046

增加BitmapUtils文件后
MusicAdapter中修改以下方法

private Bitmap loadBitmap(String url){
        try {
            InputStream is = HttpUtils.getInputStream(url);
            //执行压缩算法,获取合适尺寸的图片
            Bitmap bitmap = BitmapUtils.loadBitmap(is,5,5);
            //Bitmap bitmap = BitmapFactory.decodeStream(is);
            return bitmap;
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

Android中的GC垃圾回收机制与内存泄漏

在这里插入图片描述
如何使用软引用实现内存缓存

在这里插入图片描述
修改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));
            return bitmap;
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }
......

    @Override
    public View getView(int i, View view, ViewGroup viewGroup) {
        ViewHolder holder = null;
        ......
        //给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;
            }
        }
        //向任务集合中一个图片下载任务
        holder.imgPic.setTag(music.getPic_small());
       ......
        return view;
    }

......
}

文件缓存

在这里插入图片描述
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

import android.content.Context;
import android.graphics.Bitmap;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.widget.ImageView;
import android.widget.ListView;

import com.example.xx.v4.R;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.lang.ref.SoftReference;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

/**
 * 异步批量加载图片的工具类
 */
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修改为

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 android.widget.ListView;
import android.widget.TextView;

import com.example.xx.v4.R;
import com.example.xx.v4.entity.Music;
import com.example.xx.v4.util.ImageLoader;

import java.util.List;
/**
 * 音乐列表适配器
 */
public class MusicAdapter extends BaseAdapter {
    private Context context;
    private List<Music> musics;
    private LayoutInflater inflater;

    private ImageLoader imageLoader;

    public MusicAdapter(Context context, List<Music> musics, ListView listView) {
        super();
        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 Music 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.tvSinger = view.findViewById(R.id.tv_singer);
            view.setTag(holder);
        }

        holder = (ViewHolder) view.getTag();
        //给控件赋值
        Music music = getItem(i);
        holder.tvName.setText(music.getTitle());
        holder.tvSinger.setText(music.getAuthor());
        //图片在服务器,本来该起线程显示的,但是,这是adapter.getView()方法
        //每次图片显示时,都要启线程的话,手机会炸的...
        //给holder.imgPic设置图片
        imageLoader.displayImage(music.getPic_small(),holder.imgPic);
        return view;
    }

    public void stopThread() {
        imageLoader.stopThread();
    }

    class ViewHolder{
        ImageView imgPic;
        TextView tvName;
        TextView tvSinger;
    }
}

猜你喜欢

转载自blog.csdn.net/u010356768/article/details/83026260