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

【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條評論
主站蜘蛛池模板: 久草在线观看资源 | 久艹伊人 | 曰本一级毛片 | 91视频成人| 久射网 | 成人伊人| 欧美日本三级 | 久久精品影院永久网址 | 美女撒尿毛片免费看 | 最新狠狠色狠狠色综合 | 久久精品男人影院 | 久久国产区 | 国产欧美日韩精品综合 | 精品福利一区二区三区免费视频 | 很很鲁在线视频播放影院 | 性一交一乱一视频免费看 | 福利午夜国产网站在线不卡 | 欧美一区二区在线免费观看 | 国产精品久久久久天天影视 | 国产一区二区三区视频在线观看 | 久久精品a一国产成人免费网站 | 曰鲁夜鲁鲁狠狠综合 | 色黄网站成年女人色毛片 | 妞干网中文字幕 | 高清国产精品入口麻豆 | 日日日日干 | 国产主播第一页 | 日本一级片免费观看 | 久热精品香蕉在线视频 | 国产成人精品一区二区免费 | 日本成人tv| 97人人澡 | 国产日韩欧美自拍 | 日韩一中文字幕 | 亚洲日本在线播放 | 婷婷四房色播 | 国产精品爱久久久久久久9999 | 欧美xxxxx九色视频免费观看 | se在线观看| 毛片推荐 | 国产成人精品男人的天堂网站 |