最近在做一款拼图游戏,需要用到很多的图片,在网上下了很多的图片然后放入工程中,按照原始的方法,把图片放入到控件中(ImageView)中出了问题,无法显示,出现了out of memory 的错误。
Java.lang.OutofMemoryError : bitmap size exceeds VM budget,原因是图片太大了,超出了ImageView所能承受的大小,所以在这里我们需要对图片进行处理(注意,这里的图片都是提前放在工程的drawable文件夹中的,并非从网上获取)此游戏需要对图片有3种处理: 1 图片的比例缩放 2 分割图片 3 释放图片资源
1 图片的比例缩放(图片的加载)
Bitmap在android 中指的是一张图片,可以是png格式也可以是jpg格式或者其它格式,如何加载一张图片,BitmapFactory类提供了四类方法:decodeFile、decodeResource、decodeStream、decodeByteArray,分别用于支持文件系统,资源,输入流以及字节数组中加载出一个Bitmap图像。那么如何解决OOM这个问题呢?采用BitmapFactory.options来控制采样率,让图片按比例的缩放,满足imageView的大小:
<span style="font-size:18px;"> //获得按照比例缩放后的Bitmap类型
public static Bitmap getScaledBitmap(Activity a, int rid)
{
Display display = a.getWindowManager().getDefaultDisplay();
float destWidth = display.getWidth();
float destHeigth = display.getHeight();
Log.i("TAG", destWidth +"" + destHeigth); //屏幕的长宽高
//read in the dimension of the image oh disk
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
//options是此图片的大小
BitmapFactory.decodeResource(a.getResources(),rid,options);
float srcWidth = options.outWidth;
float srcHeight = options.outHeight;
Log.i("TAG", srcWidth +"" + srcHeight); //原图片的长宽高
int insampleSize = 1; //代表原图的缩小比例(宽高都缩小)
if(srcHeight > destHeigth || srcWidth > destWidth)
{
if(srcWidth > srcHeight){
insampleSize = Math.round(srcHeight / destHeigth);
Log.i("TAG",insampleSize +"");
}
else{
insampleSize = Math.round(srcWidth / destWidth);
Log.i("TAG",insampleSize +"");
}
}
options = new BitmapFactory.Options();
options.inSampleSize = insampleSize;
options.inJustDecodeBounds = false;
Bitmap bitmap = BitmapFactory.decodeResource(a.getResources(),rid,options);
Log.i("TAG",options.outWidth +"" + options.outHeight);
Log.i("TAG",bitmap.getWidth() + "" + bitmap.getHeight() ); //缩小后的图片大小(应该跟屏幕大小一样)按比例
bitmap1 = Bitmap.createScaledBitmap(bitmap,480,650,true); //把图片拉伸为至屏幕大小
Log.i("TAG",bitmap1.getWidth() + "" + bitmap1.getHeight() );//缩小后的图片大小(应该跟屏幕大小一样)
return bitmap1;
}
}
</span>
以上代码为我在项目中的函数:可看出我们通过BitmapFactory.Options来缩放图片,主要用到的就是它的inSampleSize参数,即采样率。当inSampleSize为1时,采样后的图片大小为图片的原始大小,当inSampleSize大于1时,为2时,采样后的的图片的长宽高均为原图大小的1/2,而像素数为原图的1/4,以此类推,取值最好是2的指数,大于1才会有缩小的效果,如果小于1当1使用,如果不是2的指数,会选择一个最接近2的指数来代替。inJustDecodeBounds参数,当此参数设为true时,BitmapFactory只会解析图片的原始宽/高信息,并不会去真正的加载图片,所以这个操作是轻量级的。如果是false的话就会重新加载图片。在按比例缩放后,把图片放到IamgeView中,如果出现了比如,Imageview中有大段的空白,也就是比例缩放后小于了Imgeview的大小,没有填满,这时有两种方法用来解决: 1 imageView中的ScaleType属性的使用,它可以对图片进行拉伸填充 ; 2 实现和1方法相同的功能填充拉伸,使用createScaleBitmap方法,上面代码有介绍。
2 分割图片
分割图片在此不做过多介绍,直接上代码,有注释
<span style="font-size:18px;"> public void createInitBitmaps(int type , Bitmap bitmap , Context context){
Bitmap bitmapli = null;
List<Bitmap> bitmapList = new ArrayList<Bitmap>();
//每个Item的宽高
int itemWidth = bitmap.getWidth()/type;
int itemHeight = bitmap.getHeight()/type;
for(int i = 1 ; i <= type ; i++){
for(int j =1 ; j <= type ; j++){
bitmapli = Bitmap.createBitmap(bitmap,(j-1)*itemWidth,(i-1)*itemHeight,
itemWidth,itemHeight);
//createBitmap函数
/*0 源图片
1 裁剪x方向的起始位置
* 2 裁剪y方向的起始位置
* 3 裁剪的宽度
* 4 裁剪的高度*/
bitmapList.add(bitmapli);
Log.i("TAG", bitmapli.getWidth() +"" + bitmapli.getHeight());
//编号用于N_Puzzle问题
itemBean = new ItemBean((i -1) * type + j ,(i -1) *type + j,bitmapli);
QuziViewActivity.itemBeanList.add(itemBean);
}
}
//保存最后一个图片在拼图完成时填充
lastBitmap = bitmapList.get(type * type -1); //获得最后一个小图片
//设置最后一个为空Item
bitmapList.remove(type * type -1);
QuziViewActivity.itemBeanList.remove(type * type -1 );
//把资源中的图片赋给blankbitmap
Bitmap blankbitmap = BitmapFactory.decodeResource(context.getResources(), R.drawable.blank);
//裁剪空白图片
blankbitmap = Bitmap.createBitmap(blankbitmap,0,0,itemWidth,itemHeight);
bitmapList.add(blankbitmap); //把空白的图片加入到集合中
QuziViewActivity.itemBeanList.add(new ItemBean(type * type , 0 ,blankbitmap));
lastblankbitmap = QuziViewActivity.itemBeanList.get(type * type -1);
}</span>
3 释放图片资源
<span style="font-size:18px;"> public void cleanImageView(ImageView imageview){
if(!(imageView.getDrawable() instanceof BitmapDrawable))
return ;
BitmapDrawable b = (BitmapDrawable)imageview.getDrawable();
b.getBitmap().recycle();
imageview.setImageDrawable(null);
}</span>
主要的方法就是这些,有哪里写错的,还请大家指出。