新聞中心
BitmapFactory的decode()方法,在Load Large Bitmaps Efficiently要 點中進行討論,不應(yīng)該執(zhí)行在主UI線程如果要讀取源數(shù)據(jù)從磁盤或網(wǎng)絡(luò)位置(或相對內(nèi)存來說任何別的真實來源).該數(shù)據(jù)需要加載的時間是不可預(yù)知的,并取決 于多種因素(從磁盤或網(wǎng)絡(luò)的讀取速度,圖像大小,CPU的功率,等).如果這些任務(wù)阻塞UI線程,系統(tǒng)標(biāo)志您的應(yīng)用程序無響應(yīng),用戶可以選擇關(guān)閉它響應(yīng) (有關(guān)更多信息,請參閱Designing for Responsiveness).

專注于為中小企業(yè)提供成都網(wǎng)站制作、網(wǎng)站設(shè)計服務(wù),電腦端+手機端+微信端的三站合一,更高效的管理,為中小企業(yè)南岔免費做網(wǎng)站提供優(yōu)質(zhì)的服務(wù)。我們立足成都,凝聚了一批互聯(lián)網(wǎng)行業(yè)人才,有力地推動了數(shù)千家企業(yè)的穩(wěn)健成長,幫助中小企業(yè)通過網(wǎng)站建設(shè)實現(xiàn)規(guī)模擴充和轉(zhuǎn)變。
本文將引導(dǎo)您通過在后臺線程中使用AsyncTask處理位圖,并告訴您如何處理并發(fā)問題.
使用一個異步任務(wù)
AsyncTask類提供了一種簡單的方式來在一個后臺線程中執(zhí)行許多任務(wù),并且把結(jié)果反饋給UI線程.使用的方法是,創(chuàng)建一個繼承與它的子類并且實現(xiàn)提供的方法.這里是一個使用AsyncTask和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 collected
- imageViewReference = new WeakReference(imageView);
- }
- // Decode image in background.
- @Override
- protected Bitmap doInBackground(Integer... params) {
- data = params[0];
- return decodeSampledBitmapFromResource(getResources(), data, 100, 100));
- }
- // Once complete, see if ImageView is still around and set bitmap.
- @Override
- protected void onPostExecute(Bitmap bitmap) {
- if (imageViewReference null) {
- final ImageView imageView = imageViewReference.get();
- if (imageView != null) {
- imageView.setImageBitmap(bitmap);
- }
- }
- }
- }
對于ImageView來說WeakReference確保那時AsyncTask并不會阻礙ImageView和任何它的引用被垃圾回收期回收.不能保證ImageView在任務(wù)完成后仍然存在,所以你必須在onPostExecute()方法中檢查它的引用.ImageView可能不再存在,如果例如,如果在任務(wù)完成之前用戶退出了活動或者配置發(fā)生了變化.
為了異步地加載位圖,簡單地創(chuàng)建一個新的任務(wù)并且執(zhí)行它:
- public void loadBitmap(int resId, ImageView imageView) {
- BitmapWorkerTask task = new BitmapWorkerTask(imageView);
- task.execute(resId);
- }
處理并發(fā)
常見的視圖組件例如ListView和GridView如在上一節(jié)中當(dāng)和AsyncTask結(jié)合使用時引出了另外一個問題.為了優(yōu)化內(nèi)存,當(dāng)用戶滾 動時這些組件回收了子視圖.如果每個子視圖觸發(fā)一個AsyncTask,當(dāng)它完成時沒法保證,相關(guān)的視圖還沒有被回收時已經(jīng)用在了別的子視圖當(dāng)中.此外, 還有異步任務(wù)開始的順序是不能保證他們完成的順序.
這篇文章透過Multithreading for Performance功能討論處理并發(fā),并且提供了一個當(dāng)任務(wù)完成后ImageView將一個引用存儲到后面能被檢查的AsyncTask的解決方案. 使用類似的方法,從上一節(jié)的AsyncTask可以擴展到遵循類似的模式.
創(chuàng)建一個專用的Drawable的子類來存儲一個引用備份到工作任務(wù)中.在這種情況下,一個BitmapDrawable被使用以便任務(wù)完成后一個占位符圖像可以顯示在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í)行BitmapWorkerTask前,你創(chuàng)建一個AsyncDrawable,并將其綁定到目標(biāo)ImageView:
- 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);
- }
- }
如果別的正在運行的任務(wù)已經(jīng)和這個ImageView關(guān)聯(lián),cancelPotentialWork引用在上面的代碼示例檢查中.如果這樣,它試圖通過調(diào)用cancel()取消先前的任務(wù).在少數(shù)情況下,新的任務(wù)數(shù)據(jù)匹配現(xiàn)有的任務(wù),而且并不需要做什么.下面是實現(xiàn) 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 task
- bitmapWorkerTask.cancel(true);
- } else {
- // The same work is already in progress
- return false;
- }
- }
- // No task associated with the ImageView, or an existing task was cancelled
- return true;
- }
一個幫助方法,getBitmapWorkerTask(),使用以上來檢索一個和特定ImageView相關(guān)的任務(wù):
- 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()方法,以便任務(wù)取消時并且當(dāng)前任務(wù)和這個ImageView關(guān)聯(lián)時進行檢查:
- class BitmapWorkerTask extends AsyncTask {
- ...
- @Override
- protected 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);
- }
- }
- }
- }
現(xiàn)在這個實現(xiàn)適合使用ListView和GridView控 件組件以及回收其子視圖的任何其他組件.在你正常地給你的ImageView控件設(shè)置圖片時簡單地調(diào)用loadBitmap就行了.例如,在一個 GridView中實現(xiàn)的方式是在支持的適配中的[android.view.View, android.view.ViewGroup) getView()](http://docs.eoeandroid.com/reference/android/widget /Adapter.html#getView(int,)方法中.
新聞標(biāo)題:處理來自UI線程的位圖
分享網(wǎng)址:http://m.fisionsoft.com.cn/article/ccohgjs.html


咨詢
建站咨詢
