黄色网页视频 I 影音先锋日日狠狠久久 I 秋霞午夜毛片 I 秋霞一二三区 I 国产成人片无码视频 I 国产 精品 自在自线 I av免费观看网站 I 日本精品久久久久中文字幕5 I 91看视频 I 看全色黄大色黄女片18 I 精品不卡一区 I 亚洲最新精品 I 欧美 激情 在线 I 人妻少妇精品久久 I 国产99视频精品免费专区 I 欧美影院 I 欧美精品在欧美一区二区少妇 I av大片网站 I 国产精品黄色片 I 888久久 I 狠狠干最新 I 看看黄色一级片 I 黄色精品久久 I 三级av在线 I 69色综合 I 国产日韩欧美91 I 亚洲精品偷拍 I 激情小说亚洲图片 I 久久国产视频精品 I 国产综合精品一区二区三区 I 色婷婷国产 I 最新成人av在线 I 国产私拍精品 I 日韩成人影音 I 日日夜夜天天综合

【Android Developers Training】 57. 在UI線程

系統(tǒng) 3042 0

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

原文鏈接: 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ī)存儲(chǔ)的數(shù)據(jù)來源)讀取的,那么就不能再主UI線程中執(zhí)行。因?yàn)榧虞d這個(gè)數(shù)據(jù)所花費(fèi)的時(shí)間是不可估計(jì)的,并且它依賴于虛度因素(從網(wǎng)絡(luò)讀取的速度,圖片尺寸,CPU的處理能力,等等)。如果其中一個(gè)任務(wù)阻塞的UI線程,那么系統(tǒng)將會(huì)把你的應(yīng)用標(biāo)記為未響應(yīng),之后用戶就可以選擇強(qiáng)制關(guān)閉它(可以閱讀: Designing for Responsiveness )。

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


一). 使用一個(gè)AsyncTask

AsyncTask 類提供一個(gè)簡單地方法在后臺(tái)線程執(zhí)行一些任務(wù),并將結(jié)果反饋給UI線程。要使用它,可以創(chuàng)建一個(gè)子類,并覆寫一些函數(shù)。下面是一個(gè)使用 AsyncTask decodeSampledBitmapFromResource() 方法把一個(gè)大圖加載到 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);

            }

        }

    }

}
      
    

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

要開始異步地加載這個(gè)位圖,簡單地創(chuàng)建一個(gè)任務(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í),會(huì)引入另一個(gè)之前章節(jié)講過的問題。為了讓存儲(chǔ)使用更高效,這些組件會(huì)在用戶滾動(dòng)窗口時(shí)回收自己的子View。如果沒一個(gè)子View都激活一個(gè) AsyncTask ,那么當(dāng)執(zhí)行完畢后,相關(guān)聯(lián)的view是否會(huì)因?yàn)榱硪粋€(gè)子view也引用同樣的對(duì)象而不被回收,這一方面是沒有保證的。另外,異步任務(wù)結(jié)束的順序是否和開始的順序保持一致,這一點(diǎn)也未必。

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

創(chuàng)建一個(gè)專用的 Drawable 子類,用來存儲(chǔ)“WorkerTask”的引用。在這個(gè)例子中,一個(gè) BitmapDrawable 被使用到,這樣的話一個(gè)“占位符式的”圖片就能在任務(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)建一個(gè) 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);

    }

}
      
    

代碼中所引用的這個(gè) cancelPotentialWork 方法用來檢查是否另一個(gè)正在運(yùn)行的任務(wù)已經(jīng)關(guān)聯(lián)了這個(gè) ImageView 。如果是的話,它嘗試通過調(diào)用 cancel() 方法取消之前的任務(wù)。在一些個(gè)別情況中,新的任務(wù)數(shù)據(jù)會(huì)和已經(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
      
      
        ;

}
      
    

在上述代碼中,一個(gè)輔助的方法, getBitmapWorkerTask(),被用來獲取與任務(wù)相關(guān)聯(lián)的一個(gè)特定 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)在這個(gè)實(shí)現(xiàn)對(duì)于 ListView GridView 和其它需要回收子view的組件來說,就變的更加合適了。只需要調(diào)用 loadBitmap()就可以對(duì)你的 ImageView 設(shè)置圖片。例如,在一個(gè) GridView 的實(shí)現(xiàn)中,是在其對(duì)應(yīng)適配器的 getView() 方法中執(zhí)行。

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


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

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號(hào)聯(lián)系: 360901061

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

【本文對(duì)您有幫助就好】

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

發(fā)表我的評(píng)論
最新評(píng)論 總共0條評(píng)論