真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

Bitmap知識點(diǎn)有哪些

本篇內(nèi)容主要講解“Bitmap知識點(diǎn)有哪些”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實(shí)用性強(qiáng)。下面就讓小編來帶大家學(xué)習(xí)“Bitmap知識點(diǎn)有哪些”吧!

公司主營業(yè)務(wù):成都做網(wǎng)站、網(wǎng)站制作、移動網(wǎng)站開發(fā)等業(yè)務(wù)。幫助企業(yè)客戶真正實(shí)現(xiàn)互聯(lián)網(wǎng)宣傳,提高企業(yè)的競爭能力。創(chuàng)新互聯(lián)建站是一支青春激揚(yáng)、勤奮敬業(yè)、活力青春激揚(yáng)、勤奮敬業(yè)、活力澎湃、和諧高效的團(tuán)隊(duì)。公司秉承以“開放、自由、嚴(yán)謹(jǐn)、自律”為核心的企業(yè)文化,感謝他們對我們的高要求,感謝他們從不同領(lǐng)域給我們帶來的挑戰(zhàn),讓我們激情的團(tuán)隊(duì)有機(jī)會用頭腦與智慧不斷的給客戶帶來驚喜。創(chuàng)新互聯(lián)建站推出石阡免費(fèi)做網(wǎng)站回饋大家。

Bitmap是什么,怎么存儲圖片。

Bitmap,位圖,本質(zhì)上是一張圖片的內(nèi)容在內(nèi)存中的表達(dá)形式。它將圖片的內(nèi)容看做是由存儲數(shù)據(jù)的有限個(gè)像素點(diǎn)組成;每個(gè)像素點(diǎn)存儲該像素點(diǎn)位置的ARGB值,每個(gè)像素點(diǎn)的ARGB值確定下來,這張圖片的內(nèi)容就相應(yīng)地確定下來。其中,A代表透明度,RGB代表紅綠藍(lán)三種顏色通道值。

Bitmap內(nèi)存如何計(jì)算

Bitmap一直都是Android中的內(nèi)存大戶,計(jì)算大小的方式有三種:

  • getRowBytes() 這個(gè)在 API Level 1添加的,返回的是bitmap一行所占的大小,需要乘以bitmap的高,才能得出btimap的大小

  • getByteCount() 這個(gè)是在 API Level 12添加的,其實(shí)是對getRowBytes()乘以高的封裝

  • getAllocationByteCount() 這個(gè)是在 API Level 19添加的

這里我將一張圖片放到項(xiàng)目的drawable-xxhdpi文件夾中,然后通過方法獲取圖片所占的內(nèi)存大小:

    var bitmap = BitmapFactory.decodeResource(resources, R.drawable.test)
    img.setImageBitmap(bitmap)
        
    Log.e(TAG,"dpi = ${resources.displayMetrics.densityDpi}")
    Log.e(TAG,"size = ${bitmap.allocationByteCount}")

打印出來的結(jié)果是

size=1960000

具體是怎么計(jì)算的呢?

圖片內(nèi)存=寬 * 高 * 每個(gè)像素所占字節(jié)。

這個(gè)像素所占字節(jié)又和Bitmap.Config有關(guān),Bitmap.Config是個(gè)枚舉類,用于描述每個(gè)像素點(diǎn)的信息,比如:

  • ARGB_8888。常用類型,總共32位,4個(gè)字節(jié),分別表示透明度和RGB通道。

  • RGB_565。16位,2個(gè)字節(jié),只能描述RGB通道。

所以我們這里的圖片內(nèi)存計(jì)算就得出:

寬700 * 高700 * 每個(gè)像素4字節(jié)=1960000

Bitmap內(nèi)存 和drawable目錄的關(guān)系

首先放一張drawable目錄對應(yīng)的屏幕密度對照表,來自郭霖的博客:

Bitmap知識點(diǎn)有哪些

對照表

剛才的案例,我們是把圖片放到drawable-xxhdpi文件夾,而drawable-xxhdpi文件夾對應(yīng)的dpi就是我們測試手機(jī)的dpi—480。所以圖片的內(nèi)存就是我們所計(jì)算的寬 * 高 * 每個(gè)像素所占字節(jié)。

如果我們把圖片放到其他的文件夾,比如drawable-hdpi文件夾(對應(yīng)的dpi是240),會發(fā)生什么呢?

再次打印結(jié)果:

size = 7840000

這是因?yàn)橐粡垐D片的實(shí)際占用內(nèi)存大小計(jì)算公式是:

占用內(nèi)存 = 寬 * 縮放比例 * 高 * 縮放比例 * 每個(gè)像素所占字節(jié)

這個(gè)縮放比例就跟屏幕密度DPI有關(guān)了:

