Android中如何加載大圖片

要好好整整不清楚的細節問題了~~加油!!!
雖然網上也有好多關於這方面的博客。。但是畢竟總結下來的纔是自己的嘛。。所以我還是寫一寫我的總結吧。。
有不好不懂的地方還希望給留言指出一二哦。。謝謝啦。。共同學習~
這篇說的是加載大圖片中的問題。。趁着自己的思路清晰趕緊寫下來。。希望能幫助到和之前一樣迷糊的同學。。
前言:
我們在新建一個虛擬機的時候,默認的虛擬機內存也就是VMHeap爲16M,所以如果在加載的過程中圖片超過了16M就會立馬出現java.lang.OutOfMemoryError:bitmap size exceeds VMbudget的錯誤。

這裏希望你明確兩個不同的概念:
假如一張圖片的像素爲:3648*2736,其大小爲2.1M;
其實:加載一張圖片時爲其分配的內存大小與其圖片本身的大小是不同的概念;
那麼一張圖片在加載時需要的內存是怎麼計算的呢?
我們知道原始的圖片都是位圖,(百度的定義如下)
位圖文件(Bitmap),擴展名可以是.bmp或者.dib。位圖是Windows標準格式圖形文件,它將圖像定義爲由點(像素)組成,每個點可以由多種色彩表示,包括2、4、8、16、24和32位色彩。例如,一幅1024×768分辨率的32位真彩圖片,其所佔存儲字節數爲:1024×768×32/8=3072KB
位圖文件圖像效果好,但是非壓縮格式的,需要佔用較大存儲空間,不利於在網絡上傳送。jpg格式則恰好彌補了位圖文件這個缺點。(--這句話不要也罷!!)
打開Android.graphics.Bitmap類裏有一個內部類Bitmap.Config類,在Bitmap類裏createBitmap(int width, int height, Bitmap.Config config)方法裏會用到ARGB_4444、ARGB_8888和RGB_565,打開個這個類一看:(這是參考的別人的話語:http://blog.csdn.net/look85/article/details/8028157
枚舉變量
public static final Bitmap.Config  ALPHA_8
public static final Bitmap.Config  ARGB_4444
public static final Bitmap.Config  ARGB_8888
public static final Bitmap.Config  RGB_565
那麼ALPHA_8, ARGB_4444,ARGB_8888,RGB_565 到底是什麼呢?
其實這都是色彩的存儲方法:我們知道ARGB指的是一種色彩模式,裏面A代表Alpha,R表示red,G表示green,B表示blue,其實所有的可見色都是右紅綠藍組成的,所以紅綠藍又稱爲三原色,每個原色都存儲着所表示顏色的信息值
說白了就ALPHA_8就是Alpha由8位組成
ARGB_4444就是由4個4位組成即16位,
ARGB_8888就是由4個8位組成即32位,
RGB_565就是R爲5位,G爲6位,B爲5位共16位

由此可見:
ALPHA_8        代表8位Alpha位圖
ARGB_4444      代表16位ARGB位圖
ARGB_8888     代表32位ARGB位圖
RGB_565         代表16位RGB位圖

位圖位數越高代表其可以存儲的顏色信息越多,當然圖像也就越逼真
​回到正題:8位即8bit = 1 byte
 所以: ARGB_4444 = 16bit/8 = 2bytes
                ARGB_8888 = 32bit/8 = 4bytes
                RGB_565 = 16bit/8 = 2bytes
所以圖片在加載時需要的空間爲:總像素的個數*像素的單位=3648*736=9980928*2bytes=19961856bytes/1024
                                                                                               =19494kB/1024 = 19.0371MB
在加載圖片時由於是按照像素點來分配空間,所以加載圖片時實際爲其分配的內存空間爲19MB大於了默認的16MB,內存不崩纔怪呢!!!!!
可見加載圖片時所需的內存大小與圖片實際佔有的大小是不一樣的哦。

解決辦法(先寫一個,後期有更好的再補):
1,縮放加載
   第一步:獲取圖片的寬和高,假如獲取的圖片的寬和高爲:3648*2736
   第二步:獲取屏幕的寬和高320*480
   第三步:計算縮放的比例:
                 寬度縮放比例: 3648/320 = 11;
                 高度縮放比例: 2736 /480 = 5;
  第四步:比較寬和高的縮放比例:原則--哪一個大就用哪一個進行縮放
                所以選擇用比例11來進行縮放:
                   縮放之後圖片的大小爲:331*248;
                再次計算加載時所需的內存大小爲:160KB
遠遠減小了~~~
上代碼:
package com.itheima40.loadbigpic;
import android.os.Bundle;
import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.BitmapFactory.Options;
import android.view.Display;
import android.view.Menu;
import android.view.View;
import android.widget.EditText;
import android.widget.ImageView;
public class MainActivity extends Activity {
private EditText etPath;
private ImageView ivIcon;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//加載控件---獲取輸入路徑的文本框和顯示圖片的ImageView
etPath = (EditText) findViewById(R.id.et_path);
ivIcon = (ImageView) findViewById(R.id.iv_icon);
}
//按鈕的點擊事件
/**
* 縮放加載
* @param v
*/
public void scaleLoad(View v) {
String path = etPath.getText().toString();
Options opts = new Options();
opts.inJustDecodeBounds = true; // 設置爲true, 加載器不會返回圖片, 而是把Options對象中以out開頭的字段給設置了.
BitmapFactory.decodeFile(path, opts);
// 得到了圖片的寬和高
int imageWidth = opts.outWidth;
int imageHeight = opts.outHeight;
System.out.println("圖片的寬和高: " + imageWidth + " * " + imageHeight);
// 獲取屏幕的寬和高
Display display = this.getWindowManager().getDefaultDisplay(); // 獲取默認窗體顯示的對象
int screenWidth = display.getWidth();
int screenHeight = display.getHeight();
System.out.println("屏幕的寬和高: " + screenWidth + " * " + screenHeight);
// 計算縮放比例
int widthScale = imageWidth / screenWidth;
int heightScale = imageHeight / screenHeight;
//選擇比例大的那個進行縮放
int scale = widthScale > heightScale ? widthScale:heightScale;
System.out.println("縮放比例: " + scale);
// 使用計算出來的比例進行縮放
opts.inJustDecodeBounds = false; // 指定加載可以加載出圖片.
opts.inSampleSize = scale;
Bitmap bm = BitmapFactory.decodeFile(path, opts);
// 顯示到ImageView控件上
ivIcon.setImageBitmap(bm);
}
}
main.xml中的樣式,簡單~不寫後臺的XML實現了---忘記說了。。圖片是存放在sd卡上的。。隨便拷貝一張圖片到SDCard的目錄下就行



代碼中需要注意的地方:

opts.inJustDecodeBounds=true;// 設置爲true, 加載器不會返回圖片, 而是把Options對象中以out開頭的字段給設置
所以你看BitmapFactory.decodeFile(path, opts);並沒有返回值吧。
但是後期我們需要BitmapFactory.decodeFile(path, opts);返回一張圖片的時候就將opts.inJustDecodeBounds=false;

opts.inJustDecodeBounds = true;
// 設置爲true, 加載器不會返回圖片, 而是把Options對象中以out開頭的字段給設置了.
BitmapFactory.decodeFile(path, opts);


上面兩句可以不用寫的~


 



 



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章