I need help with NinePatchDrawable:
My app can download themes from the network. Almost all things work fine, except 9-Patch PNGs.
final Bitmap bubble =
It's actually slightly more complicated than that, but what it boils down to is pretty simple:
The padding rect is returned by BitmapFactory.decodeStream(InputStream, Rect, Options). There is no version of decodeByteArray() which can return the padding rect.
The whole nine-patch API is a bit silly:
decodeByteArray() calls nativeDecodeByteArray(), which is presumably more efficient than nativeDecodeStream() on a ByteArrayInputStream, but obviously the devs never expected you to want to decode a nine-patch from memory.NinePatch instead of BitmapFactory. Sadly, NinePatch.java is not much more than a wrapper that passes the bitmap and nine-patch chunk to drawing methods (and most of the NinePatch.draw() calls aren't thread-safe due to the call to mRect.set(location)).NinePatch and a padding rect, which makes NinePatch somewhat useless in application code (unless you want to do the padding yourself). There is no NinePatchDrawable.getNinePatch() or NinePatch.getBitmap().This comment sums it up pretty well:
ugh. The
decodeStreamcontract is that we have already allocated the pad rect, but if the bitmap does not had a ninepatch chunk, then the pad will be ignored. If we could change this to lazily alloc/assign the rect, we could avoid the GC churn of making newRects only to drop them on the floor.
My fix is fairly simple:
public final class NinePatchWrapper {
private final Bitmap mBitmap;
private final Rect mPadding;
/**
* The caller must ensure that that bitmap and padding are not modified after
* this method returns. We could copy them, but Bitmap.createBitmap(Bitmap)
* does not copy the nine-patch chunk on some Android versions.
*/
public NinePatchWrapper(Bitmap bitmap, Rect padding) {
mBitmap = bitmap;
mPadding = padding;
}
public NinePatchDrawable newDrawable(Resources resources) {
return new NinePatchDrawable(mBitmap, mBitmap.getNinePatchChunk(), mPadding, null);
}
}
...
public NinePatchWrapper decodeNinePatch(byte[] byteArray, int density) {
Rect padding = new Rect();
ByteArrayInputStream stream = new ByteArrayInputStream(byteArray);
Bitmap bitmap = BitmapFactory.decodeStream(stream, padding, null);
bitmap.setDensity(density);
return new NinePatchWrapper(bitmap, padding);
}
Untested, since it's greatly simplified. In particular, you might want to check that the nine-patch chunk is valid.