縮放比例 = 設(shè)備dpi/圖片所在目錄的dpi

所以我們這張圖片的實(shí)際占用內(nèi)存位:

寬700 * (480/240) * 高700 * (480/240) * 每個(gè)像素4字節(jié) = 7840000

Bitmap加載優(yōu)化?不改變圖片質(zhì)量的情況下怎么優(yōu)化?

常用的優(yōu)化方式是兩種:

  • 修改Bitmap.Config

這一點(diǎn)剛才也說過,不同的Conifg代表每個(gè)像素不同的占用空間,所以如果我們把默認(rèn)的ARGB_8888改成RGB_565,那么每個(gè)像素占用空間就會由4字節(jié)變成2字節(jié)了,那么圖片所占內(nèi)存就會減半了。

可能一定程度上會降低圖片質(zhì)量,但是我實(shí)際測試看不出什么變化。

  • 修改inSampleSize

inSampleSize,采樣率,這個(gè)參數(shù)是用于圖片尺寸壓縮的,他會在寬高的維度上每隔inSampleSize個(gè)像素進(jìn)行一次采集,從而達(dá)到縮放圖片的效果。這種方法只會改變圖片大小,不會影響圖片質(zhì)量。

    val options=BitmapFactory.Options()
    options.inSampleSize=2    val bitmap = BitmapFactory.decodeResource(resources, R.drawable.test2,options)
    img.setImageBitmap(bitmap)

實(shí)際項(xiàng)目中,我們可以設(shè)置一個(gè)與目標(biāo)圖像大小相近的inSampleSize,來減少實(shí)際使用的內(nèi)存:

    fun getImage(): Bitmap {
        var options = BitmapFactory.Options()
        options.inJustDecodeBounds = true        BitmapFactory.decodeResource(resources, R.drawable.test2, options)
        // 計(jì)算最佳采樣率        options.inSampleSize = getImageSampleSize(options.outWidth, options.outHeight)
        options.inJustDecodeBounds = false        return BitmapFactory.decodeResource(resources, R.drawable.test2, options)
    }

inJustDecodeBounds是什么?

上面的例子大家應(yīng)該發(fā)現(xiàn)了,其中有個(gè)inJustDecodeBounds,又設(shè)置為true,又設(shè)置成false的,總感覺多此一舉,那么他到底是干嘛呢?

因?yàn)槲覀円@取圖片本身的大小,如果直接decodeResource加載一遍的話,那么就會增加內(nèi)存了,所以官方提供了這樣一個(gè)參數(shù)inJustDecodeBounds。如果inJustDecodeBounds為ture,那么decodebitmap為null,也就是不返回實(shí)際的bitmap,只把圖片的大小信息放到了options的值中。

所以這個(gè)參數(shù)就是用來獲取圖片的大小信息的同時(shí)不占用內(nèi)存。

Bitmap內(nèi)存復(fù)用怎么實(shí)現(xiàn)?

如果有個(gè)需求,是在同一個(gè)imageview中可以加載不同的圖片,那我們需要每次都去新建一個(gè)Bitmap對象,占用新的內(nèi)存空間嗎?如果我們這樣寫的話:

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.actvitiy_bitmap)

        btn1.setOnClickListener {
            img.setImageBitmap(getBitmap(R.drawable.test))
        }

        btn2.setOnClickListener {
            img.setImageBitmap(getBitmap(R.drawable.test2))
        }
    }

    fun getBitmap(resId: Int): Bitmap {
        var options = BitmapFactory.Options()
        return BitmapFactory.decodeResource(resources, resId, options)
    }

這樣就會Bitmap就會頻繁去申請內(nèi)存,釋放內(nèi)存,從而導(dǎo)致大量GC,內(nèi)存抖動。

為了防止這種情況呢,我們就可以用到inBitmap參數(shù),用于Bitmap的內(nèi)存復(fù)用。這樣同一塊內(nèi)存空間就可以被多個(gè)Bitmap對象復(fù)用,從而減少了頻繁的GC。

    val options by lazy {
        BitmapFactory.Options()
    }

    val reuseBitmap by lazy {
        options.inMutable = true        BitmapFactory.decodeResource(resources, R.drawable.test, options)
    }

    fun getBitmap(resId: Int): Bitmap {
        options.inMutable = true        options.inBitmap = reuseBitmap
        return BitmapFactory.decodeResource(resources, resId, options)
    }

這里有幾個(gè)要注意的點(diǎn)

  • inBitmap要和 inMutable屬性配套使用,否則將無法復(fù)用。

  • Android 4.4之前,只能重用相同大小的 Bitmap 內(nèi)存區(qū)域; 4.4之后只要復(fù)用內(nèi)存空間的Bitmap對象大小比 inBitmap指向的內(nèi)存空間要小即可。

