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

【Android Developers Training】 59. 管理圖片

系統(tǒng) 2952 0

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

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


接著上一節(jié)課的步伐,還有很多特定的事情可以讓垃圾回收和位圖重用變得容易。根據(jù)你的目標(biāo)Android系統(tǒng)的不同版本,推薦的策略也會(huì)有所不同。這系列課程的樣例代碼: BitmapFun (鏈接: http://www.cnblogs.com/jdneo/p/3512517.html )向你展示了你的應(yīng)用如何在不同的Android版本間有效率地工作。

在開始這堂課之前,我們先來看一下Android對(duì)于位圖存儲(chǔ)管理的演變:

  • 在Android 2.2(API Level 8)之前,當(dāng)垃圾回收發(fā)生時(shí),你應(yīng)用的線程會(huì)停止。由此導(dǎo)致的延遲會(huì)降低應(yīng)用的性能表現(xiàn)。 在Android 2.3開始加入了并發(fā)式的垃圾回收,這意味著當(dāng)一個(gè)位圖不再被引用時(shí),對(duì)應(yīng)的內(nèi)存會(huì)被迅速回收
  • 在Android 2.3.3(API Level 10)之前,一副位圖的依托像素?cái)?shù)據(jù)(backing pixel data)存儲(chǔ)于本機(jī)內(nèi)存中。它和位圖本身是分離開的,位圖存儲(chǔ)于 Dalvik堆中。本機(jī)內(nèi)存中的像素?cái)?shù)據(jù)并不會(huì)以一種可預(yù)測的形式進(jìn)行釋放,因此可能會(huì)導(dǎo)致一個(gè)應(yīng)用超過它的內(nèi)存限制而崩潰。 從Android 3.0(API Level 11)開始,像素?cái)?shù)據(jù)和與其關(guān)聯(lián)的位圖都存儲(chǔ)于Dalvik堆中了

下面的章節(jié)將會(huì)描述如何對(duì)不同的Android版本,優(yōu)化位圖存儲(chǔ)管理。


一). 在Android 2.3.3及之前的系統(tǒng)版本上管理內(nèi)存

在Android 2.3.3(API Level 10)及以前,推薦使用 recycle() 。如果你在你的應(yīng)用中要顯示大量的位圖數(shù)據(jù),你極有可能引起 OutOfMemoryError 錯(cuò)誤。 recycle() 可以讓應(yīng)用盡快地釋放內(nèi)存。

Caution:

只有當(dāng)你確定對(duì)應(yīng)的位圖將不再被使用的情況下,你才應(yīng)該使用 recycle() 。如果你使用了 recycle() ,并在之后嘗試?yán)L制該位圖,那么你將會(huì)得到這樣的錯(cuò)誤提示:“ Canvas: trying to use a recycled bitmap.

下面的代碼是調(diào)用 recycle() 的樣例。它使用引用計(jì)數(shù)(變量“ mDisplayRefCount ”以及“ mCacheRefCount ”)來追蹤位圖是否是當(dāng)前正在顯示或是在緩存中。當(dāng)下列情況發(fā)生時(shí),代碼會(huì)回收位圖:

  • mDisplayRefCount ”以及“ mCacheRefCount ”的引用計(jì)數(shù)都為0。
  • 位圖不是“ null ”,同時(shí)它還未被回收。
      
        private
      
      
        int
      
       mCacheRefCount = 0
      
        ;


      
      
        private
      
      
        int
      
       mDisplayRefCount = 0
      
        ;

