BitmapFactory.decodeResource在Android 2.2中返回一个可变位图,在Android 1.6中返回一个不可变的Bitmap。

2022-09-01 01:11:33

我正在开发一个应用程序,并在运行Android 2.2的设备上进行测试。在我的代码中,我使用使用 BitmapFactory.decodeResource 检索的位图,并且能够通过调用它进行更改。当我在朋友的运行Android 1.6的设备上测试它时,我接到了一个电话。在线文档说,当位图不可变时,从此方法抛出一个。文档没有说明返回不可变位图的任何信息,但显然必须如此。bitmap.setPixels()IllegalStateExceptionbitmap.setPixelsIllegalStateExceptiondecodeResource

是否可以进行不同的调用,以便从应用程序资源可靠地获取可变位图,而无需第二个对象(我可以创建一个相同大小的可变位图并将其包装到 Canvas 中,但这需要两个大小相等的位图占用的内存是我预期的两倍)?Bitmap


答案 1

可以将不可变位图转换为可变位图。

我找到了一个可接受的解决方案,它只使用一个位图的内存。

源位图原始保存(RandomAccessFile)在磁盘上(没有RAM内存),然后释放源位图(现在,内存中没有位图),之后,文件信息加载到另一个位图。通过这种方式可以制作位图副本,每次在RAM内存中仅存储一个位图。

在此处查看完整的解决方案和实现:Android:将不可变位图转换为可变位图

我向此解决方案添加了一个改进,该解决方案现在适用于任何类型的位图(ARGB_8888,RGB_565等),并删除临时文件。看到我的方法:

/**
 * Converts a immutable bitmap to a mutable bitmap. This operation doesn't allocates
 * more memory that there is already allocated.
 * 
 * @param imgIn - Source image. It will be released, and should not be used more
 * @return a copy of imgIn, but muttable.
 */
public static Bitmap convertToMutable(Bitmap imgIn) {
    try {
        //this is the file going to use temporally to save the bytes. 
        // This file will not be a image, it will store the raw image data.
        File file = new File(Environment.getExternalStorageDirectory() + File.separator + "temp.tmp");

        //Open an RandomAccessFile
        //Make sure you have added uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
        //into AndroidManifest.xml file
        RandomAccessFile randomAccessFile = new RandomAccessFile(file, "rw");

        // get the width and height of the source bitmap.
        int width = imgIn.getWidth();
        int height = imgIn.getHeight();
        Config type = imgIn.getConfig();

        //Copy the byte to the file
        //Assume source bitmap loaded using options.inPreferredConfig = Config.ARGB_8888;
        FileChannel channel = randomAccessFile.getChannel();
        MappedByteBuffer map = channel.map(MapMode.READ_WRITE, 0, imgIn.getRowBytes()*height);
        imgIn.copyPixelsToBuffer(map);
        //recycle the source bitmap, this will be no longer used.
        imgIn.recycle();
        System.gc();// try to force the bytes from the imgIn to be released

        //Create a new bitmap to load the bitmap again. Probably the memory will be available. 
        imgIn = Bitmap.createBitmap(width, height, type);
        map.position(0);
        //load it back from temporary 
        imgIn.copyPixelsFromBuffer(map);
        //close the temporary file and channel , then delete that also
        channel.close();
        randomAccessFile.close();

        // delete the temp file
        file.delete();

    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    } 

    return imgIn;
}

答案 2

使用可变选项 true 将位图复制到其自身。这样就不需要额外的内存消耗和长行代码。

Bitmap bitmap= BitmapFactory.decodeResource(....);
bitmap= bitmap.copy(Bitmap.Config.ARGB_8888, true);

推荐