LeveListDrawable实现多图片显示以及防止图片内存溢出方法
来源:互联网 发布:实时数据库应用 编辑:程序博客网 时间:2024/05/16 10:27
<span style="font-size:12px;"> <?xml version="1.0" encoding="utf-8"?> <level-list xmlns:android="http://schemas.android.com/apk/res/android" > <item android:drawable="@drawable/drawable_resource" android:maxLevel="integer" android:minLevel="integer" /> </level-list></span>
XML定义的Drawable的一种,以<level-list>作为根元素,其间可包含任意多个<item>节点,每一个<item>节点包含一个drawable对象和maxLevel与minLevel值,如:
<span style="font-size:12px;"><?xml version="1.0" encoding="utf-8"?><level-list xmlns:android="http://schemas.android.com/apk/res/android" > <item android:minLevel="0" android:maxLevel="10" android:drawable="@drawable/b1" /> <item android:minLevel="11" android:maxLevel="20" android:drawable="@drawable/b2" /> <item android:minLevel="21" android:maxLevel="30" android:drawable="@drawable/b3" /> <item android:minLevel="31" android:maxLevel="40" android:drawable="@drawable/b4" /></level-list></span>
当我们向LevelListDrawable对象提供一个Level值后,LevelListDrawable对象就会从前往后查看每一个<item>,当某个<item>节点的Level范围满足提供的那个Level值后,就会返回该<item>结点里指定的drawable。并且不会继续往后找。所以定义这个LevelListDrawable时要注意各个<item>的顺序。比如:
<span style="font-size:12px;"><?xml version="1.0" encoding="utf-8"?><level-list xmlns:android="http://schemas.android.com/apk/res/android" > <item android:maxLevel="40" android:drawable="@drawable/b4" /> <item android:maxLevel="10" android:drawable="@drawable/b1" /> <item android:maxLevel="20" android:drawable="@drawable/b2" /> <item android:maxLevel="30" android:drawable="@drawable/b3" /> </level-list></span>
那么无论提供什么样的Level值,都不会返回后面三个<item>里的drawable(这里如果提供的Level值超过40,将返回一个空对象)。
可以通过Drawable对象的setLevel(int)方法来提供Level值。
比如当我们将一个LevelListDrawable作为一个View的background后,可以通过View的getBackground()方法获取这个Drawable对象,然后调用这个Drawable对象的setLevel()方法,提供不同的Level值,就可以改变View的背景。这个可以用来制作诸如进度条、音量调节等效果。
ImageView组件还提供了setImageLevel()方法来快捷设置android:src指定的LevelListDrawable的Level值(android:backgroudn指定的背景还是要通过View的形式来更改)。
下面是例子:
1、在XML文件中定义
level_list.xml:
<?xml version="1.0" encoding="utf-8"?> <level-list xmlns:android="http://schemas.android.com/apk/res/android"> <item android:maxLevel="1" android:drawable="@drawable/image1" /> <item android:maxLevel="2" android:drawable="@drawable/image2" /> <item android:maxLevel="3" android:drawable="@drawable/image3" /> <item android:maxLevel="4" android:drawable="@drawable/image4" /> <item android:maxLevel="5" android:drawable="@drawable/image5" /> </level-list>
在布局文件main.xml中:
<ImageView android:id="@+id/imgView" android:src="@drawable/level_list" android:layout_width="wrap_content" android:layout_height="wrap_content"/>
2、在代码中使用:
因为我所使用的图片过大,会导致内存泄露,所以做了一些处理。
package com.example.drawabletest; import android.app.Activity; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.LevelListDrawable; import android.os.Bundle; import android.view.Menu; import android.view.View; import android.widget.Button; import android.widget.ImageView; import android.widget.Toast; public class MainActivity extends Activity { private int[] ids = new int[] { R.drawable.image1, R.drawable.image2, R.drawable.image3, R.drawable.image4, R.drawable.image5 }; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); final ImageView imageView = (ImageView) findViewById(R.id.imgView); BitmapFactory.Options opts = new BitmapFactory.Options(); opts.inJustDecodeBounds = true; BitmapFactory.decodeResource(getResources(), R.drawable.image1, opts); opts.inSampleSize = computeSampleSize(opts, -1, 500 * 500); opts.inJustDecodeBounds = false; opts.inInputShareable=true; opts.inPurgeable=true; LevelListDrawable levelListDrawable = new LevelListDrawable();//定义一个LevelDrawable try { for (int i = 0; i < ids.length; i++) {//for循环,加载5个drawable资源 Bitmap bmp = BitmapFactory.decodeResource(getResources(),ids[i], opts); BitmapDrawable bitmapDrawable = new BitmapDrawable(bmp); levelListDrawable.addLevel(i, i+1, bitmapDrawable);//添加到LevelListDrawable } imageView.setImageDrawable(levelListDrawable);//设置 } catch (OutOfMemoryError err) { err.printStackTrace(); } imageView.setImageLevel(1);//默认的level为0,将到设置为1 Button btn = (Button) findViewById(R.id.btn); btn.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { int i = imageView.getDrawable().getLevel(); if (i >=5) i = 0; // imageView.setImageLevel(++i);//改变level imageView.getDrawable().setLevel(++i); //能达到同样的效果 } }); } @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.activity_main, menu); return true; } //这是android源码中智能计算opts.inSampleSize的方法 public static int computeSampleSize(BitmapFactory.Options options, int minSideLength, int maxNumOfPixels) { int initialSize = computeInitialSampleSize(options, minSideLength, maxNumOfPixels); int roundedSize; if (initialSize <= 8) { roundedSize = 1; while (roundedSize < initialSize) { roundedSize <<= 1; } } else { roundedSize = (initialSize + 7) / 8 * 8; } return roundedSize; } private static int computeInitialSampleSize(BitmapFactory.Options options, int minSideLength, int maxNumOfPixels) { double w = options.outWidth; double h = options.outHeight; int lowerBound = (maxNumOfPixels == -1) ? 1 : (int) Math.ceil(Math.sqrt(w * h / maxNumOfPixels)); int upperBound = (minSideLength == -1) ? 128 : (int) Math.min( Math.floor(w / minSideLength), Math.floor(h / minSideLength)); if (upperBound < lowerBound) { // return the larger one when there is no overlapping zone. return lowerBound; } if ((maxNumOfPixels == -1) && (minSideLength == -1)) { return 1; } else if (minSideLength == -1) { return lowerBound; } else { return upperBound; } } }
使用LevelDrawable注意几点:
1、默认的level为0,如果没有和0匹配的level,那么就不显示。
2、level匹配以maxLevel优先。即如果有个item,min:1,max:2。 另一份item,min:2,max:3。
如果此时设置level=2,那么会匹配第一个item。
解释上面防止图片内存溢出的代码:
首先我们把这个图片转成Bitmap,然后再利用Bitmap的getWidth()和getHeight()方法就可以取到图片的宽高了。
新问题又来了,在通过BitmapFactory.decodeFile(Stringpath)方法将突破转成Bitmap时,遇到大一些的图片,我们经常会遇到OOM(Out OfMemory)的问题。怎么避免它呢?
这就用到了我们上面提到的BitmapFactory.Options这个类。
BitmapFactory.Options这个类,有一个字段叫做
If set to true, the decoderwill return null (no bitmap), but theout…
也就是说,如果我们把它设为true,那么BitmapFactory.decodeFile(Stringpath, Optionsopt)并不会真的返回一个Bitmap给你,它仅仅会把它的宽,高取回来给你,这样就不会占用太多的内存,也就不会那么频繁的发生OOM了。
示例代码如下:
- BitmapFactory.Options options = newBitmapFactory.Options();
- options.inJustDecodeBounds = true;
- Bitmap bmp = BitmapFactory.decodeFile(path, options);
这段代码之后,options.outWidth 和 options.outHeight就是我们想要的宽和高了。
有了宽,高的信息,我们怎样在图片不变形的情况下获取到图片指定大小的缩略图呢?
比如我们需要在图片不变形的前提下得到宽度为200的缩略图。
那么我们需要先计算一下缩放之后,图片的高度是多少
- int height = options.outHeight * 200 / options.outWidth;
- options.outWidth = 200;
- options.outHeight = height;
- options.inJustDecodeBounds = false;
- Bitmap bmp = BitmapFactory.decodeFile(path, options);
- image.setImageBitmap(bmp);
这样虽然我们可以得到我们期望大小的ImageView
但是在执行BitmapFactory.decodeFile(path,options);时,并没有节约内存。要想节约内存,还需要用到BitmapFactory.Options这个类里的
我们可以根据图片实际的宽高和我们期望的宽高来计算得到这个值。
- inSampleSize = options.outWidth / 200;
options.inSampleSize = 10; //width,hight设为原来的十分一,图片大小为原来的1/100
另外,为了节约内存我们还可以使用下面的几个字段:
- options.inPreferredConfig =Bitmap.Config.ARGB_4444;
//默认是Bitmap.Config.ARGB_8888 - options.inPurgeable = true;
- options.inInputShareable = true;
- LeveListDrawable实现多图片显示以及防止图片内存溢出方法
- 防止加载图片内存溢出的方法
- 图片处理(防止内存溢出)
- 【Android】通过软引用实现图片缓存,防止内存溢出
- 通过软引用实现图片缓存,防止内存溢出
- Android 通过软引用实现图片缓存,防止内存溢出
- Android 通过软引用实现图片缓存,防止内存溢出
- Android 通过软引用实现图片缓存,防止内存溢出
- Android 通过软引用实现图片缓存,防止内存溢出
- Android 通过软引用实现图片缓存,防止内存溢出
- Android 通过软引用实现图片缓存,防止内存溢出
- Android 通过软引用实现图片缓存,防止内存溢出
- Android通过软引用实现图片缓存,防止内存溢出
- android 加载图片防止内存溢出
- Android加载图片,防止内存溢出
- 防止图片decode时候(内存溢出)oom
- Android Bitmap图片处理,防止内存溢出
- 获取手机摄像机图片的缩略图方法,防止内存溢出异常
- REST Client组件例子,及获取数据api的一些知识
- 字符串"true"转换为布尔型boolean「true」
- 基于FUSE框架的文件系统-课程设计
- Android Studio 与 Eclipse 快捷键对照及AS常用快捷键
- hadoop面试题总结1
- LeveListDrawable实现多图片显示以及防止图片内存溢出方法
- HDU 1016 Prime Ring Problem
- jQuery选择器总结
- simpleAdapter类
- (水)大臣的旅费 蓝桥杯 树的直径
- JavaScript模拟生成二维数组及多维数组
- 110. Balanced Binary Tree
- 面向对象高级编程
- 多个activity之间通信