...


      
      
        //
      
      
         Notify the drawable that the displayed state has changed.


      
      
        //
      
      
         Keep a count to determine when the drawable is no longer displayed.
      
      
        public
      
      
        void
      
       setIsDisplayed(
      
        boolean
      
      
         isDisplayed) {

    
      
      
        synchronized
      
       (
      
        this
      
      
        ) {

        
      
      
        if
      
      
         (isDisplayed) {

            mDisplayRefCount
      
      ++
      
        ;

            mHasBeenDisplayed 
      
      = 
      
        true
      
      
        ;

        } 
      
      
        else
      
      
         {

            mDisplayRefCount
      
      --
      
        ;

        }

    }

    
      
      
        //
      
      
         Check to see if recycle() can be called.
      
      
            checkState();

}




      
      
        //
      
      
         Notify the drawable that the cache state has changed.


      
      
        //
      
      
         Keep a count to determine when the drawable is no longer being cached.
      
      
        public
      
      
        void
      
       setIsCached(
      
        boolean
      
      
         isCached) {

    
      
      
        synchronized
      
       (
      
        this
      
      
        ) {

        
      
      
        if
      
      
         (isCached) {

            mCacheRefCount
      
      ++
      
        ;

        } 
      
      
        else
      
      
         {

            mCacheRefCount
      
      --
      
        ;

        }

    }

    
      
      
        //
      
      
         Check to see if recycle() can be called.
      
      
            checkState();

}




      
      
        private
      
      
        synchronized
      
      
        void
      
      
         checkState() {

    
      
      
        //
      
      
         If the drawable cache and display ref counts = 0, and this drawable

    
      
      
        //
      
      
         has been displayed, then recycle.
      
      
        if
      
       (mCacheRefCount <= 0 && mDisplayRefCount <= 0 &&
      
         mHasBeenDisplayed

            
      
      &&
      
         hasValidBitmap()) {

        getBitmap().recycle();

    }

}




      
      
        private
      
      
        synchronized
      
      
        boolean
      
      
         hasValidBitmap() {

    Bitmap bitmap 
      
      =
      
         getBitmap();

    
      
      
        return
      
       bitmap != 
      
        null
      
       && !
      
        bitmap.isRecycled();

}
      
    

二).?在Android 3.0及以后的系統(tǒng)版本上管理內(nèi)存

Android 3.0(API Level 11)引入了 BitmapFactory.Options.inBitmap 域。如果配置了該選項(xiàng),接受該 Options 對(duì)象的解碼方法會(huì)在加載內(nèi)容時(shí)嘗試去重用已經(jīng)存在的位圖。這意味著位圖內(nèi)存被重用了,從而提高了性能表現(xiàn),同時(shí)免去了內(nèi)存分配和回收的工作。然而,對(duì)于如何使用 inBitmap 會(huì)有一些限制。特別地,在Android 4.4(API Level 19)之前,只有尺寸吻合的位圖才被支持。更多詳細(xì)信息,可以閱讀: inBitmap

保存一幅位圖以備將來使用

下面的代碼樣例展示了在相同的應(yīng)用中,一個(gè)已經(jīng)存在的位圖是如何為了將來可能被再次使用到而保存的。當(dāng)一個(gè)應(yīng)用在Android 3.0及以上的設(shè)備上運(yùn)行,且一個(gè)位圖從 LruCache 中移除,該位圖的軟引用會(huì)放置在一個(gè) HashSet 中,以備之后 inBitmap 使用:

      Set<SoftReference<Bitmap>>
      
         mReusableBitmaps;


      
      
        private
      
       LruCache<String, BitmapDrawable>
      
         mMemoryCache;




      
      
        //
      
      
         If you're running on Honeycomb or newer, create a


      
      
        //
      
      
         synchronized HashSet of references to reusable bitmaps.
      
      
        if
      
      
         (Utils.hasHoneycomb()) {

    mReusableBitmaps 
      
      =
      
        

            Collections.synchronizedSet(
      
      
        new
      
       HashSet<SoftReference<Bitmap>>
      
        ());

}



