1. 程式人生 > >【達內課程】音樂播放器4.0(優化)

【達內課程】音樂播放器4.0(優化)

最後可以對圖片進行壓縮,可以檢視
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;
    }
}