Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android開發之圖片詳解(4)

Android開發之圖片詳解(4)

編輯:關於Android編程

接上一篇。
主要研究下bitmap和drawable的使用,以及兩者的區別。
先看測試代碼:

package com.example.imagetext;

import java.util.ArrayList;
import java.util.List;

import com.example.imagetext.R.drawable;

import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.WindowManager;
import android.widget.ImageView;

public class MainActivity extends Activity {
    private Drawable drawable1,drawable2,drawable4,drawable3;
    private Bitmap bitmap1,bitmap2,bitmap3,bitmap4,bitmap6,bitmap5,bitmap7;
    private ImageView iv1,iv2;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        drawable1 = getResources().getDrawable(R.drawable.bg_1);
        drawable2 = getResources().getDrawable(R.drawable.bg_1);

        bitmap1 = ((BitmapDrawable)drawable1).getBitmap();
        bitmap2 = ((BitmapDrawable)drawable2).getBitmap();



        iv1= (ImageView) findViewById(R.id.iv1);
        iv2= (ImageView) findViewById(R.id.iv2);

        iv1.setImageResource(R.drawable.bg_1);      
        iv2.setImageResource(R.drawable.bg_1);

        drawable3 = iv1.getDrawable();
        drawable4 = iv2.getDrawable();

        bitmap3 = ((BitmapDrawable)drawable3).getBitmap();
        bitmap4 = ((BitmapDrawable)drawable4).getBitmap();

        bitmap5 = BitmapFactory.decodeResource(getResources(), R.drawable.bg_1);
        bitmap6=BitmapFactory.decodeResource(getResources(), R.drawable.bg_1);
        bitmap7 = BitmapFactory.decodeStream(getResources().openRawResource(R.drawable.bg_1));
        if(drawable1.equals(drawable2)){
            Log.e("tttext","drawble1==drawable2");
        }else{
            Log.e("tttext","drawble1!=drawable2");
        }

        if(drawable3.equals(drawable4)){
            Log.e("tttext","drawble3==drawable4");
        }else{
            Log.e("tttext","drawble3!=drawable4");
        }

        if(bitmap1.equals(bitmap2)){
            Log.e("tttext","bitmap1==bitmap2");
        }else{
            Log.e("tttext","bitmap1!=bitmap2");
        }

        if(bitmap3.equals(bitmap4)){
            Log.e("tttext","bitmap3==bitmap4");
        }else{
            Log.e("tttext","bitmap3!=bitmap4");
        }

        if(bitmap3.equals(bitmap1)){
            Log.e("tttext","bitmap3==bitmap1");
        }else{
            Log.e("tttext","bitmap3!=bitmap1");
        }

        if(bitmap5.equals(bitmap6)){
            Log.e("tttext","bitmap5==bitmap6");
        }else{
            Log.e("tttext","bitmap5!=bitmap6");
        }
        Log.e("tttext","bitmap1占用內存:"+getBitmapsize(bitmap1)/1024/1024+"M");
        Log.e("tttext","bitmap3占用內存:"+getBitmapsize(bitmap3)/1024/1024+"M");
        Log.e("tttext","bitmap5占用內存:"+getBitmapsize(bitmap5)/1024/1024+"M");
        Log.e("tttext","bitmap7占用內存:"+getBitmapsize(bitmap7)/1024/1024+"M");
    }

    @SuppressLint("NewApi")
    public long getBitmapsize(Bitmap bitmap) {

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR1) {
            return bitmap.getByteCount();
        }
        // Pre HC-MR1
        return bitmap.getRowBytes() * bitmap.getHeight();

    }


}

打印結果如下:這裡寫圖片描述

好的,現在我們逐一進行分析。<喎?/kf/ware/vc/" target="_blank" class="keylink">vcD4KCjxwPjGhoyAgPGNvZGU+ZHJhd2FibGUxID0gZ2V0UmVzb3VyY2VzKCkuZ2V0RHJhd2FibGUoUi5kcmF3YWJsZS5iZ18xKTsgPGJyPgogICAgICAgIGRyYXdhYmxlMiA9IGdldFJlc291cmNlcygpLmdldERyYXdhYmxlKFIuZHJhd2FibGUuYmdfMSk7IDxicj4KYml0bWFwMSA9ICgoQml0bWFwRHJhd2FibGUpZHJhd2FibGUxKS5nZXRCaXRtYXAoKTsgPGJyPgogICAgICAgIGJpdG1hcDIgPSAoKEJpdG1hcERyYXdhYmxlKWRyYXdhYmxlMikuZ2V0Qml0bWFwKCk7IDxicj4KPC9jb2RlPiA8YnI+CrTTtPLTob3hufu/ydLUv7Sz9qOsZHJhd2FibGUxus1kcmF3YWJsZTKyorK7ysfNrNK7uPa21M/zo6y1q8rHy/zDx8v5s9bT0LXEYml0bWFwyLTKx82s0ru49rbUz/Oho8nPxqrOxNXCztLS0b6ty7W5/cHLo6y1sWRyYXdhYmxl0v3Tw7XEysfSu7j218rUtM28xqzKsaOsy/zWuM/ytcTKx9K7uPbOu828ttTP82JpdG1hcERyYXdhYmxlsqLH0sv8u+HIpbu6tObA78Pm0bDV0srHt/HS0b6ttObU2tXiuPZiaXRtYXCjrMjnufvT0NaxvdO4tNPDo6y38dTy0MK9qKGjPC9wPgoKPHA+MqGjICBpdjEuc2V0SW1hZ2VSZXNvdXJjZShSLmRyYXdhYmxlLmJnXzEpOyA8YnI+CiAgICAgICAgaXYyLnNldEltYWdlUmVzb3VyY2UoUi5kcmF3YWJsZS5iZ18xKTs8L3A+Cgo8cHJlIGNsYXNzPQ=="brush:java;"> drawable3 = iv1.getDrawable(); drawable4 = iv2.getDrawable(); bitmap3 = ((BitmapDrawable)drawable3).getBitmap(); bitmap4 = ((BitmapDrawable)drawable4).getBitmap();