mMemoryCache 
      
      = 
      
        new
      
       LruCache<String, BitmapDrawable>
      
        (mCacheParams.memCacheSize) {



    
      
      
        //
      
      
         Notify the removed entry that is no longer being cached.
      
      
            @Override

    
      
      
        protected
      
      
        void
      
       entryRemoved(
      
        boolean
      
      
         evicted, String key,

            BitmapDrawable oldValue, BitmapDrawable newValue) {

        
      
      
        if
      
       (RecyclingBitmapDrawable.
      
        class
      
      
        .isInstance(oldValue)) {

            
      
      
        //
      
      
         The removed entry is a recycling drawable, so notify it

            
      
      
        //
      
      
         that it has been removed from the memory cache.
      
      

            ((RecyclingBitmapDrawable) oldValue).setIsCached(
      
        false
      
      
        );

        } 
      
      
        else
      
      
         {

            
      
      
        //
      
      
         The removed entry is a standard BitmapDrawable.
      
      
        if
      
      
         (Utils.hasHoneycomb()) {

                
      
      
        //
      
      
         We're running on Honeycomb or later, so add the bitmap

                
      
      
        //
      
      
         to a SoftReference set for possible use with inBitmap later.
      
      
                        mReusableBitmaps.add

                        (
      
      
        new
      
       SoftReference<Bitmap>
      
        (oldValue.getBitmap()));

            }

        }

    }

....

}
      
    

使用一個(gè)存在的位圖

在運(yùn)行的程序中,解碼方法檢查是否有可用的位圖。例如:

      
        public
      
      
        static
      
      
         Bitmap decodeSampledBitmapFromFile(String filename,

        
      
      
        int
      
       reqWidth, 
      
        int
      
      
         reqHeight, ImageCache cache) {



    
      
      
        final
      
       BitmapFactory.Options options = 
      
        new
      
      
         BitmapFactory.Options();

    ...

    BitmapFactory.decodeFile(filename, options);

    ...



    
      
      
        //
      
      
         If we're running on Honeycomb or newer, try to use inBitmap.
      
      
        if
      
      
         (Utils.hasHoneycomb()) {

        addInBitmapOptions(options, cache);

    }

    ...

    
      
      
        return
      
      
         BitmapFactory.decodeFile(filename, options);

}
      
    

下面的代碼是上述代碼中 addInBitmapOptions() 方法的實(shí)現(xiàn)。它尋找一個(gè)存在的位圖,并將它作為 inBitmap 的值。注意,該方法僅僅在它找到了一個(gè)合適的匹配時(shí),才將位圖設(shè)置為 inBitmap 的值(你的代碼不可以假定這個(gè)匹配一定能找到):

      
        private
      
      
        static
      
      
        void
      
      
         addInBitmapOptions(BitmapFactory.Options options,

        ImageCache cache) {

    
      
      
        //
      
      
         inBitmap only works with mutable bitmaps, so force the decoder to

    
      
      
        //
      
      
         return mutable bitmaps.
      
      

    options.inMutable = 
      
        true
      
      
        ;



    
      
      
        if
      
       (cache != 
      
        null
      
      
        ) {

        
      
      
        //
      
      
         Try to find a bitmap to use for inBitmap.
      
      

        Bitmap inBitmap =
      
         cache.getBitmapFromReusableSet(options);



        
      
      
        if
      
       (inBitmap != 
      
        null
      
      
        ) {

            
      
      
        //
      
      
         If a suitable bitmap has been found, set it as the value of

            
      
      
        //
      
      
         inBitmap.
      
      

            options.inBitmap =
      
         inBitmap;

        }

    }

}




      
      
        //
      
      
         This method iterates through the reusable bitmaps, looking for one 


      
      
        //
      
      
         to use for inBitmap:
      
      
        protected
      
      
         Bitmap getBitmapFromReusableSet(BitmapFactory.Options options) {

        Bitmap bitmap 
      
      = 
      
        null
      
      
        ;



    
      
      
        if
      
       (mReusableBitmaps != 
      
        null
      
       && !
      
        mReusableBitmaps.isEmpty()) {

        
      
      
        synchronized
      
      
         (mReusableBitmaps) {

            
      
      
        final
      
       Iterator<SoftReference<Bitmap>>
      
         iterator

                    
      
      =
      
         mReusableBitmaps.iterator();

            Bitmap item;



            
      
      
        while
      
      
         (iterator.hasNext()) {

                item 
      
      =
      
         iterator.next().get();



                
      
      
        if
      
       (
      
        null
      
       != item &&
      
         item.isMutable()) {

                    
      
      
        //
      
      
         Check to see it the item can be used for inBitmap.
      
      
        if
      
      
         (canUseForInBitmap(item, options)) {

                        bitmap 
      
      =
      
         item;



                        
      
      
        //
      
      
         Remove from reusable set so it can't be used again.
      
      
                                iterator.remove();

                        
      
      
        break
      
      
        ;

                    }

                } 
      
      
        else
      
      
         {

                    
      
      
        //
      
      
         Remove from the set if the reference has been cleared.
      
      
                            iterator.remove();

                }

            }

        }

    }

    
      
      
        return
      
      
         bitmap;

}
      
    

