1. Bitmap 性能相关
使用 inSampleSize 来缩放
使用方式:
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true; // 设为 true 不会分配内存,用来获取图片宽高
BitmapFactory.decodeResource(getResources(), R.mipmap.test, options);
int width = options.outWidth;
int height = options.outHeight;
// 根据图片宽高和实际需要宽高计算 inSampleSize, 需要是 2 的次方,inSampleSize 是 2 则图片宽高压缩为原来的 1/2, inSampleSize 小于 1 则置为 1
// options.inSampleSize = ;
options.inJustDecodeBounds = false;
// 按照 inSampleSize 来解析 bitmap
Bitmap resource = BitmapFactory.decodeResource(getResources(), R.mipmap.test, options);
使用合适的 Config
在把资源解析为 Bitmap 过程中通过设置 options.inPreferredConfig, 或者在创建 Bitmap (Bitmap.createBitmap) 时指定 Config, Config 的值有以下几种:
ALPHA_8:无颜色,只有透明度
RGB_565:只有颜色,无透明度
ARGB_4444:一个像素占8个字节
ARGB_8888:一个像素占4个字节,相比 ARGB_4444, ARGB_8888 更推荐使用
根据自己需要选择使用
2. 大图加载
大图加载使用的是 BitmapRegionDecoder, 代码如下:
// 自定义大图加载 View
public class LongImageView extends View {
private static BitmapFactory.Options options = new BitmapFactory.Options();
private static BitmapRegionDecoder decoder;
private Rect rect = new Rect();
// View 宽高
private int mHeight;
private int mWidth;
// 图片宽高
private int mImgHeight;
private int mImgWidth;
static {
options.inPreferredConfig = Bitmap.Config.RGB_565;
}
public LongImageView(Context context) {
super(context);
}
public LongImageView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}
public LongImageView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
private int lastX;
private int lastY;
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
if (lastX == 0) {
lastX = (int) event.getX();
}
if (lastY == 0) {
lastY = (int) event.getY();
}
break;
case MotionEvent.ACTION_MOVE: // 这里只是简单地处理了手势,待优化
int disY = (lastY - (int)event.getY());
int disX = (lastX - (int)event.getX());
if (mImgWidth > mWidth) {
rect.offset(disX, 0);
checkWidth();
invalidate();
}
if (mImgHeight > mHeight) {
rect.offset(0, disY);
checkHeight();
invalidate();
}
lastX = (int) event.getX();
lastY = (int) event.getY();
break;
case MotionEvent.ACTION_UP:
lastX = 0;
lastY = 0;
break;
}
return true;
}
private void checkHeight() {
if (rect.top < 0) {
rect.top = 0;
rect.bottom = mHeight;
}
if (rect.bottom > mImgHeight) {
rect.bottom = mImgHeight;
rect.top = mImgHeight - mHeight;
}
}
private void checkWidth() {
if (rect.left < 0) {
rect.left = 0;
rect.right = mWidth;
}
if (rect.right > mImgWidth) {
rect.right = mImgWidth;
rect.left = mImgWidth - mWidth;
}
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
mWidth = getMeasuredWidth();
mHeight = getMeasuredHeight();
rect.left = 0;
rect.top = 0;
rect.right = mWidth;
rect.bottom = mHeight;
}
@Override
protected void onDraw(Canvas canvas) {
Bitmap bitmap = decoder.decodeRegion(rect, options);
canvas.drawBitmap(bitmap, 0, 0, null);
}
public void setInputStream(InputStream is) {
try {
decoder = BitmapRegionDecoder.newInstance(is, true);
// 直接使用了 decoder 获取宽高,就不能再用 BitmapFactory 来解析 is 获取图片宽高了
mImgHeight = decoder.getHeight();
mImgWidth = decoder.getWidth();
requestLayout();
invalidate();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (is != null) {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
// 使用
LongImageView liv = (LongImageView) findViewById(R.id.liv);
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.test);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.PNG, 100, baos);
InputStream isBm = new ByteArrayInputStream(baos.toByteArray());
liv.setInputStream(isBm);