欧美三区_成人在线免费观看视频_欧美极品少妇xxxxⅹ免费视频_a级毛片免费播放_鲁一鲁中文字幕久久_亚洲一级特黄

【Android Developers Training】 57. 在UI線程

系統 2539 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條評論
主站蜘蛛池模板: 国产东北普通话对白 | 午夜家庭影院 | 欧美午夜免费观看福利片 | 日本高清一级片 | 成人黄色短视频在线观看 | 99热久久这里只有精品6国产网 | 久久国产精品免费一区二区三区 | 国产高清视频一区二区 | 久久这里只有精品9 | 波多野结衣的一级片 | 极品嫩模私拍后被潜在线观看 | 性夜影院爽黄e爽痛轻点www | 精品亚洲综合在线第一区 | 国产精品久久国产精品 | 国产亚洲综合一区二区在线 | 香港三级午夜理伦三级 | 18pao成人国产永久视频 | 亚洲精品www | 六月婷婷在线 | 天天操天天插 | 中文字幕免费 | 国产手机在线αⅴ片无码观看 | 亚洲播播播 | 91网视频在线观看 | a级毛片观看 | 久久精品视频大全 | 日本黄大片视频在线播放 | 欧美一区二区三区国产精品 | 91丁香亚洲综合社区 | 摸金校尉之九幽将军 | 2017av伦理片| 综合久久久久综合 | 电家庭影院午夜 | 久爱www成人网免费视频 | 欧美系列第一页 | 精品国产一区二区三区久久 | 黄色影视大全 | 五月天综合在线 | 国产成人在线观看免费网站 | 91视频在线 | 夜精品A片观看无码一区二区 |