android 下的网络图片加载
2019獨角獸企業重金招聘Python工程師標準>>>
Android圖片的異步加載,主要原理:
加載圖片時先查看緩存中時候存在該圖片,如果存在則返回該圖片,否則先加載載一個默認的占位圖片,同時創建一個通過網絡獲取圖片的任務并添加,任務完成后放松消息給主線程更新界面。
廢話少說,先貼上代碼:
package com.wangge.uumao.http; ?
?
import java.lang.ref.SoftReference; ?
import java.util.ArrayList; ?
import java.util.HashMap; ?
import java.util.List; ?
import java.util.Map; ?
?
import android.graphics.Bitmap; ?
import android.os.Handler; ?
import android.os.Message; ?
import android.util.Log; ?
import android.widget.ImageView; ?
?
import com.wangge.uumao.util.PicUtil; ?
?
public class AsynImageLoader { ?
??? private static final String TAG = "AsynImageLoader"; ?
??? // 緩存下載過的圖片的Map? ?
??? private Map<String, SoftReference<Bitmap>> caches; ?
??? // 任務隊列? ?
??? private List<Task> taskQueue; ?
??? private boolean isRunning = false; ?
???? ?
??? public AsynImageLoader(){ ?
??????? // 初始化變量? ?
??????? caches = new HashMap<String, SoftReference<Bitmap>>(); ?
??????? taskQueue = new ArrayList<AsynImageLoader.Task>(); ?
??????? // 啟動圖片下載線程? ?
??????? isRunning = true; ?
??????? new Thread(runnable).start(); ?
??? } ?
???? ?
??? /**
???? * ?
???? * @param imageView 需要延遲加載圖片的對象
???? * @param url 圖片的URL地址
???? * @param resId 圖片加載過程中顯示的圖片資源
???? */ ?
??? public void showImageAsyn(ImageView imageView, String url, int resId){ ?
??????? imageView.setTag(url); ?
??????? Bitmap bitmap = loadImageAsyn(url, getImageCallback(imageView, resId)); ?
???????? ?
??????? if(bitmap == null){ ?
??????????? imageView.setImageResource(resId); ?
??????? }else{ ?
??????????? imageView.setImageBitmap(bitmap); ?
??????? } ?
??? } ?
???? ?
??? public Bitmap loadImageAsyn(String path, ImageCallback callback){ ?
??????? // 判斷緩存中是否已經存在該圖片? ?
??????? if(caches.containsKey(path)){ ?
??????????? // 取出軟引用? ?
??????????? SoftReference<Bitmap> rf = caches.get(path); ?
??????????? // 通過軟引用,獲取圖片? ?
??????????? Bitmap bitmap = rf.get(); ?
??????????? // 如果該圖片已經被釋放,則將該path對應的鍵從Map中移除掉? ?
??????????? if(bitmap == null){ ?
??????????????? caches.remove(path); ?
??????????? }else{ ?
??????????????? // 如果圖片未被釋放,直接返回該圖片? ?
??????????????? Log.i(TAG, "return image in cache" + path); ?
??????????????? return bitmap; ?
??????????? } ?
??????? }else{ ?
??????????? // 如果緩存中不常在該圖片,則創建圖片下載任務? ?
??????????? Task task = new Task(); ?
??????????? task.path = path; ?
??????????? task.callback = callback; ?
??????????? Log.i(TAG, "new Task ," + path); ?
??????????? if(!taskQueue.contains(task)){ ?
??????????????? taskQueue.add(task); ?
??????????????? // 喚醒任務下載隊列? ?
??????????????? synchronized (runnable) { ?
??????????????????? runnable.notify(); ?
??????????????? } ?
??????????? } ?
??????? } ?
???????? ?
??????? // 緩存中沒有圖片則返回null? ?
??????? return null; ?
??? } ?
???? ?
??? /**
???? * ?
???? * @param imageView ?
???? * @param resId 圖片加載完成前顯示的圖片資源ID
???? * @return
???? */ ?
??? private ImageCallback getImageCallback(final ImageView imageView, final int resId){ ?
??????? return new ImageCallback() { ?
???????????? ?
??????????? @Override ?
??????????? public void loadImage(String path, Bitmap bitmap) { ?
??????????????? if(path.equals(imageView.getTag().toString())){ ?
??????????????????? imageView.setImageBitmap(bitmap); ?
??????????????? }else{ ?
??????????????????? imageView.setImageResource(resId); ?
??????????????? } ?
??????????? } ?
??????? }; ?
??? } ?
???? ?
??? private Handler handler = new Handler(){ ?
?
??????? @Override ?
??????? public void handleMessage(Message msg) { ?
??????????? // 子線程中返回的下載完成的任務? ?
??????????? Task task = (Task)msg.obj; ?
??????????? // 調用callback對象的loadImage方法,并將圖片路徑和圖片回傳給adapter? ?
??????????? task.callback.loadImage(task.path, task.bitmap); ?
??????? } ?
???????? ?
??? }; ?
???? ?
??? private Runnable runnable = new Runnable() { ?
???????? ?
??????? @Override ?
??????? public void run() { ?
??????????? while(isRunning){ ?
??????????????? // 當隊列中還有未處理的任務時,執行下載任務? ?
??????????????? while(taskQueue.size() > 0){ ?
??????????????????? // 獲取第一個任務,并將之從任務隊列中刪除? ?
??????????????????? Task task = taskQueue.remove(0); ?
??????????????????? // 將下載的圖片添加到緩存? ?
??????????????????? task.bitmap = PicUtil.getbitmap(task.path); ?
??????????????????? caches.put(task.path, new SoftReference<Bitmap>(task.bitmap)); ?
??????????????????? if(handler != null){ ?
??????????????????????? // 創建消息對象,并將完成的任務添加到消息對象中? ?
??????????????????????? Message msg = handler.obtainMessage(); ?
??????????????????????? msg.obj = task; ?
??????????????????????? // 發送消息回主線程? ?
??????????????????????? handler.sendMessage(msg); ?
??????????????????? } ?
??????????????? } ?
???????????????? ?
??????????????? //如果隊列為空,則令線程等待? ?
??????????????? synchronized (this) { ?
??????????????????? try { ?
??????????????????????? this.wait(); ?
??????????????????? } catch (InterruptedException e) { ?
??????????????????????? e.printStackTrace(); ?
??????????????????? } ?
??????????????? } ?
??????????? } ?
??????? } ?
??? }; ?
???? ?
??? //回調接口? ?
??? public interface ImageCallback{ ?
??????? void loadImage(String path, Bitmap bitmap); ?
??? } ?
???? ?
??? class Task{ ?
??????? // 下載任務的下載路徑? ?
??????? String path; ?
??????? // 下載的圖片? ?
??????? Bitmap bitmap; ?
??????? // 回調對象? ?
??????? ImageCallback callback; ?
???????? ?
??????? @Override ?
??????? public boolean equals(Object o) { ?
??????????? Task task = (Task)o; ?
??????????? return task.path.equals(path); ?
??????? } ?
??? } ?
}
源代碼的17-24行是一些變量,數組的聲明。
private static final String TAG = "AsynImageLoader"; ?
??? // 緩存下載過的圖片的Map? ?
??? private Map<String, SoftReference<Bitmap>> caches; ?
??? // 任務隊列? ?
??? private List<Task> taskQueue; ?
??? private boolean isRunning = false;
值得一提的是的這里的下載過的圖片的mAp是軟應用了,為什么了。我們查閱資料以后得知:
如果一個對象只具有軟引用,那就類似于可有可物的 生活用品。如果內存空間足夠,垃圾回收器就不會回收它,如果內存空間不足了,就會回收這些對象的內存。只 要垃圾回收器沒有回收它,該對象就可以被程序使用。軟引用可用來實現內存敏感的高速緩存。?軟引用可以和一個引用隊列(ReferenceQueue)聯 合使用,如果軟引用所引用的對象被垃圾回收,Java虛擬機就會把這個軟引用加入到與之關聯的引用隊列中。
?由于圖片是大對象了,確保沒有足夠的緩存以后,java虛擬機能夠將其回收。
代碼的25-33行做了一件事,來初始化變量。
public AsynImageLoader(){ ???????? // 初始化變量? ?
??????? caches = new HashMap<String, SoftReference<Bitmap>>(); ?
??????? taskQueue = new ArrayList<AsynImageLoader.Task>(); ?
??????? // 啟動圖片下載線程? ?
??????? isRunning = true; ?
??????? new Thread(runnable).start(); ?
??? }
并且啟動圖片下載線程。
40行-50行主要是用來啟動異步線程來展示圖片。
public void showImageAsyn(ImageView imageView, String url, int resId){ ?
??????? imageView.setTag(url); ?
??????? Bitmap bitmap = loadImageAsyn(url, getImageCallback(imageView, resId)); ?
???????? ?
??????? if(bitmap == null){ ?
??????????? imageView.setImageResource(resId); ?
??????? }else{ ?
??????????? imageView.setImageBitmap(bitmap); ?
??????? } ?
??? }
這個方法,主要調用了本段源代碼,最核心的方法loadImageAsyn方法。
public Bitmap loadImageAsyn(String path, ImageCallback callback){ ?
??????? // 判斷緩存中是否已經存在該圖片? ?
??????? if(caches.containsKey(path)){ ?
??????????? // 取出軟引用? ?
??????????? SoftReference<Bitmap> rf = caches.get(path); ?
??????????? // 通過軟引用,獲取圖片? ?
??????????? Bitmap bitmap = rf.get(); ?
??????????? // 如果該圖片已經被釋放,則將該path對應的鍵從Map中移除掉? ?
??????????? if(bitmap == null){ ?
??????????????? caches.remove(path); ?
??????????? }else{ ?
??????????????? // 如果圖片未被釋放,直接返回該圖片? ?
??????????????? Log.i(TAG, "return image in cache" + path); ?
??????????????? return bitmap; ?
??????????? } ?
??????? }else{ ?
??????????? // 如果緩存中不常在該圖片,則創建圖片下載任務? ?
??????????? Task task = new Task(); ?
??????????? task.path = path; ?
??????????? task.callback = callback; ?
??????????? Log.i(TAG, "new Task ," + path); ?
??????????? if(!taskQueue.contains(task)){ ?
??????????????? taskQueue.add(task); ?
??????????????? // 喚醒任務下載隊列? ?
??????????????? synchronized (runnable) { ?
??????????????????? runnable.notify(); ?
??????????????? } ?
??????????? } ?
??????? } ?
???????? ?
??????? // 緩存中沒有圖片則返回null? ?
??????? return null; ?
??? }
首先判斷緩存池中是否包含了這個圖片,如果有這個圖片,就從緩存中取得這個圖片,否則的話,就從網絡段來請求。這就是本方法的作用。
而runnable是從網絡直接下載圖片的方法。
private Runnable runnable = new Runnable() { ?118.???????? ?
119.??????? @Override ?
120.??????? public void run() { ?
121.??????????? while(isRunning){ ?
122.??????????????? // 當隊列中還有未處理的任務時,執行下載任務? ?
123.??????????????? while(taskQueue.size() > 0){ ?
124.??????????????????? // 獲取第一個任務,并將之從任務隊列中刪除? ?
125.??????????????????? Task task = taskQueue.remove(0); ?
126.??????????????????? // 將下載的圖片添加到緩存? ?
127.??????????????????? task.bitmap = PicUtil.getbitmap(task.path); ?
128.??????????????????? caches.put(task.path, new SoftReference<Bitmap>(task.bitmap)); ?
129.??????????????????? if(handler != null){ ?
130.??????????????????????? // 創建消息對象,并將完成的任務添加到消息對象中? ?
131.??????????????????????? Message msg = handler.obtainMessage(); ?
132.??????????????????????? msg.obj = task; ?
133.??????????????????????? // 發送消息回主線程? ?
134.??????????????????????? handler.sendMessage(msg); ?
135.??????????????????? } ?
136.??????????????? } ?
137.???????????????? ?
138.??????????????? //如果隊列為空,則令線程等待? ?
139.??????????????? synchronized (this) { ?
140.??????????????????? try { ?
141.??????????????????????? this.wait(); ?
142.??????????????????? } catch (InterruptedException e) { ?
143.??????????????????????? e.printStackTrace(); ?
144.??????????????????? } ?
145.??????????????? } ?
146.??????????? } ?
147.??????? } ?
148.??? };
上述的代碼告訴我們這樣一個意思,通過一個消息的隊列來下載圖片,如果沒有此線程的話,就令線程等待。
這就實現了android異步加載圖片的應用。
轉載于:https://my.oschina.net/u/1182603/blog/174153
總結
以上是生活随笔為你收集整理的android 下的网络图片加载的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: vs2012 智能提示消失解决办法
- 下一篇: 15 个变量和方法命名的最佳实践