BitmapFactory.de codeResource返回一个可变的位图在Android 2.2及一个不变的位图中的Andr​​oid 1.6位图、图中、codeResource、de

2023-09-12 00:20:23 作者:回忆如困兽

我开发一个应用程序,并运行Android 2.2设备上测试它。在我的code,我利用我检索使用BitmapFactory.de codeResource一个位图,而我能够通过调用 bitmap.setPixels()就可以了。当我测试这个运行Android 1.6朋友的设备上,我得到一个 IllegalStateException异常在调用 bitmap.setPixels 。文档在网上说,一个 IllegalStateException异常从此方法抛出时,位图是不可改变的。该文件并没有说明什么去codeResource 返回一个不可变的位图,但很明显,这一定是这样的。

I am developing an application and testing it on my device running Android 2.2. In my code, I make use of a Bitmap that I retrieve using BitmapFactory.decodeResource, and I am able to make changes by calling bitmap.setPixels() on it. When I test this on a friend's device running Android 1.6, I get an IllegalStateException in the call to bitmap.setPixels. Documentation online says an IllegalStateException is thrown from this method when the bitmap is immutable. The documentation doesn't say anything about decodeResource returning an immutable bitmap, but clearly that must be the case.

是否有不同的电话我可以从应用程序的资源得到了可变位可靠,无需第二个位图对象(我可以创建一个可变的一个同样大小并绘制成帆布包裹它,但这需要两个相同大小的位图使用了两倍的内存,因为我本来打算)?

Is there a different call I can make to get a mutable bitmap reliably from an application resource without needing a second Bitmap object (I could create a mutable one the same size and draw into a Canvas wrapping it, but that would require two bitmaps of equal size using up twice as much memory as I had intended)?

推荐答案

您可以将您的不可变的位图到一个可变的位图。

You can convert your immutable bitmap to a mutable bitmap.

我发现,使用一个位图的只有内存可以接受的解决方案。

I found an acceptable solution that uses only the memory of one bitmap.

一个源位图的原始保存(RandomAccessFile中)在磁盘上(无RAM内存),那么源位图的发布,(现在,有没有位图在内存),并在此之后,文件信息加载到另一个位图。这种方式可以使具有存储在每个时间的RAM存储器只是一个位图的位图副本。

A source bitmap is raw saved (RandomAccessFile) on disk (no ram memory), then source bitmap is released, (now, there's no bitmap at memory), and after that, the file info is loaded to another bitmap. This way is possible to make a bitmap copy having just one bitmap stored in ram memory per time.

查看完整的解决方案和实施在这里:安卓转换不可变的位图到可变

See the full solution and implementation here: Android: convert Immutable Bitmap into Mutable

予添加一个改进这一解决方案,现在可以与任何类型的位图(ARGB_8888,RGB_565等),并删除临时文件。见我的方法:

I add a improvement to this solution, that now works with any type of Bitmaps (ARGB_8888, RGB_565, etc), and deletes the temp file. See my method:

/**
 * 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;
}