所以一般在復(fù)用之前,還要判斷下,新的Bitmap內(nèi)存是不是小于可以復(fù)用的Bitmap內(nèi)存,然后才能進(jìn)行復(fù)用。

高清大圖加載該怎么處理?

如果是高清大圖,那就說明不允許進(jìn)行圖片壓縮,比如微博長圖,清明上河圖。

所以我們就要對圖片進(jìn)行局部顯示,這就用到BitmapRegionDecoder屬性,主要用于顯示圖片的某一塊矩形區(qū)域。

比如我要顯示左上角的100 * 100區(qū)域:

    fun setImagePart() {
        val inputStream: InputStream = assets.open("test.jpg")
        val bitmapRegionDecoder: BitmapRegionDecoder =
            BitmapRegionDecoder.newInstance(inputStream, false)
        val options = BitmapFactory.Options()
        val bitmap = bitmapRegionDecoder.decodeRegion(
            Rect(0, 0, 100, 100), options)
        image.setImageBitmap(bitmap)
    }

實(shí)際項(xiàng)目使用中,我們可以根據(jù)手勢滑動,然后不斷更新我們的Rect參數(shù)來實(shí)現(xiàn)具體的功能即可。

具體實(shí)現(xiàn)源碼可以參考鴻洋的博客:https://blog.csdn.net/lmj623565791/article/details/49300989

如何跨進(jìn)程傳遞大圖?

  • Bundle直接傳遞。bundle最常用于Activity間傳遞,也屬于跨進(jìn)程的一種方式,但是傳遞的大小有限制,一般為1M。

//intent.put的putExtra方法實(shí)質(zhì)也是通過bundleintent.putExtra("image",bitmap);

bundle.putParcelable("image",bitmap)

Bitmap之所以可以直接傳遞,是因?yàn)槠鋵?shí)現(xiàn)了Parcelable接口進(jìn)行了序列化。而Parcelable的傳遞原理是利用了Binder機(jī)制,將Parcel序列化的數(shù)據(jù)寫入到一個(gè)共享內(nèi)存(緩沖區(qū))中,讀取的時(shí)候也會從這個(gè)緩沖區(qū)中去讀取字節(jié)流,然后再反序列化成對象使用。這個(gè)共享內(nèi)存也就是緩存區(qū)有一個(gè)大小限制—1M,而且是公用的。所以傳圖片的話很容易就容易超過這個(gè)大小然后報(bào)錯(cuò)TransactionTooLargeException。

所以這個(gè)方案不可靠。

  • 文件傳輸。

將圖片保存到文件,然后只傳輸文件路徑,這樣肯定是可以的,但是不高效。

  • putBinder

這個(gè)就是考點(diǎn)了。通過傳遞binder的方式傳遞bitmap。

//傳遞binderval bundle = Bundle()
bundle.putBinder("bitmap", BitmapBinder(mBitmap))//接收binder中的bitmapval imageBinder: BitmapBinder = bundle.getBinder("bitmap") as BitmapBinderval bitmap: Bitmap? = imageBinder.getBitmap()//Binder子類class BitmapBinder :Binder(){
    private var bitmap: Bitmap? = null    fun ImageBinder(bitmap: Bitmap?) {
        this.bitmap = bitmap
    }

    fun getBitmap(): Bitmap? {
        return bitmap
    }
}

為什么用putBinder就沒有大小限制了呢?

  • 因?yàn)?putBinder中傳遞的其實(shí)是一個(gè)文件描述符fd,文件本身被放到一個(gè)共享內(nèi)存中,然后獲取到這個(gè)fd之后,只需要從共享內(nèi)存中取出Bitmap數(shù)據(jù)即可,這樣傳輸就很高效了。

  • 而用 Intent/bundle直接傳輸?shù)臅r(shí)候,會禁用文件描述符fd,只能在parcel的緩存區(qū)中分配空間來保存數(shù)據(jù),所以無法突破1M的大小限制。

文件描述符是一個(gè)簡單的整數(shù),用以標(biāo)明每一個(gè)被進(jìn)程所打開的文件和socket。第一個(gè)打開的文件是0,第二個(gè)是1,依此類推。

到此,相信大家對“Bitmap知識點(diǎn)有哪些”有了更深的了解,不妨來實(shí)際操作一番吧!這里是創(chuàng)新互聯(lián)網(wǎng)站,更多相關(guān)內(nèi)容可以進(jìn)入相關(guān)頻道進(jìn)行查詢,關(guān)注我們,繼續(xù)學(xué)習(xí)!


網(wǎng)頁標(biāo)題:Bitmap知識點(diǎn)有哪些
地址分享:http://weahome.cn/article/ipogoi.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部