最后,此方法決定備選的位圖是否符合 inBitmap 的尺寸標(biāo)準(zhǔn):

      
        static
      
      
        boolean
      
      
         canUseForInBitmap(

        Bitmap candidate, BitmapFactory.Options targetOptions) {



    
      
      
        if
      
       (Build.VERSION.SDK_INT >=
      
         Build.VERSION_CODES.KITKAT) {

        
      
      
        //
      
      
         From Android 4.4 (KitKat) onward we can re-use if the byte size of

        
      
      
        //
      
      
         the new bitmap is smaller than the reusable bitmap candidate

        
      
      
        //
      
      
         allocation byte count.
      
      
        int
      
       width = targetOptions.outWidth /
      
         targetOptions.inSampleSize;

        
      
      
        int
      
       height = targetOptions.outHeight /
      
         targetOptions.inSampleSize;

        
      
      
        int
      
       byteCount = width * height *
      
         getBytesPerPixel(candidate.getConfig());

        
      
      
        return
      
       byteCount <=
      
         candidate.getAllocationByteCount();

    }



    
      
      
        //
      
      
         On earlier versions, the dimensions must match exactly and the inSampleSize must be 1
      
      
        return
      
       candidate.getWidth() ==
      
         targetOptions.outWidth

            
      
      && candidate.getHeight() ==
      
         targetOptions.outHeight

            
      
      && targetOptions.inSampleSize == 1
      
        ;

}




      
      
        /**
      
      
        

 * A helper function to return the byte usage per pixel of a bitmap based on its configuration.

 
      
      
        */
      
      
        static
      
      
        int
      
      
         getBytesPerPixel(Config config) {

    
      
      
        if
      
       (config ==
      
         Config.ARGB_8888) {

        
      
      
        return
      
       4
      
        ;

    } 
      
      
        else
      
      
        if
      
       (config ==
      
         Config.RGB_565) {

        
      
      
        return
      
       2
      
        ;

    } 
      
      
        else
      
      
        if
      
       (config ==
      
         Config.ARGB_4444) {

        
      
      
        return
      
       2
      
        ;

    } 
      
      
        else
      
      
        if
      
       (config ==
      
         Config.ALPHA_8) {

        
      
      
        return
      
       1
      
        ;

    }

    
      
      
        return
      
       1
      
        ;

}
      
    

【Android Developers Training】 59. 管理圖片存儲(chǔ)


更多文章、技術(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)論
主站蜘蛛池模板: 吉木乃县| 衡阳县| 阆中市| 元氏县| 荣昌县| 平湖市| 建瓯市| 合山市| 平顶山市| 武冈市| 汉沽区| 中卫市| 丹江口市| 台州市| 长武县| 郓城县| 云林县| 琼海市| 高碑店市| 驻马店市| 武强县| 新晃| 泾阳县| 英山县| 井冈山市| 邹平县| 盐池县| 包头市| 新化县| 滦平县| 湖口县| 泸州市| 西青区| 长岭县| 涪陵区| 会泽县| 三亚市| 沙坪坝区| 明溪县| 密山市| 迭部县|