Android-單線程輪循機制批量下載圖片、圖片壓縮、內存泄漏、圖片緩存、文件緩存

ListView異步批量加載圖片

單線程輪循機制批量下載圖片

例如:imageloader框架底層也是這麼實現的!

思路:主線程向任務集合添加一個任務,工作線程從任務集合移除第一個任務,如果有任務一直移除,一直輪循,拿到圖片之後解析成Bitmap,呈現的imageView當中。

這裏寫圖片描述

package com.tarena.musicclient.adapter;

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

import org.apache.http.HttpEntity;
import org.apache.http.util.EntityUtils;

import com.tarena.musicclient.activity.R;
import com.tarena.musicclient.entity.Music;
import com.tarena.musicclient.util.BitmapUtils;
import com.tarena.musicclient.util.GlobalConsts;
import com.tarena.musicclient.util.HttpUtils;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Handler;
import android.os.Message;
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;

public class MusicAdapter extends BaseAdapter{
    private Context context;
    private List<Music> musics;
    private LayoutInflater inflater;
    //(2)聲明任務集合  
    private List<ImageLoadTask> tasks=new ArrayList<ImageLoadTask>();
    private ListView listView;
    //聲明用於輪循任務集合的工作線程
    private Thread workThread;
    //聲明變量控制while循環
    private boolean isLoop=true;
    //聲明緩存集合
    private HashMap<String, SoftReference<Bitmap>> cache 
        =new HashMap<String, SoftReference<Bitmap>>();

    //聲明Handler  更新ImageView
    private Handler handler=new Handler(){
        public void handleMessage(android.os.Message msg) {
            switch (msg.what) {
            case HANDLER_LOAD_IMAGE_SUCCESS:
                //給ImageView設置Bitmap
                ImageLoadTask task=(ImageLoadTask)msg.obj;
                //通過tag尋找到相應的ImageView
                ImageView ivAlum=(ImageView)listView.findViewWithTag(task.position);
                if(ivAlum!=null){
                    if(task.bitmap!=null){
                        ivAlum.setImageBitmap(task.bitmap);
                    }else{
                        ivAlum.setImageResource(R.drawable.ic_launcher);
                    }
                }
                break;
            }
        }
    };

    public static final int HANDLER_LOAD_IMAGE_SUCCESS=0;


