Android加载图片时,对于分辨率小,配置低的机子,很容易发生OutOfMemoryError。手机的内存比图片的大很多,怎么会这样?

在设置Android虚拟机的内存时:

RAM:模拟器的内存空间

VM Heapdalvik虚拟机最大占用内存,也就是单个进程的最大占用内存。

VM Heap高配的手机,可能有32M,64M,128M,而低配的手机,一般是16M,分辨率越大的手机,一般分配的也比较多。

Android系统对dalvik的vm heapsize作了硬性限制,当java进程申请的java空间超过阈值时,就会抛出OOM异常。也就是说RAM充足也会发生OOM的异常。

--------------------

VM Heap大小16mb,当应用加载一张大图时,加载图片所需要的内存空间不是按照图片大小算的,而是按照图片的像素点来算的。

图片像素点计算:

1张叫juhua.jsp的图片,大小1.27MB,分辨率:3840*2160,24位。

* Android保存图片像素信息,是用ARGB保存
 * A:0-255,需要一个长度为8的二进制数字,占用1个字节
 * R:0-255,需要一个长度为8的二进制数字,占用1个字节
 * G:0-255,需要一个长度为8的二进制数字,占用1个字节
 * B:0-255,需要一个长度为8的二进制数字,占用1个字节

3840*2160*4=33177600字节/1024/1024=31.640MB
超过了VM Heap的16MB,报内存溢出
10-27 06:16:27.645: I/dalvikvm-heap(1894): Forcing collection of SoftReferences for 33177612-byte allocation
10-27 06:16:27.645: E/dalvikvm-heap(1894): Out of memory on a 33177612-byte allocation.
10-27 06:16:27.655: E/AndroidRuntime(1894): Caused by: java.lang.OutOfMemoryError

************************************
解决方法:
按比例缩小图片,再加载。
现有手机屏幕分辨率 320*480
宽比:3840/320=12
高比:2160/480=4

选择比例大的数字12

缩放后再设置,就不会溢出了。
31.640MB/12=2.64mb


代码例子:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity" >

    <Button
        android:id="@+id/btn1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="点击加载大图片(OOO)"
        android:onClick="loadPic"/>
    
    <Button
        android:id="@+id/btn2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@id/btn1"
        android:text="点击缩放加载大图片"
        android:onClick="scaleLoadPic"/>
    
    <ImageView 
        android:id="@+id/iv_pic"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@id/btn2"
        />

</RelativeLayout>

package com.example.loadbigpic;

import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.BitmapFactory.Options;
import android.os.Bundle;
import android.view.Display;
import android.view.View;
import android.widget.ImageView;

public class MainActivity extends Activity {

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
	}
	
	public void loadPic(View v){
		/*
		 * BitmapFactory.decodeResource(?,?)
		 * 这个带两个参数的方法:第一个参数是包含你要加载的位图资源文件的对象(一般写成 getResources()就ok了);
		 * 第二个时你需要加载的位图资源的Id。
			BitmapFactory.decodeResource(?,?,?)带三个参数的方法:
			前两个和上面的方法一样。第三个参数应该是对你要加载的位图是否需要完整显示,如果你只需要部分,可以在这里定制。
		 */
		Bitmap bm=BitmapFactory.decodeResource(getResources(),R.drawable.juhua);
		ImageView iv_pic=(ImageView) findViewById(R.id.iv_pic);
		iv_pic.setImageBitmap(bm);
		
	}
	
	public void scaleLoadPic(View v){
		Options opts=new Options();
		//默认为false,设为true,则decoder返回null,
		//即BitmapFactory.decodeResource(getResources(),R.drawable.juhua,opts);返回null
		//但会返回图片的参数的信息到Options对象里
		//不解析图片到内存里
		opts.inJustDecodeBounds=true;
		BitmapFactory.decodeResource(getResources(),R.drawable.juhua,opts);
		//获取图片的宽,高
		int imageWidth=opts.outWidth;
		int imageHeigth=opts.outHeight;
		
		//获取屏幕的高宽
		Display dp=getWindowManager().getDefaultDisplay();
		//在高版本里有新的方法获取,但图片加载是常用功能,要兼容低版本,所以过时了也用
		int screenWidth=dp.getWidth();
		int screenHeight=dp.getHeight();
		
		//计算缩放比例
		int scale=1;
		int scaleWidth=imageWidth/screenWidth;
		int scaleHeight=imageHeigth/screenHeight;
		
		//取缩放比例,取那个大的值
		if(scaleWidth>=scaleHeight && scaleWidth>=1){
			scale=scaleWidth;
		}else if(scaleWidth<scaleHeight && scaleHeight>=1){
			scale=scaleHeight;
		}
		
		//设置缩放比例
		opts.inSampleSize=scale;
		opts.inJustDecodeBounds=false;
		Bitmap bm=BitmapFactory.decodeResource(getResources(),R.drawable.juhua,opts);
		
		ImageView iv_pic=(ImageView) findViewById(R.id.iv_pic);
		iv_pic.setImageBitmap(bm);
		
	}

}







Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