這幾天在作圖記的時候遇第一次遇到了OOM,好激動~~java
追究緣由,是由於在ListView中加載的圖片太大形成的,由於我使用的都是手機相機直接拍攝的照片,圖片都比較大,因此在加載的時候會出現內存溢出,那麼咱們就須要將圖片壓縮顯示了。android
首先,咱們能夠經過Bitmap.getWidth和 Bitmap.getHeight來獲取一張圖片的實際寬和高app
MainActivity.javaide
package com.example.test3; import java.io.IOException; import java.io.InputStream; import android.app.Activity; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.os.Bundle; import android.view.Display; import android.view.View; import android.view.View.OnClickListener; import android.view.WindowManager; import android.widget.Button; import android.widget.ImageView; import android.widget.Toast; public class MainActivity extends Activity { private ImageView iv; private Button bt; private int screenWidth, screenHeigh; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); bt = (Button) findViewById(R.id.bt); iv = (ImageView) findViewById(R.id.img); // 獲取屏幕信息 WindowManager wm = (WindowManager) getSystemService(WINDOW_SERVICE); Display display = wm.getDefaultDisplay(); screenWidth = display.getWidth(); screenHeigh = display.getHeight(); bt.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { try { InputStream is = getAssets().open("pic.jpg"); Bitmap bitmap = BitmapFactory.decodeStream(is); iv.setImageBitmap(bitmap); int realWidth = bitmap.getWidth(); int realHeight = bitmap.getHeight(); Toast.makeText(MainActivity.this, "真實圖片的寬:" + realWidth + ",真實圖片的高:" + realHeight + "\n 屏幕寬度:" + screenWidth + ",屏幕高度:" + screenHeigh, Toast.LENGTH_SHORT).show(); is.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }); } }
運行結果:優化
當咱們使用ListView來加載這些大圖的時候,每每會出現內存溢出的狀況,譬以下面:this
MainActivity.javaspa
package com.example.test3; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.List; import android.app.Activity; import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.BaseAdapter; import android.widget.ImageView; import android.widget.ListView; public class MainActivity extends Activity { private ListView lv; private List list = new ArrayList(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); addItem(); lv = (ListView) findViewById(R.id.lv); MyAdapter adapter = new MyAdapter(list, MainActivity.this); lv.setAdapter(adapter); } private void addItem() { list.add(""); list.add(""); list.add(""); list.add(""); } class MyAdapter extends BaseAdapter { private List mList; private Context mContext; public MyAdapter(List list, Context context) { this.mList = list; this.mContext = context; } @Override public int getCount() { // TODO Auto-generated method stub return mList.size(); } @Override public Object getItem(int position) { // TODO Auto-generated method stub return mList.get(position); } @Override public long getItemId(int position) { // TODO Auto-generated method stub return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { View view = LayoutInflater.from(mContext).inflate(R.layout.item, null); ImageView iv = (ImageView) view.findViewById(R.id.image); try { InputStream is = getAssets().open("pic.jpg"); Bitmap bitmap = BitmapFactory.decodeStream(is); is.close(); iv.setImageBitmap(bitmap); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } return view; } } }
由於咱們沒有對adapter作任何優化,因此咱們每次滑動界面的時候,都會調用getView方法而後加載圖片,這個時候就會出現OOM異常:code
雖然出現OOM異常的緣由有N多種,但就上個例子中,咱們只須要將圖片按照必定比例去縮小,而後在ListView中加載縮略圖,就能夠解決掉。blog
在Android的BitmapFactory.Options類,能夠幫助咱們對圖片進行一系列的配置(不知道這個表述是否正確)圖片
該類有一個成員變量inJustDecodeBounds,源碼中對該變量的描述以下
If set to true, the decoder will return null (no bitmap), but the out... fields will still be set, allowing the caller to query the bitmap without having to allocate the memory for its pixels.
若是將其設置爲true,那麼在BitmapFactory.decodeXXX的時候將返回爲null(不返回bitmap),可是容許調用者在不給這些bitmap分配內存的狀況下查詢該bitmap的信息。
那麼咱們就能夠在不將其加載到內存的狀況下,獲取到該圖片的寬高,咱們修改getView方法中的代碼:
public View getView(int position, View convertView, ViewGroup parent) { View view = LayoutInflater.from(mContext).inflate(R.layout.item, null); ImageView iv = (ImageView) view.findViewById(R.id.image); BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; try { InputStream is = getAssets().open("pic.jpg"); Bitmap bitmap = BitmapFactory.decodeStream(is, null, options); int width = options.outWidth; int height = options.outHeight; Log.d("TTTT", "width=" + width + ",height=" + height); is.close(); iv.setImageBitmap(bitmap); } catch (IOException e) { e.printStackTrace(); } return view; }
輸出結果爲:
而且在程序界面並無顯示圖片,由於decodeStream返回值爲null
繼續修改getView方法,此次咱們加載一張5000*5000的大圖
@Override public View getView(int position, View convertView, ViewGroup parent) { View view = LayoutInflater.from(mContext).inflate(R.layout.item, null); ImageView iv = (ImageView) view.findViewById(R.id.image); BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; try { inputStream = getAssets().open("big_pic.png"); BitmapFactory.decodeStream(inputStream, null, options); // 圖片真實寬高 int picWidth = options.outWidth; int picHeight = options.outHeight; Log.d("TTTT", "圖片的真實width:" + picWidth + ",圖片的真實height:" + picHeight); // 手機屏幕寬高 WindowManager wm = (WindowManager) getSystemService(WINDOW_SERVICE); Display display = wm.getDefaultDisplay(); int screenWidth = display.getWidth(); int screenHeight = display.getHeight(); Log.d("TTTT", "屏幕的width:" + screenWidth + ",屏幕的height:" + screenHeight); // 獲取縮放比例 int scaleX = picWidth / screenWidth; int scaleY = picHeight / screenHeight; // 設置默認縮放比例爲1 int scale = 1; if (scaleX >= scaleY & scaleY >= 1) { scale = scaleX; } else if (scaleY >= scaleX & scaleX >= 1) { scale = scaleY; } Log.d("TTTT", "縮放比例爲:" + scale); options.inJustDecodeBounds = false; options.inSampleSize = scale; inputStream = getAssets().open("big_pic.png"); Bitmap bitmap = BitmapFactory.decodeStream(inputStream, null, options); Log.d("TTTT", "縮放後的width:" + bitmap.getWidth() + ",縮放後的height:" + bitmap.getHeight()); inputStream.close(); iv.setImageBitmap(bitmap); } catch (IOException e) { e.printStackTrace(); } return view; }
再次運行:
系統提示:
圖片的真實width:5000,圖片的真實height:5000 屏幕的width:1080,屏幕的height:1776 縮放比例爲:4 縮放後的width:1250,縮放後的height:1250
在上面的代碼中咱們能夠看到,咱們講injust inJustDecodeBounds設置爲了false,表示咱們要將bitmap加載到內存中去了,而且咱們使用inSampleSize來設置了縮放比例
至此,圖片縮放完成