    public MusicAdapter(Context context, List<Music> musics, ListView listView) {
        this.context=context;
        this.musics=musics;
        this.listView=listView;
        inflater=LayoutInflater.from(context);
        //(5)MusicAdapter有幾個,工作線程就有幾個
        //對workThread進行初始化
        workThread=new Thread(){
            public void run() {
                //(6)不斷輪循任務集合
                while(isLoop){
                    //如果任務集合不是空集  
                    if(!tasks.isEmpty()){
                        //獲取任務對象並且發送請求 
                        ImageLoadTask task = tasks.remove(0);
                        //通過路徑返回Bitmap對象
                        Bitmap bitmap=loadBitmap(task.path);
                        task.bitmap=bitmap;
                        //給相應的ImageView設置Bitmap   handler
                        Message msg=new Message();
                        msg.what=HANDLER_LOAD_IMAGE_SUCCESS;
                        msg.obj=task;
                        handler.sendMessage(msg);
                    }else{
                        //同步代碼塊:一但調用了某個對象的wait()/notify()方法後,外面一定套一個以這個對象爲鎖的同步代碼塊
                        synchronized (workThread) {
                            //如果任務集合是空集  wait等待
                            try {
                                workThread.wait();
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }
                    }
                }
            }
        };
        workThread.start();
    }

    /**
     * 通過path  獲取Bitmap
     * @param path
     * @return
     */
    public Bitmap loadBitmap(String path){
        Bitmap bitmap=null;
        String uri=GlobalConsts.BASEURL+path;
        try {
            //實體轉成字節數組,字節數組轉成圖片
            HttpEntity entity=HttpUtils.send(HttpUtils.METHOD_GET, uri, null);
            byte[] bytes=EntityUtils.toByteArray(entity);
            bitmap=BitmapUtils.loadBitmap(bytes, 50, 50);
            //向緩存集合中存儲緩存圖片
            cache.put(path, new SoftReference<Bitmap>(bitmap));

        } catch (IOException e) {
            e.printStackTrace();
        }
        return bitmap;
    }

    @Override
    public int getCount() {
        return musics.size();
    }

    public Object getItem(int position) {
        return musics.get(position);
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

    public View getView(int position, View convertView, ViewGroup parent) {
        ViewHolder holder=null;
        if(convertView==null){
            convertView=inflater.inflate(R.layout.item_lv_music, null);
            holder=new ViewHolder();
            holder.ivAlbum=(ImageView)convertView.findViewById(R.id.imageView1);
            holder.tvName=(TextView)convertView.findViewById(R.id.tvName);
            holder.tvDuration=(TextView)convertView.findViewById(R.id.tvDuration);
            holder.tvSinger=(TextView)convertView.findViewById(R.id.tvSinger);
            holder.tvAuthor=(TextView)convertView.findViewById(R.id.tvAuthor);
            convertView.setTag(holder);
        }
        holder=(ViewHolder)convertView.getTag();
        //給控件賦值
        Music music=musics.get(position);
        holder.tvName.setText(music.getName());
        holder.tvSinger.setText(music.getSinger());
        holder.tvAuthor.setText(music.getAuthor());
        holder.tvDuration.setText(music.getDurationtime());
        //給當前item中的ImageView設置一個Tag
        //用於圖片下載完成後根據該tag
        //找到相應的ImageView
        holder.ivAlbum.setTag(position);
        //查詢緩存中是否有圖片 如果有 則直接獲取
        SoftReference<Bitmap> ref=cache.get(music.getAlbumpic());
        if(ref!=null && ref.get()!=null){
            Bitmap bitmap=ref.get();
            holder.ivAlbum.setImageBitmap(bitmap);
            System.out.println("從緩存中讀取圖片..");
            return convertView;
        }
        //(3)下載一張圖片  
        //向任務隊列中添加一個圖片任務
        ImageLoadTask task=new ImageLoadTask();
        //albumPic:   images/xxxxx.jpg
        task.path=music.getAlbumpic();
        task.position=position;
        tasks.add(task);
        //(4)喚醒工作線程  起來幹活
        notifyWorkThread();
        return convertView;
    }
    /**
     * 喚醒工作線程
     */
    public void notifyWorkThread(){
    //注意:一但調用wait活notify方法的時候,就要在這個同步代碼塊對象上加鎖
        synchronized (workThread) {
            workThread.notify();
        }
    }

    //(1)創建圖片下載任務類型的類
    class ImageLoadTask{
        String path;//圖片路徑
        Bitmap bitmap;//圖片對象
        int position; 
    }

    class ViewHolder{
        ImageView ivAlbum;
        TextView tvName;
        TextView tvDuration;
        TextView tvSinger;
        TextView tvAuthor;
    }

    public void stopWorkThread() {
        isLoop=false;
        notifyWorkThread();
    }
}

圖片壓縮

圖片壓縮的意義:(像一些小圖標,不需要很高清)
例如我們寫的上面的程序圖片都是從服務器端下載下來的,一個圖片大小是5k,但是這個5k的圖片加載到內存裏就不止是5k了,一個Bitmap肯定比5k要多(5k的十倍)50k,10張就500k(半兆),這樣圖片多了的話就非常浪費內存,佔用內存!當佔用內存十分大的時候,android 手機就會出現GC(垃圾回收機制),自動銷燬堆內存中的垃圾。如果java管理的內存越來越滿,快溢出了,GC執行頻率會上升,導致效果:在GC執行垃圾回收的時候,所有的線程暫停,主線程也不準繪製UI!如果GC執行頻率非常頻繁,肯定會出現吊幀,卡頓的現象!

Bitmap圖片(位圖對象):

BitmapFactory 圖片工廠:

Options封裝了創建Bitmap對象時使用的參數

package com.tarena.musicclient.adapter;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import org.apache.http.HttpEntity;
import org.apache.http.util.EntityUtils;

import com.tarena.musicclient.activity.R;
import com.tarena.musicclient.entity.Music;
import com.tarena.musicclient.util.BitmapUtils;
import com.tarena.musicclient.util.GlobalConsts;
import com.tarena.musicclient.util.HttpUtils;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Handler;
import android.os.Message;
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;

public class MusicAdapter extends BaseAdapter{
    private Context context;
    private List<Music> musics;
    private LayoutInflater inflater;
    //聲明任務集合  
    private List<ImageLoadTask> tasks=new ArrayList<ImageLoadTask>();
    private ListView listView;
    //聲明用於輪循任務集合的工作線程
    private Thread workThread;
    //聲明Handler  更新ImageView
    private Handler handler=new Handler(){
        public void handleMessage(android.os.Message msg) {
            switch (msg.what) {
            case HANDLER_LOAD_IMAGE_SUCCESS:
                //給ImageView設置Bitmap
                ImageLoadTask task=(ImageLoadTask)msg.obj;
                //通過tag尋找到相應的ImageView
                ImageView ivAlum=(ImageView)listView.findViewWithTag(task.position);
                if(ivAlum!=null){
                    if(task.bitmap!=null){
                        ivAlum.setImageBitmap(task.bitmap);
                    }else{
                        ivAlum.setImageResource(R.drawable.ic_launcher);
                    }
                }
                break;
            }
        }
    };

    public static final int HANDLER_LOAD_IMAGE_SUCCESS=0;


    public MusicAdapter(Context context, List<Music> musics, ListView listView) {
        this.context=context;
        this.musics=musics;
        this.listView=listView;
        inflater=LayoutInflater.from(context);
        //對workThread進行初始化
        workThread=new Thread(){
            public void run() {
                //不斷輪循任務集合
                while(true){
                    //如果任務集合不是空集  
                    if(!tasks.isEmpty()){
                        //獲取任務對象並且發送請求 
                        ImageLoadTask task = tasks.remove(0);
                        Bitmap bitmap=loadBitmap(task.path);
                        task.bitmap=bitmap;
                        //給相應的ImageView設置Bitmap   handler
                        Message msg=new Message();
                        msg.what=HANDLER_LOAD_IMAGE_SUCCESS;
                        msg.obj=task;
                        handler.sendMessage(msg);
                    }else{
                        synchronized (workThread) {
                            //如果任務集合是空集  wait等待
                            try {
                                workThread.wait();
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }
                    }
                }
            }
        };
        workThread.start();
    }

    /**
     * 通過path  獲取Bitmap
     * @param path
     * @return
     */
    public Bitmap loadBitmap(String path){
        Bitmap bitmap=null;
        String uri=GlobalConsts.BASEURL+path;
        try {
            HttpEntity entity=HttpUtils.send(HttpUtils.METHOD_GET, uri, null);
            byte[] bytes=EntityUtils.toByteArray(entity);
            /**
             *圖片壓縮處理,工具類工具方法(傳個來字節數字,和寬度、高度)
             **/
            bitmap=BitmapUtils.loadBitmap(bytes, 50, 50);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return bitmap;
    }

    @Override
    public int getCount() {
        return musics.size();
    }

    public Object getItem(int position) {
        return musics.get(position);
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

    public View getView(int position, View convertView, ViewGroup parent) {
        ViewHolder holder=null;
        if(convertView==null){
            convertView=inflater.inflate(R.layout.item_lv_music, null);
            holder=new ViewHolder();
            holder.ivAlbum=(ImageView)convertView.findViewById(R.id.imageView1);
            holder.tvName=(TextView)convertView.findViewById(R.id.tvName);
            holder.tvDuration=(TextView)convertView.findViewById(R.id.tvDuration);
            holder.tvSinger=(TextView)convertView.findViewById(R.id.tvSinger);
            holder.tvAuthor=(TextView)convertView.findViewById(R.id.tvAuthor);
            convertView.setTag(holder);
        }
        holder=(ViewHolder)convertView.getTag();
        //給控件賦值
        Music music=musics.get(position);
        holder.tvName.setText(music.getName());
        holder.tvSinger.setText(music.getSinger());
        holder.tvAuthor.setText(music.getAuthor());
        holder.tvDuration.setText(music.getDurationtime());
        //給當前item中的ImageView設置一個Tag
        //用於圖片下載完成後根據該tag
        //找到相應的ImageView
        holder.ivAlbum.setTag(position);

        //下載一張圖片  
        //向任務隊列中添加一個圖片任務
        ImageLoadTask task=new ImageLoadTask();
        //albumPic:   images/xxxxx.jpg
        task.path=music.getAlbumpic();
        task.position=position;
        tasks.add(task);
        //喚醒工作線程  起來幹活
        notifyWorkThread();
        return convertView;
    }
    /**
     * 喚醒工作線程,起來運行跳出循環
     */
    public void notifyWorkThread(){
        synchronized (workThread) {
            workThread.notify();
        }
    }


    class ImageLoadTask{
        String path;
        Bitmap bitmap;
        int position;
    }

    class ViewHolder{
        ImageView ivAlbum;
        TextView tvName;
        TextView tvDuration;
        TextView tvSinger;
        TextView tvAuthor;
    }
}

圖片壓縮工具類

package com.tarena.musicclient.util;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.BitmapFactory.Options;

public class BitmapUtils {

    /**
     * 通過字節數組解析出Bitmap對象
     * 需要按照一定的寬高的規格進行壓縮
     * @param bytes  數據源
     * @param width  圖片的目標寬度
     * @param height  圖片的目標高度
     * @return
     */
    public static Bitmap loadBitmap(byte[] bytes, int width, int height) {
        Options opt=new Options();
        //設置是否僅僅加載邊界屬性
        opt.inJustDecodeBounds=true;
        BitmapFactory.decodeByteArray(bytes, 0, bytes.length, opt);
        //獲取圖片的原始的高度與寬度
        int w=opt.outWidth/width;
        int h=opt.outHeight/height;
        int scale=w>h ? w : h;
        //設置壓縮比例
        opt.inSampleSize=scale;
        //再次進行解析Bitmap
        opt.inJustDecodeBounds=false;
        return BitmapFactory.decodeByteArray(bytes, 0, bytes.length, opt);
    }

}

Android 內存泄漏

Android內存當中有垃圾對象,這些垃圾對象被佔用了之後還不能被GC(垃圾回收機制回收)內存也不能重複利用,導致內存泄漏。
GC垃圾回收機制:
這裏寫圖片描述

項目中內存泄漏中的地方:
這裏寫圖片描述
解決方法:
在Activity生命週期方法中銷燬的時候關閉當前線程,詳情看上方代碼

內存泄漏最常見的情況:
Thread
new Thread (){}.start()必須給出run方法執行完畢的條件,在應用程序退出的時候銷燬工作線程。

查看本程序中運行的線程

這裏寫圖片描述

Java中的引用

強引用: StrongReference
e=new Emp();
就算出OOM,也不會銷燬強引用
軟引用: SoftReference
弱java管理的內存接近閾值,將會銷燬一些軟引用。釋放內存
弱引用: WeakReference
就算java管理的內存沒有接近閾值,就會銷燬一些弱引用。
虛引用: …………
由GC管理的。

軟引用的使用:
SoftReference s=new SoftReference(bitmap);
Bitmap bitmap=s.get();

Android圖片的內存緩存

第一次把圖片下載到手機後,存入內存中,再次需要下載圖片時,先去內存中查詢,如果已經下載過,那麼直接獲取,如果沒有獲取過,再去下載。
存:
注意:
一直存會容易c內存溢出OOM
HashMap < String,Bitmap > cache ;
cache.put(“images/jsjs.jpg”,bitmap);
cache.put(“images/jsjs.jpg”,bitmap);
cache.put(“images/jsjs.jpg”,bitmap);
cache.put(“images/jsjs.jpg”,bitmap);
cache.put(“images/jsjs.jpg”,bitmap);
WeakHashMap:
弱引用,當java的內存達到閾值的時候,會隨機刪除鍵值對。
取:
Bitmap bitmap=cache.get(“images/jsjs.jpg”);
改進後:
HashMap < String,SoftReference> map;
map.put(path,new SoftReference(bitmap));
map.get(path).get();
代碼參考上方例子

圖片的文件緩存

(1)下載圖片後,把圖片數據保存到應用的緩存目錄中。

public void save(File targetFile,Bitmap bitmap)//工具類存的方法

Bitmap bitmap;
FileOutputStream fos;//寫出到文件
file.write();
//緩存目錄都存到cach文件中
bimap.compress();//壓縮方法

(2)再次獲取圖片時,先去內存緩存中去查詢,如果沒有則去緩存目錄中查詢。有則直接讀取。沒有的話再次發送請求。

public Bitmap loadBitmap(path)//工具類方法:通過路徑加載bitmap,也可以出入壓縮的比例

String path;
BitmapFactory.decodeFile(path,Options);

文件緩存工具類方法:

package com.tarena.musicclient.util;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;

import android.graphics.Bitmap;
import android.graphics.Bitmap.CompressFormat;
import android.graphics.BitmapFactory;
import android.graphics.BitmapFactory.Options;

public class BitmapUtils {

    /**
     * 通過一個文件路徑  查找到Bitmap
     * @param path
     * @return
     * @throws IOException
     */
    public static Bitmap  loadBitmap(String path)throws IOException{
        File file=new File(path);
        if(file.exists()){
            return BitmapFactory.decodeFile(path);
        }
        return null;
    }

    /***
     * 保存圖片
     * @param targetFile  目標文件
     * @param bitmap  位圖對象
     * @throws IOException  
     */
    public static void save(File targetFile, Bitmap bitmap)throws IOException{
        if(!targetFile.getParentFile().exists()){
            //父目錄不存在 則創建
            targetFile.getParentFile().mkdirs();
        }
        if(!targetFile.exists()){
            targetFile.createNewFile();
        }
        //寫入
        FileOutputStream fos=new FileOutputStream(targetFile);
        bitmap.compress(CompressFormat.JPEG, 100, fos);
    }

    /**
     * 通過字節數組解析出Bitmap對象
     * 需要按照一定的寬高的規格進行壓縮
     * @param bytes  數據源
     * @param width  圖片的目標寬度
     * @param height  圖片的目標高度
     * @return
     */
    public static Bitmap loadBitmap(byte[] bytes, int width, int height) {
        Options opt=new Options();
        //設置是否僅僅加載邊界屬性
        opt.inJustDecodeBounds=true;
        BitmapFactory.decodeByteArray(bytes, 0, bytes.length, opt);
        //獲取圖片的原始的高度與寬度
        int w=opt.outWidth/width;
        int h=opt.outHeight/height;
        int scale=w>h ? w : h;
        //設置壓縮比例
        opt.inSampleSize=scale;
        //再次進行解析Bitmap
        opt.inJustDecodeBounds=false;
        return BitmapFactory.decodeByteArray(bytes, 0, bytes.length, opt);
    }

}

使用:

package com.tarena.musicclient.adapter;

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

import org.apache.http.HttpEntity;
import org.apache.http.util.EntityUtils;

import com.tarena.musicclient.activity.R;
import com.tarena.musicclient.entity.Music;
import com.tarena.musicclient.util.BitmapUtils;
import com.tarena.musicclient.util.GlobalConsts;
import com.tarena.musicclient.util.HttpUtils;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
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;

public class MusicAdapter extends BaseAdapter{
    private Context context;
    private List<Music> musics;
    private LayoutInflater inflater;
    //聲明任務集合  
    private List<ImageLoadTask> tasks=new ArrayList<ImageLoadTask>();
    private ListView listView;
    //聲明用於輪循任務集合的工作線程
    private Thread workThread;
    //聲明變量控制while循環
    private boolean isLoop=true;
    //聲明緩存集合
    private HashMap<String, SoftReference<Bitmap>> cache 
        =new HashMap<String, SoftReference<Bitmap>>();

    //聲明Handler  更新ImageView
    private Handler handler=new Handler(){
        public void handleMessage(android.os.Message msg) {
            switch (msg.what) {
            case HANDLER_LOAD_IMAGE_SUCCESS:
                //給ImageView設置Bitmap
                ImageLoadTask task=(ImageLoadTask)msg.obj;
                //通過tag尋找到相應的ImageView
                ImageView ivAlum=(ImageView)listView.findViewWithTag(task.position);
                if(ivAlum!=null){
                    if(task.bitmap!=null){
                        ivAlum.setImageBitmap(task.bitmap);
                    }else{
                        ivAlum.setImageResource(R.drawable.ic_launcher);
                    }
                }
                break;
            }
        }
    };

    public static final int HANDLER_LOAD_IMAGE_SUCCESS=0;


    public MusicAdapter(Context context, List<Music> musics, ListView listView) {
        this.context=context;
        this.musics=musics;
        this.listView=listView;
        inflater=LayoutInflater.from(context);
        //對workThread進行初始化
        workThread=new Thread(){
            public void run() {
                //不斷輪循任務集合
                while(isLoop){
                    //如果任務集合不是空集  
                    if(!tasks.isEmpty()){
                        //獲取任務對象並且發送請求 
                        ImageLoadTask task = tasks.remove(0);
                        Bitmap bitmap=loadBitmap(task.path);
                        task.bitmap=bitmap;
                        //給相應的ImageView設置Bitmap   handler
                        Message msg=new Message();
                        msg.what=HANDLER_LOAD_IMAGE_SUCCESS;
                        msg.obj=task;
                        handler.sendMessage(msg);
                    }else{
                        synchronized (workThread) {
                            //如果任務集合是空集  wait等待
                            try {
                                workThread.wait();
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }
                    }
                }
            }
        };
        workThread.start();
    }

    /**
     * 通過path  獲取Bitmap
     * @param path
     * @return
     */
    public Bitmap loadBitmap(String path){
        Bitmap bitmap=null;
        String uri=GlobalConsts.BASEURL+path;
        try {
            HttpEntity entity=HttpUtils.send(HttpUtils.METHOD_GET, uri, null);
            byte[] bytes=EntityUtils.toByteArray(entity);
            bitmap=BitmapUtils.loadBitmap(bytes, 50, 50);
            //向緩存集合中存儲緩存圖片
            cache.put(path, new SoftReference<Bitmap>(bitmap));
            //向文件緩存中存儲圖片
            //cacheDir:  /data/data/com.xxx.client/cache/
            //path: images/xxxx.jpg
            File targetFile=new File(context.getCacheDir(), path);
            BitmapUtils.save(targetFile, bitmap);

        } catch (IOException e) {
            e.printStackTrace();
        }
        return bitmap;
    }

    @Override
    public int getCount() {
        return musics.size();
    }

    public Object getItem(int position) {
        return musics.get(position);
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

    public View getView(int position, View convertView, ViewGroup parent) {
        ViewHolder holder=null;
        if(convertView==null){
            convertView=inflater.inflate(R.layout.item_lv_music, null);
            holder=new ViewHolder();
            holder.ivAlbum=(ImageView)convertView.findViewById(R.id.imageView1);
            holder.tvName=(TextView)convertView.findViewById(R.id.tvName);
            holder.tvDuration=(TextView)convertView.findViewById(R.id.tvDuration);
            holder.tvSinger=(TextView)convertView.findViewById(R.id.tvSinger);
            holder.tvAuthor=(TextView)convertView.findViewById(R.id.tvAuthor);
            convertView.setTag(holder);
        }
        holder=(ViewHolder)convertView.getTag();
        //給控件賦值
        Music music=musics.get(position);
        holder.tvName.setText(music.getName());
        holder.tvSinger.setText(music.getSinger());
        holder.tvAuthor.setText(music.getAuthor());
        holder.tvDuration.setText(music.getDurationtime());
        //給當前item中的ImageView設置一個Tag
        //用於圖片下載完成後根據該tag
        //找到相應的ImageView
        holder.ivAlbum.setTag(position);
        Bitmap bitmap=getCacheBitmap(music.getAlbumpic());
        if(bitmap!=null){
            holder.ivAlbum.setImageBitmap(bitmap);
            return convertView;
        }
        //下載一張圖片  
        //向任務隊列中添加一個圖片任務
        ImageLoadTask task=new ImageLoadTask();
        //albumPic:   images/xxxxx.jpg
        task.path=music.getAlbumpic();
        task.position=position;
        tasks.add(task);
        //喚醒工作線程  起來幹活
        notifyWorkThread();
        return convertView;
    }

    private Bitmap getCacheBitmap(String path){
        //查詢緩存中是否有圖片 如果有 則直接獲取
        SoftReference<Bitmap> ref=cache.get(path);
        if(ref!=null && ref.get()!=null){
            Bitmap bitmap=ref.get();
            System.out.println("從緩存中讀取圖片..");
            return bitmap;
        }
        //查詢文件緩存
        File targetFile=new File(context.getCacheDir(), path);
        Bitmap bitmap;
        try {
            bitmap = BitmapUtils.loadBitmap(targetFile.getAbsolutePath());
            //如果文件中查到了bitmap  
            //那麼存入內存緩存
            if(bitmap!=null){
                System.out.println("從文件緩存中讀取圖片..");
                cache.put(path, new SoftReference<Bitmap>(bitmap));
            }
            return bitmap;
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;  
    }

    /**
     * 喚醒工作線程
     */
    public void notifyWorkThread(){
        synchronized (workThread) {
            workThread.notify();
        }
    }


    class ImageLoadTask{
        String path;
        Bitmap bitmap;
        int position;
    }

    class ViewHolder{
        ImageView ivAlbum;
        TextView tvName;
        TextView tvDuration;
        TextView tvSinger;
        TextView tvAuthor;
    }

    public void stopWorkThread() {
        isLoop=false;
        notifyWorkThread();
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章