我将下一个例外:将问题解码为现有位图,将inBitmap
设置为true;
引起:java.lang.IllegalArgumentException:解码到现有位图的问题
在android.graphics.BitmapFactory.decodeResource(BitmapFactory.java:460)
...
有趣的是,运行时,相同的代码在不同的地方失败:
这是我的代码,它是此DevBytes: Bitmap Allocation视频中显示的副本。
private BitmapFactory.Options options;
private Bitmap reusedBitmap;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final ImageView imageView = (ImageView) findViewById(R.id.image_view);
// set the size to option, the images we will load by using this option
options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
options.inMutable = true;
BitmapFactory.decodeResource(getResources(), R.drawable.img1, options);
// we will create empty bitmap by using the option
reusedBitmap = Bitmap.createBitmap(options.outWidth, options.outHeight, Bitmap.Config.ARGB_8888);
// set the option to allocate memory for the bitmap
options.inJustDecodeBounds = false;
options.inSampleSize = 1;
options.inBitmap = reusedBitmap;
// #1
reusedBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.img1, options);
imageView.setImageBitmap(reusedBitmap);
imageView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
options.inBitmap = reusedBitmap;
// #2
reusedBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.img2, options);
imageView.setImageBitmap(reusedBitmap);
}
});
}
BitmapFactory.decodeResource()
在 // #1
BitmapFactory.decodeResource()
// #2
和jpg
。两者都失败了。png
方法检查了described here。如何正确使用此canUseForInBitmap
属性?
如果您遇到此类问题或者您发现我做了些蠢事,请发表评论/回复。任何帮助将不胜感激。如果您了解任何解决方法,那就太棒了。
很抱歉没有解释为什么我试图以这种方式重用位图的原因。
原因是每次他决定释放内存时, GC 会锁定。
inBitmap
功能应该帮助我们重用位图而不分配新的内存,这会导致GC清理已经分配的内存。
例如,如果我使用这种常用方法:
inBitmap
然后这将是GC工作:
Log.i("my_tag", "image 1");
imageView.setImageResource(R.drawable.img1);
Log.i("my_tag", "image 2");
imageView.setImageResource(R.drawable.img2);
Log.i("my_tag", "image 3");
imageView.setImageResource(R.drawable.img3);
锁定主线程超过 100ms !
如果我I/my_tag ( 5886): image 1
D/dalvikvm( 5886): GC_FOR_ALLOC freed 91K, 2% free 9113K/9240K, paused 15ms, total 15ms
I/dalvikvm-heap( 5886): Grow heap (frag case) to 19.914MB for 11520016-byte allocation
D/dalvikvm( 5886): GC_FOR_ALLOC freed <1K, 1% free 20362K/20492K, paused 13ms, total 13ms
I/my_tag ( 5886): image 2
D/dalvikvm( 5886): GC_FOR_ALLOC freed 11252K, 2% free 9111K/9236K, paused 15ms, total 15ms
I/dalvikvm-heap( 5886): Grow heap (frag case) to 19.912MB for 11520016-byte allocation
D/dalvikvm( 5886): GC_FOR_ALLOC freed <1K, 1% free 20361K/20488K, paused 35ms, total 35ms
I/my_tag ( 5886): image 3
D/dalvikvm( 5886): GC_FOR_ALLOC freed 11250K, 2% free 9111K/9236K, paused 15ms, total 15ms
I/dalvikvm-heap( 5886): Grow heap (frag case) to 19.913MB for 11520016-byte allocation
D/dalvikvm( 5886): GC_FOR_ALLOC freed <1K, 1% free 20361K/20488K, paused 32ms, total 32ms
没有decodeResource()
选项,也会发生同样的事情。所以问题仍然存在,如何使用这个属性?
答案 0 :(得分:3)
我尝试使用模拟的Nexus 4代码。
我有默认的ic_launcher.png文件,我在drawable-mdpi中复制并粘贴了两次(就像我通常那样)。我重命名了两个新文件以匹配代码中的名称(因此我做的更改较少)
当我运行应用程序时,我观察到的与你一样
经过几次不同的尝试,我决定将新的png复制到其他可绘制的文件夹 - 所以它们存在于:
我运行应用程序,它正在运行!
我不确定为什么它真的有效,但显然它必须具有正确的屏幕分辨率/密度。
答案 1 :(得分:2)
创建一个新的位图然后尝试重用它有点奇怪。为什么不让decodeResource
首先创建一个新的位图?我怀疑你在#2中的问题是,一旦你设置ImageView
使用位图,它就不能再重复使用它了(因为它已经在使用中)。 docs中提到了IllegalArgumentException
:
如果解码操作无法使用此位图,则decode方法将返回null并将抛出IllegalArgumentException。
就解决方法而言,您可能会尝试保留两个位图并切换ImageView
所指向的位图,例如:
ImageView
指向位图1 ImageView
指向位图2 答案 2 :(得分:1)
在#1&amp;之前,您需要将options.inMutable设置为true。代码中的#2。 这可能听起来有点添加,但这些都是你所踩过的小地雷。
希望这有帮助
答案 3 :(得分:0)
为什么要解码位图?只是做:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final ImageView imageView = (ImageView) findViewById(R.id.image_view);
imageView.setImageResource(R.drawable.img1);
imageView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
imageView.setImageResource(R.drawable.img2);
}
});
}
你确定你的两个图像都有相同的尺寸吗?根据{{3}}
如果设置了[inBitmap],则解码采用Options对象的方法 尝试在加载内容时重用此位图。如果解码 操作不能使用这个位图,解码方法将返回null 并将抛出IllegalArgumentException。目前的实施 需要重用的位图是可变的,结果是必需的 即使在解码时,重用的位图仍将保持可变 通常会导致不可变位图的资源。
您仍应始终使用返回的解码方法Bitmap 并且由于约束,不假设重用位图有效 以上概述和可能发生的故障情况。检查是否 返回值与Options中设置的inBitmap的值匹配 结构将指示位图是否被重用,但在所有情况下都是你 应该使用解码函数返回的Bitmap来确保 您正在使用用作解码目标的位图。
使用BitmapFactory
从KITKAT开始,BitmapFactory可以重用任何可变位图 解码任何其他位图,只要得到的字节数 解码后的位图小于或等于分配的字节数 重用的位图。这可能是因为内在尺寸较小, 或其缩放后的尺寸(密度/样本大小)较小。
在KITKAT之前适用其他约束:正在解码的图像 (无论是作为资源还是作为流)必须采用jpeg或png格式。 仅支持相同大小的位图,inSampleSize设置为1。 此外,重用位图的配置将覆盖 设置inPreferredConfig,如果设置。
修改强>
如果您有大型资源位图,只需将其加载到asynctask ...更多信息documentation但它可以更加简单。
答案 4 :(得分:0)
我不确定您在#2遇到的问题。但是你遇到Nexus 4的问题可能是因为你把两个图像放在了错误的dpi drawable文件夹中。因此,当它尝试解码位图时,它无法找到资源。
我的手机屏幕密度是hdpi,起初我尝试将两个图像放在drawable-mdpi中,我面对的问题是#1。所以我将它改为drawable-hdpi,并且它有效。
答案 5 :(得分:-4)
只需输入largeHeap =&#34; true&#34;在应用程序标签(AndroidManifest.xml)
中