Android Load Picture Asynchronously
眾所周知Android應(yīng)用開發(fā)中不能在UI線程中做耗時(shí)的操作,否則就會(huì)彈出煩人的ANR窗口。
應(yīng)用開發(fā)中如果需要加載來自網(wǎng)絡(luò)、磁盤或其他非內(nèi)存中圖片資源時(shí),因加載時(shí)間會(huì)受到其他因素(如磁盤、網(wǎng)絡(luò)、圖片大小、CPU等等)的影響,很容易產(chǎn)生耗時(shí)操作。所以在進(jìn)行類似操作時(shí)要避免在UI線程中進(jìn)行。今天就和大家分享一下如何通過AsyncTask異步加載圖片和怎么處理多線程并發(fā)問題。
如何使用 AsyncTask加載圖片?
通過AysncTask可以很容易的在啟動(dòng)后臺(tái)線程加載資源,然后將結(jié)果返回到UI線程中。使用它時(shí),需要?jiǎng)?chuàng)建它的子類并實(shí)現(xiàn)相應(yīng)的方法,如下是一個(gè)通過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的原因,是為了在內(nèi)存資源緊張時(shí)確保AsyncTask 不會(huì)阻止對(duì)其進(jìn)行資源回收,因此當(dāng)task結(jié)束時(shí)不能保證Imageview還存在,所以你應(yīng)該在onPostExecute中對(duì)它進(jìn)行驗(yàn)證(本例中在Task結(jié)束前如果用戶關(guān)閉Activity,或系統(tǒng)設(shè)置改變時(shí),ImageView可能會(huì)被回收)。
通過以下方式我們就可以異步加載圖片:
| 1 2 3 4 | public void loadBitmap(int resId, ImageView imageView) { ????BitmapWorkerTask task = new BitmapWorkerTask(imageView); ????task.execute(resId); } |
如何處理并發(fā)操作?
常用的View組件中 像ListView、GridView等 為了高效實(shí)用內(nèi)存,用戶在進(jìn)行View滾動(dòng)操作時(shí)系統(tǒng)會(huì)對(duì)不再使用子View進(jìn)行資源回收,,采用上面的方式進(jìn)行圖片加載時(shí)會(huì)引入另外一個(gè)問題。如果在每個(gè)子View中開啟AsyncTask,不能保證在任務(wù)完成時(shí),相關(guān)的View是否已經(jīng)被回收。此外,也不能保證他們加載完成的順序
我們可以通過將AsyncTask的引用保存ImageView關(guān)聯(lián)Drawable中,任務(wù)完成時(shí)檢查引用是否存在.
創(chuàng)建一個(gè)專用的Drawable子類,存儲(chǔ)工作任務(wù)線程的引用。這樣在任務(wù)完成時(shí)即可將圖片設(shè)置在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();} }在執(zhí)行BitmapTask前,你可以創(chuàng)建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判斷是否已經(jīng)存在正在運(yùn)行的任務(wù)綁定在ImageView中,若有,通過執(zhí)行任務(wù)cancel方法取消它,當(dāng)然這種情況不常發(fā)生,
下面是cancelPotentialWork的實(shí)現(xiàn):
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; }下面是一個(gè)輔助方法,通過ImageView查找與其關(guān)聯(lián)的異步任務(wù);
| 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中執(zhí)行更新操作,
首先檢查任務(wù)是否取消,如后更行與其關(guān)聯(lián)的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回收處理的組件中使用,通過調(diào)用
loadBitmap你可以很簡(jiǎn)單的添加圖片到ImageView中,如:在GirdView的 Adapter中的getView方法中調(diào)用。
轉(zhuǎn)載于:https://www.cnblogs.com/qiengo/archive/2012/05/26/2519168.html
《新程序員》:云原生和全面數(shù)字化實(shí)踐50位技術(shù)專家共同創(chuàng)作,文字、視頻、音頻交互閱讀總結(jié)
以上是生活随笔為你收集整理的Android Load Picture Asynchronously的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: [转载]读塔莎奶奶的美好生活
- 下一篇: [zz]用U盘装win7/XP系统的操作