日韩久久久精品,亚洲精品久久久久久久久久久,亚洲欧美一区二区三区国产精品 ,一区二区福利

【Android Developers Training】 57. 在UI線程

系統(tǒng) 2642 0

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

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


在上節(jié)課(博客鏈接: http://www.cnblogs.com/jdneo/p/3514060.html )中所討論的 BitmapFactory.decode* 方法,在數(shù)據(jù)源是從閃存盤或者網(wǎng)絡(luò)(任何非手機(jī)存儲的數(shù)據(jù)來源)讀取的,那么就不能再主UI線程中執(zhí)行。因?yàn)榧虞d這個數(shù)據(jù)所花費(fèi)的時(shí)間是不可估計(jì)的,并且它依賴于虛度因素(從網(wǎng)絡(luò)讀取的速度,圖片尺寸,CPU的處理能力,等等)。如果其中一個任務(wù)阻塞的UI線程,那么系統(tǒng)將會把你的應(yīng)用標(biāo)記為未響應(yīng),之后用戶就可以選擇強(qiáng)制關(guān)閉它(可以閱讀: Designing for Responsiveness )。

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


一). 使用一個AsyncTask

AsyncTask 類提供一個簡單地方法在后臺線程執(zhí)行一些任務(wù),并將結(jié)果反饋給UI線程。要使用它,可以創(chuàng)建一個子類,并覆寫一些函數(shù)。下面是一個使用 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 和任何它引用的對象被垃圾回收器回收。這樣的話,在任務(wù)結(jié)束后, ImageView 是否仍然存在就沒有保證了,所以你必須在 onPostExecute() 中檢查一下引用是否存在。這個 ImageView 也許已經(jīng)不存在了,就比如說,用戶轉(zhuǎn)到了其他的activity,或者一個配置的變更在任務(wù)完成之前發(fā)生了。

要開始異步地加載這個位圖,簡單地創(chuàng)建一個任務(wù)的實(shí)例并執(zhí)行它:

      
        public
      
      
        void
      
       loadBitmap(
      
        int
      
      
         resId, ImageView imageView) {

    BitmapWorkerTask task 
      
      = 
      
        new
      
      
         BitmapWorkerTask(imageView);

    task.execute(resId);

}
      
    

二). 處理并發(fā)

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

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

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

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

    }

}
      
    

在執(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);

    }

}
      
    

代碼中所引用的這個 cancelPotentialWork 方法用來檢查是否另一個正在運(yùn)行的任務(wù)已經(jīng)關(guān)聯(lián)了這個 ImageView 。如果是的話,它嘗試通過調(diào)用 cancel() 方法取消之前的任務(wù)。在一些個別情況中,新的任務(wù)數(shù)據(jù)會和已經(jīng)存在的任務(wù)相符合,那么就沒有其他的事情取藥發(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 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(),被用來獲取與任務(wù)相關(guān)聯(lián)的一個特定 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()方法,這樣它就能檢查任務(wù)是否取消了以及當(dāng)前的任務(wù)是否和 ImageView 所關(guān)聯(lián)的數(shù)據(jù)相匹配:

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

            }

        }

    }

}
      
    

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

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


更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號聯(lián)系: 360901061

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

【本文對您有幫助就好】

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

發(fā)表我的評論
最新評論 總共0條評論
主站蜘蛛池模板: 西宁市| 盐池县| 邵阳市| 翁牛特旗| 兴城市| 当雄县| 鄯善县| 广州市| 德州市| 丰城市| 贡觉县| 汝州市| 耿马| 莱芜市| 大埔区| 肇庆市| 金山区| 繁昌县| 长顺县| 手游| 松原市| 安丘市| 临澧县| 澄江县| 宝山区| 莱芜市| 兰西县| 友谊县| 临江市| 永泰县| 新巴尔虎左旗| 杭锦旗| 乐亭县| 卓尼县| 监利县| 方城县| 永善县| 丰县| 宜州市| 原平市| 泌阳县|