Open zhjlong opened 5 years ago
https://www.jianshu.com/p/116e05dfd66b 参考这个文章,一些想法 1.用浏览器加载的方法,从上到下一点一点加载,这样的好处是图片清晰度比较高 2.先加载一张缩略图占位,然后压缩整个图片,减少图片的像素加载出图片,会快一些但不够清晰 //尺寸压缩(通过缩放图片像素来减少图片占用内存大小) `public static void sizeCompress(Bitmap bmp, File file) { // 尺寸压缩倍数,值越大,图片尺寸越小 int ratio = 8; // 压缩Bitmap到对应尺寸 Bitmap result = Bitmap.createBitmap(bmp.getWidth() / ratio, bmp.getHeight() / ratio, Config.ARGB_8888); Canvas canvas = new Canvas(result); Rect rect = new Rect(0, 0, bmp.getWidth() / ratio, bmp.getHeight() / ratio); canvas.drawBitmap(bmp, null, rect, null);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
// 把压缩后的数据存放到baos中
result.compress(Bitmap.CompressFormat.JPEG, 100, baos);
try {
FileOutputStream fos = new FileOutputStream(file);
fos.write(baos.toByteArray());
fos.flush();
fos.close();
} catch (Exception e) {
e.printStackTrace();
}
}`
看到小伙伴回答的,大概是基于加载速度和内存优化两个方向的,我没其他想法,拾人牙慧答一下;
加载优化的就是Http协议中的Range / Accept-Range ,他可以指定获取body的一部分,从而达到分块加载图片的效果; 内存优化的方向是,我屏幕只有这么大,那我就只加载跟屏幕一样的Bitmap就好了,超出屏幕外面的就没必要加到内存里面增加负担;
@Override
protected void onDraw(Canvas canvas) {
//这个mDecoder就是上面同学说到的BitmapRegionDecoder,options就是BitmapFactory.Options
Bitmap bm = mDecoder.decodeRegion(mRect, options);
canvas.drawBitmap(bm, 0, 0, null);
}
根据手势滑动每次重新计算mRect去获取部分bitmap绘制到屏幕上。
(谢谢上面同学的回答)
加载大长图可以使用 压缩或局部加载的方法。
压缩可以使用BitmapFactory类的相关方法,获取到图片的原始大小后,再计算图片压缩比,最后压缩图片后再显示。不过压缩就会降低图片的清晰度,如果要按原图加载图片,可以用BitmapRegionDecoder实现图片局部加载。
BitmapRegionDecoder可以用来显示图片指定的一个矩形区域。通过自定义View重写onTouchEvent()判断手势滑动位置,从而改变矩形区域的位置。
如果是加载网络大图片,还可以分块请求数据,让图片更快地显示出来。
(分享鸿洋的一篇博客:Android 高清加载巨图方案 拒绝压缩图片)
参考简书资料:https://www.jianshu.com/p/4640764bfbc6 图片太大,进行压缩处理: BitmapFactory这个类就提供了多个解析方法(decodeResource、decodeStream、decodeFile等)用于创建Bitmap。我们可以根据图片的来源来选择解析方法。比如如果图片来源于网络,就可以使用decodeStream方法;如果是sd卡里面的图片,就可以选择decodeFile方法;如果是资源文件里面的图片,就可以使用decodeResource方法等。 BitmapFactory为这些方法都提供了一个可选的参数BitmapFactory.Options,用来辅助我们解析图片。这个参数有一个属性inSampleSize,这个属性可以帮助我们来进行图片的压缩。 如果不进行压缩处理,图片超出屏幕显示范围,进行局部加载处理: BitmapRegionDecoder bitmapRegionDecoder = BitmapRegionDecoder.newInstance(inputStream, false); bitmapRegionDecoder.decodeRegion(rect, options); 参数一是一个rect,控制显示区域,参数二是BitmapFactory.Options,你可以控制图片的inSampleSize,inPreferredConfig等。
1.对图片进行压缩处理
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(getResources(), R.mipmap.wei, options);
options.inSampleSize = Math.max(options.outWidth / DensityUtils.screenWidth(this),
options.outHeight / DensityUtils.screenHeight(this));
options.inJustDecodeBounds = false;
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.wei, options);
mImageView.setImageBitmap(bitmap);
mMemoryText.setText("bitmapMemory="+bitmap.getByteCount() + " imageMemory="+bitmap.getAllocationByteCount());
这种方案虽然也能够显示,但是不能够保证图片的清晰度。
2.局部展示:
InputStream is = null;
try {
is = getAssets().open("wei.png");
BitmapRegionDecoder decoder = BitmapRegionDecoder.newInstance(is, false);
BitmapFactory.Options options1 = new BitmapFactory.Options();
options1.inPreferredConfig = Bitmap.Config.ARGB_8888;
Bitmap bitmap = decoder.decodeRegion(new Rect(0, 0, DensityUtils.screenWidth(this),
DensityUtils.screenHeight(this)- DensityUtils.dip2px(this, 200)), options1);
mImageView.setImageBitmap(bitmap);
mMemoryText.setText("bitmapMemory="+bitmap.getByteCount() + " imageMemory="+bitmap.getAllocationByteCount());
} catch (IOException e) {
e.printStackTrace();
} finally {
if (is != null) {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
这种方案是加载图片的局部,如果要观察其余部分,可以通过增加手势操作或者触摸事件。
1,对于加载网络的图片,如果只是作为缩略图展示的话,可以下载该图片的缩略图来展示,以提高加载速度和省流量的目的。点击详情图片时,才去加载原图。
2,就是使用上面各位同学说的BitmapRegionDecoder这个类来展示局部图片,根据可见区域来加载图片,从而避免oom的问题。但是该类只是Android为我们提供的基本API,实际使用中,你会发现如果在onDraw方法中绘制bitmap对象会占用主线程资源,导致丢帧而造成卡顿的现象。除此之外还需要考虑快速滑动而造成bitmap大量创建和大量回收而生成的抖动问题。而且如果要加载长图,还要有放大缩小的功能,这些也需要我们自己实现。
3,使用SubsamplingScaleImageView框架来加载长图,该框架底层就是使用BitmapRegionDecoder来加载局部图片的,该框架提供了缩放和触摸等手势的功能。该框架为了解决滑动卡顿的问题,对于move事件进行了优化,不会直接加载清晰度高的图片,而是对于原解码率的图片进行scale放大,直到up事件发生后,才会在后台加载相应解码率的图片,生成对应的bitmap,再进行相应的更新。因此滑动时,我们先会看到模糊的图片,然后才能看到清晰的图片。它的缺点是不能直接加载网络的图片,要把网络的图片下载到本地才能加载。
4,使用SketchImageView来加载长图,底层也是BitmapRegionDecoder实现的。这是一套很完整的图片加载框架,对于大图的分块加载,缩放手势,缓存复用缓存回收应有尽有,支持加载网络链接的大图。是一套很不错的加载大图的商业级方案,具体介绍可以看https://github.com/panpf/sketch
BitmapRegionDecoder
它的官方解释
很直白,加载一张图片的一部分。
使用也很简单。rect是一个显示区域,options是图片的设置项。这样就可以显示一张大图的的部分了。显示不同的区域,根据手势调整rect的区域即可。