這裡看到,盡管我們使用.setImageResource方法時,打印出來的結果也一樣,但是,不同的是,setImageResource與setImageDrawable所引用的drawble以及bitmap並不是同一個,也就是說setImageResource只會復用setImageResource的位圖,setImageDrawable只會復用setImageDrawable的位圖,這裡要注意。

3。bitmap5 = BitmapFactory.decodeResource(getResources(), R.drawable.bg_1);
bitmap6=BitmapFactory.decodeResource(getResources(), R.drawable.bg_1);
bitmap7 = BitmapFactory.decodeStream(getResources().openRawResource(R.drawable.bg_1));

這裡我是直接從資源文件夾裡加載的bitmap
,分別用了兩種方法,從打印的結果可知,三者均不為同一個bitmap對象,並沒有進行復用。
但是,從占用內存大小可知:BitmapFactory.decodeResource得到的bitmap依然是放大了4倍的,(為什麼放大的是4倍,可以看看我上篇文章所說的,測試機是320dpi,而這個圖片是放在mdpi文件件下的),而BitmapFactory.decodeStream得到的則是真實的沒有經過縮放的圖片,這也正是兩個方法之間的區別。

4。
setImageResource(直接在xml裡src引用也是調用的這個方法)
setImageDrawable
setImageBitmap
這幾個方法的區別是什麼呢?

首先從源碼可以看到,setImageDrawable和setImageBitmap這兩個方法是一樣的,都是調用的setImageDrawable,之所以要區分出一個setImageBitmap是為了方便我們在引用網絡圖片或者是本地非資源文件的圖片時轉化成bitmap的縮放。另外這兩個方法是異步去加載的。

而setImageResource或者是src這個從源碼也可以看到,它們是在主線程中執行的,可能會造成activity的啟動的延遲。

5.到底有沒有必要調用bitmap.recycle()這個方法去手動回收圖片呢,這裡應該分場景:
如果是從資源文件夾裡加載的圖片,最好不要自己去手動釋放,因為它會復用緩存裡的bitmap但是並不會去判斷它是否被回收了,否則很容易出現異常。
如果是從網絡上或者是從本地相冊之類的文件加載的圖片,因為我們本身就算用的流去轉成bitmap,就算回收了也不會去復用,這個時候是可以去手動回收的,並且可以和軟引用聯合使用。
那可能有的人要問了,如果我非要使用資源文件夾裡的圖片,又非要手動去回收,但是又要保證不出現異常該怎麼辦呢?比如說一個banner頁,這個時候,我建議不要用自帶的setImageResource(直接在xml裡src引用也是調用的這個方法)
setImageDrawable這兩個方法。

應該用bitmap=BitmapFactory.decodeResource和setImageBitmap聯合使用,這裡並不會復用,並且系統也會根據頻幕密度去縮放,避免造成內存的浪費,同時你也可以自己手動去回收bitmap而不會報異常,因為上面我講過了,用這個方法是系統是不會去復用bitmap的。

6.bitmap和Drawble的具體區別,我再總結下,bitmap表示的是一個位圖,可以理解為一個對象,而Drawble表示的是一個圖畫,即可以是一個位圖,也可以是個圖形。
bitmap和Drawble都可以進行縮放,但是只有bitmap可以對像素進行精確的操作。
所以當你要精確的壓縮放大像素時,就必須用bitmap。比如網絡圖片的傳輸和加載。但是這裡值得注意的是,我們可以先從流中獲取到bitmap的寬高信息,並且計算出你具體想要縮放到的寬高。然後再加載到bitmap,可以一開始就將整個大圖加載到bitmap裡造成內存溢出,實際上很多時候都是因為這個原因出現的OOM,比如拍照。

下一篇,還有最後一篇,主要針對bitmap說下怎麼避免內存溢出和提高效率的情況下的縮放。

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved