亚洲免费在线-亚洲免费在线播放-亚洲免费在线观看-亚洲免费在线观看视频-亚洲免费在线看-亚洲免费在线视频

【Android Developers Training】 57. 在UI線程

系統 2451 0

注:本文翻譯自Google官方的Android Developers Training文檔,譯者技術一般,由于喜愛安卓而產生了翻譯的念頭,純屬個人興趣愛好。

原文鏈接: http://developer.android.com/training/displaying-bitmaps/process-bitmap.html


在上節課(博客鏈接: http://www.cnblogs.com/jdneo/p/3514060.html )中所討論的 BitmapFactory.decode* 方法,在數據源是從閃存盤或者網絡(任何非手機存儲的數據來源)讀取的,那么就不能再主UI線程中執行。因為加載這個數據所花費的時間是不可估計的,并且它依賴于虛度因素(從網絡讀取的速度,圖片尺寸,CPU的處理能力,等等)。如果其中一個任務阻塞的UI線程,那么系統將會把你的應用標記為未響應,之后用戶就可以選擇強制關閉它(可以閱讀: Designing for Responsiveness )。

這節課會教你如何在一個后臺線程,使用 AsyncTask 處理圖像,并告訴你如何處理并發問題。


一). 使用一個AsyncTask

AsyncTask 類提供一個簡單地方法在后臺線程執行一些任務,并將結果反饋給UI線程。要使用它,可以創建一個子類,并覆寫一些函數。下面是一個使用 AsyncTask decodeSampledBitmapFromResource() 方法把一個大圖加載到 ImageView 中的例子:

      
        class
      
       BitmapWorkerTask 
      
        extends
      
       AsyncTask<Integer, Void, Bitmap>
      
         {

    
      
      
        private
      
      
        final
      
       WeakReference<ImageView>
      
         imageViewReference;

    
      
      
        private
      
      
        int
      
       data = 0
      
        ;



    
      
      
        public
      
      
         BitmapWorkerTask(ImageView imageView) {

        
      
      
        //
      
      
         Use a WeakReference to ensure the ImageView can be garbage collected
      
      

        imageViewReference = 
      
        new
      
       WeakReference<ImageView>
      
        (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
      
       && bitmap != 
      
        null
      
      
        ) {

            
      
      
        final
      
       ImageView imageView =
      
         imageViewReference.get();

            
      
      
        if
      
       (imageView != 
      
        null
      
      
        ) {

                imageView.setImageBitmap(bitmap);

            }

        }

    }

}
      
    

對于 ImageView 的軟引用( WeakReference )保證了 AsyncTask 不會阻止 ImageView 和任何它引用的對象被垃圾回收器回收。這樣的話,在任務結束后, ImageView 是否仍然存在就沒有保證了,所以你必須在 onPostExecute() 中檢查一下引用是否存在。這個 ImageView 也許已經不存在了,就比如說,用戶轉到了其他的activity,或者一個配置的變更在任務完成之前發生了。

要開始異步地加載這個位圖,簡單地創建一個任務的實例并執行它:

      
        public
      
      
        void
      
       loadBitmap(
      
        int
      
      
         resId, ImageView imageView) {

    BitmapWorkerTask task 
      
      = 
      
        new
      
      
         BitmapWorkerTask(imageView);

    task.execute(resId);

}
      
    

二). 處理并發

當一些普通的View組件,如: ListView GridView 等和 AsyncTask 配合使用時,會引入另一個之前章節講過的問題。為了讓存儲使用更高效,這些組件會在用戶滾動窗口時回收自己的子View。如果沒一個子View都激活一個 AsyncTask ,那么當執行完畢后,相關聯的view是否會因為另一個子view也引用同樣的對象而不被回收,這一方面是沒有保證的。另外,異步任務結束的順序是否和開始的順序保持一致,這一點也未必。

在這篇博客: Multithreading for Performance 中進一步討論了處理并發的問題,并提供了一種解決方案,這個方案能讓 ImageView 存儲一個最新的 AsyncTask 引用,同時在任務執行完畢后可以對其進行檢查。還是像之前章節那樣類似的方法,對 AsyncTask 進行一些擴展。

創建一個專用的 Drawable 子類,用來存儲“WorkerTask”的引用。在這個例子中,一個 BitmapDrawable 被使用到,這樣的話一個“占位符式的”圖片就能在任務完成之前被顯示:

      
        static
      
      
        class
      
       AsyncDrawable 
      
        extends
      
      
         BitmapDrawable {

    
      
      
        private
      
      
        final
      
       WeakReference<BitmapWorkerTask>
      
         bitmapWorkerTaskReference;



    
      
      
        public
      
      
         AsyncDrawable(Resources res, Bitmap bitmap,

            BitmapWorkerTask bitmapWorkerTask) {

        
      
      
        super
      
      
        (res, bitmap);

        bitmapWorkerTaskReference 
      
      =

            
      
        new
      
       WeakReference<BitmapWorkerTask>
      
        (bitmapWorkerTask);

    }



    
      
      
        public
      
      
         BitmapWorkerTask getBitmapWorkerTask() {

        
      
      
        return
      
      
         bitmapWorkerTaskReference.get();

    }

}
      
    

在執行 BitmapWorkerTask 之前,創建一個 AsyncDrawable 并將它和目標 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);

    }

}
      
    

代碼中所引用的這個 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 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

      
        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<Integer, Void, Bitmap>
      
         {

    ...



    @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);

            }

        }

    }

}
      
    

現在這個實現對于 ListView GridView 和其它需要回收子view的組件來說,就變的更加合適了。只需要調用 loadBitmap()就可以對你的 ImageView 設置圖片。例如,在一個 GridView 的實現中,是在其對應適配器的 getView() 方法中執行。

【Android Developers Training】 57. 在UI線程之外處理圖像


更多文章、技術交流、商務合作、聯系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號聯系: 360901061

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對您有幫助就好】

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長會非常 感謝您的哦!!!

發表我的評論
最新評論 總共0條評論
主站蜘蛛池模板: 免费不卡中文字幕在线 | 一本一本久久a久久精品综合麻豆 | 国模和精品嫩模私拍视频 | 欧美综合色 | 日韩天天操| 99精品久久久久中文字幕 | 免费刺激性视频大片区 | 日本夜爽爽一区二区三区 | 色福利网 | 精品无码久久久久久国产 | 国产特黄一级一片免费 | 有码一区| 狠狠操狠狠操狠狠操 | 亚欧精品一区二区三区 | 91亚洲精品国产第一区 | 99热久久国产这里有只有精品 | 99热这里只有精品在线 | 国产精品久久久久蜜芽 | 亚洲欧美精品天堂久久综合一区 | 高清欧美色欧美综合网站 | 亚洲图片 中文字幕 | 91精品国产一区二区三区左线 | 久久精品综合一区二区三区 | 国产成人午夜精品影院游乐网 | 久久午夜激情 | 久久久久久免费观看 | 一级片免费| 国产一区二区三区免费在线观看 | 日韩国产精品欧美一区二区 | 免费永久国产在线视频 | 亚拍精品一区二区三区 | 一品毛片 | 欧美日本激情 | 色综合h| 91在线精品老司机免费播放 | 麻豆精品久久久一区二区 | 亚洲视频网站在线观看 | 爱爱永久免费视频网站 | 久久国产视频一区 | 97视频久久 | 成人97 |