Android Load Picture Asynchronously
眾所周知Android應用開發中不能在UI線程中做耗時的操作,否則就會彈出煩人的ANR窗口。
應用開發中如果需要加載來自網絡、磁盤或其他非內存中圖片資源時,因加載時間會受到其他因素(如磁盤、網絡、圖片大小、CPU等等)的影響,很容易產生耗時操作。所以在進行類似操作時要避免在UI線程中進行。今天就和大家分享一下如何通過AsyncTask異步加載圖片和怎么處理多線程并發問題。
如何使用 AsyncTask加載圖片?
通過AysncTask可以很容易的在啟動后臺線程加載資源,然后將結果返回到UI線程中。使用它時,需要創建它的子類并實現相應的方法,如下是一個通過AysncTask和decodeSampledBitmapFromResource()方法加載一張大圖片到ImageView中的例子:
class BitmapWorkerTask extends AsyncTask {private final WeakReference imageViewReference;private int data = 0;public BitmapWorkerTask(ImageView imageView) {// Use a WeakReference to ensure the ImageView can be garbage collectedimageViewReference = new WeakReference(imageView);}// Decode image in background. @Overrideprotected Bitmap doInBackground(Integer... params) {data = params[0];return decodeSampledBitmapFromResource(getResources(), data, 100, 100));}// Once complete, see if ImageView is still around and set bitmap. @Overrideprotected void onPostExecute(Bitmap bitmap) {if (imageViewReference != null && bitmap != null) {final ImageView imageView = imageViewReference.get();if (imageView != null) {imageView.setImageBitmap(bitmap);}}} }使用WeakReference 保存ImageView的原因,是為了在內存資源緊張時確保AsyncTask 不會阻止對其進行資源回收,因此當task結束時不能保證Imageview還存在,所以你應該在onPostExecute中對它進行驗證(本例中在Task結束前如果用戶關閉Activity,或系統設置改變時,ImageView可能會被回收)。
通過以下方式我們就可以異步加載圖片:
| 1 2 3 4 | public void loadBitmap(int resId, ImageView imageView) { ????BitmapWorkerTask task = new BitmapWorkerTask(imageView); ????task.execute(resId); } |
如何處理并發操作?
常用的View組件中 像ListView、GridView等 為了高效實用內存,用戶在進行View滾動操作時系統會對不再使用子View進行資源回收,,采用上面的方式進行圖片加載時會引入另外一個問題。如果在每個子View中開啟AsyncTask,不能保證在任務完成時,相關的View是否已經被回收。此外,也不能保證他們加載完成的順序
我們可以通過將AsyncTask的引用保存ImageView關聯Drawable中,任務完成時檢查引用是否存在.
創建一個專用的Drawable子類,存儲工作任務線程的引用。這樣在任務完成時即可將圖片設置在ImageView中
static class AsyncDrawable extends BitmapDrawable {private final WeakReference bitmapWorkerTaskReference;public AsyncDrawable(Resources res, Bitmap bitmap,BitmapWorkerTask bitmapWorkerTask) {super(res, bitmap);bitmapWorkerTaskReference =new WeakReference(bitmapWorkerTask);}public BitmapWorkerTask getBitmapWorkerTask() {return bitmapWorkerTaskReference.get();} }在執行BitmapTask前,你可以創建AsyncDrawable并將其綁定到ImageView中
| 1 2 3 4 5 6 7 8 9 | public void loadBitmap(int resId, ImageView imageView) { ????if (cancelPotentialWork(resId, imageView)) { ????????final BitmapWorkerTask task = new BitmapWorkerTask(imageView); ????????final AsyncDrawable asyncDrawable = ????????????????new AsyncDrawable(getResources(), mPlaceHolderBitmap, task); ????????imageView.setImageDrawable(asyncDrawable); ????????task.execute(resId); ????} } |
?
上面代碼中通過cancelPotentialWork判斷是否已經存在正在運行的任務綁定在ImageView中,若有,通過執行任務cancel方法取消它,當然這種情況不常發生,
下面是cancelPotentialWork的實現:
public static boolean cancelPotentialWork(int data, ImageView imageView) {final BitmapWorkerTask bitmapWorkerTask = getBitmapWorkerTask(imageView);if (bitmapWorkerTask != null) {final int bitmapData = bitmapWorkerTask.data;if (bitmapData != data) {// Cancel previous taskbitmapWorkerTask.cancel(true);} else {// The same work is already in progressreturn false;}}// No task associated with the ImageView, or an existing task was cancelledreturn true; }下面是一個輔助方法,通過ImageView查找與其關聯的異步任務;
| 1 2 3 4 5 6 7 8 9 10 | private static BitmapWorkerTask getBitmapWorkerTask(ImageView imageView) { ???if (imageView != null) { ???????final Drawable drawable = imageView.getDrawable(); ???????if (drawable instanceof AsyncDrawable) { ???????????final AsyncDrawable asyncDrawable = (AsyncDrawable) drawable; ???????????return asyncDrawable.getBitmapWorkerTask(); ???????} ????} ????return null; } |
?
下一步需要在BitmapWorkerTask中的onPostExecute中執行更新操作,
首先檢查任務是否取消,如后更行與其關聯的ImageView:
class BitmapWorkerTask extends AsyncTask {... @Overrideprotected void onPostExecute(Bitmap bitmap) {if (isCancelled()) {bitmap = null;}if (imageViewReference != null && bitmap != null) {final ImageView imageView = imageViewReference.get();final BitmapWorkerTask bitmapWorkerTask =getBitmapWorkerTask(imageView);if (this == bitmapWorkerTask && imageView != null) {imageView.setImageBitmap(bitmap);}}} }通過以上方法,你就可以在ListView、GridView或者其他具有子view回收處理的組件中使用,通過調用
loadBitmap你可以很簡單的添加圖片到ImageView中,如:在GirdView的 Adapter中的getView方法中調用。
轉載于:https://www.cnblogs.com/qiengo/archive/2012/05/26/2519168.html
《新程序員》:云原生和全面數字化實踐50位技術專家共同創作,文字、視頻、音頻交互閱讀總結
以上是生活随笔為你收集整理的Android Load Picture Asynchronously的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: [转载]读塔莎奶奶的美好生活
- 下一篇: [zz]用U盘装win7/XP系统的操作