踩的坑,奮筆記錄一次
在開發中,使用畫布,直接用bitmap物件創立
Bitmap tempBitmap = Bitmap.createBitmap(bitmap);
Canvas canvas = new Canvas(tempBitmap);
複製程式碼
程式碼跟到這裡,發現會報IllegalSatateException 異常,看了原始碼發現:
/**
* Construct a canvas with the specified bitmap to draw into. The bitmap
* must be mutable.
*
* <p>The initial target density of the canvas is the same as the given
* bitmap's density.
*
* @param bitmap Specifies a mutable bitmap for the canvas to draw into.
*/
public Canvas(@NonNull Bitmap bitmap) {
if (!bitmap.isMutable()) {
throw new IllegalStateException("Immutable bitmap passed to Canvas constructor");
}
throwIfCannotDraw(bitmap);
mNativeCanvasWrapper = initRaster(bitmap);
mFinalizer = new CanvasFinalizer(mNativeCanvasWrapper);
mBitmap = bitmap;
mDensity = bitmap.mDensity;
}
複製程式碼
發現這裡的bitmap,需要有個屬性 mutable 為true情況下才可以成功建立。 然而並不瞭解這個屬性的相關資訊,原始碼中只有介紹
/**
* Returns true if the bitmap is marked as mutable (i.e. can be drawn into)
*/
public final boolean isMutable() {
return mIsMutable;
}
複製程式碼
字面意思就是bitmap是否可變的,至少有道翻譯是這樣的。。。控制bitmap的setPixel方法能否使用,也就是外界能否修改bitmap的畫素。那什麼時候會造成bitmap不可變?焦點到Bitmap.createBitmap(bitmap);
/**
* Returns an immutable bitmap from the source bitmap. The new bitmap may
* be the same object as source, or a copy may have been made. It is
* initialized with the same density as the original bitmap.
*/
public static Bitmap createBitmap(Bitmap src) {
return createBitmap(src, 0, 0, src.getWidth(), src.getHeight());
}
複製程式碼
裡面明確指出,返回的bitmap是不可變,而且有可能是和傳入的物件是同一個。我的理解,該方法返回的bitmap mutable 是不確定的,當傳入的src的mutable 屬性為true時,經測試,返回出來的bitmap也是可操作的,既然它解釋著may be the same object as source,還是有些依據。 那既然這個方法不能保證建立的bitmap具有mutable 性,肯定有有建立具有mutable 性的方法。
/**
* Returns a mutable bitmap with the specified width and height. Its
* initial density is as per {@link #getDensity}.
*
* @param width The width of the bitmap
* @param height The height of the bitmap
* @param config The bitmap config to create.
* @throws IllegalArgumentException if the width or height are <= 0
*/
public static Bitmap createBitmap(int width, int height, Config config) {
return createBitmap(width, height, config, true);
}
複製程式碼
只有這個方法返回的bitmap是mutable 的,總結下來:建立自圖形的Bitmap是immutable,而給定寬高以及其他一些引數建立的Bitmap是mutable. 當前的問題是,提供了一個immutable 的bitmap,如何將其轉變為mutable 。
/**
* 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;
}
複製程式碼
###拿走不謝!