Android中如何用Picasso加载数据库中的Bitmap图片?
嘿,我懂你的困扰——Picasso的load()方法默认确实没有直接接受Bitmap对象的重载,你直接调用load(bitmapArray.get(i))肯定会报错。不过咱们有几个实用的方案,既能用上Picasso的resize、缓存这些特性,又能加载你从数据库解码出来的Bitmap数组。
方案一:将Bitmap转为ByteArrayInputStream加载
这是最快实现的方式,只需要把Bitmap转换成字节输入流,就能让Picasso识别并加载:
首先添加一个工具方法,把Bitmap转成字节数组:
private byte[] bitmapToByteArray(Bitmap bitmap) { ByteArrayOutputStream stream = new ByteArrayOutputStream(); // 这里可以根据需求改压缩格式和质量,比如JPG+80质量会更省内存 bitmap.compress(Bitmap.CompressFormat.PNG, 100, stream); return stream.toByteArray(); }
然后修改适配器的onBindViewHolder方法:
@Override public void onBindViewHolder(RecyclerDataAdapter.ViewHolder viewHolder, int i) { Bitmap targetBitmap = bitmapArray.get(i); ByteArrayInputStream inputStream = new ByteArrayInputStream(bitmapToByteArray(targetBitmap)); Picasso.with(context) .load(inputStream) .resize(240, 120) // 还可以加占位符、错误图等Picasso特性 // .placeholder(R.drawable.loading) // .error(R.drawable.error) .into(viewHolder.img_android); }
这种方式的好处是快速上手,不需要额外的类,但每次都要压缩Bitmap,对性能有一点点影响,适合小范围使用。
方案二:自定义RequestHandler扩展Picasso(推荐复用场景)
如果你的项目里经常需要用Picasso加载Bitmap,那自定义一个RequestHandler会更优雅,相当于给Picasso增加了直接加载Bitmap的能力:
首先创建一个BitmapRequestHandler类:
public class BitmapRequestHandler extends RequestHandler { // 自定义一个Uri协议,用来标识这是Bitmap请求 private static final String SCHEME_BITMAP = "bitmap"; @Override public boolean canHandleRequest(Request data) { // 判断是否是我们自定义的Bitmap请求 return SCHEME_BITMAP.equals(data.uri.getScheme()); } @Override public Result load(Request request, int networkPolicy) throws IOException { // 从tag中取出Bitmap对象 Bitmap bitmap = (Bitmap) request.tag; // 返回加载结果,标记为从磁盘加载(也可以根据实际情况改) return new Result(bitmap, Picasso.LoadedFrom.DISK); } // 生成对应的Uri,用来告诉Picasso用我们的Handler处理 public static Uri createBitmapUri(Bitmap bitmap) { return new Uri.Builder() .scheme(SCHEME_BITMAP) // 用Bitmap的哈希值作为host,确保Uri唯一 .host(String.valueOf(bitmap.hashCode())) .build(); } }
然后在你的Application初始化或者第一次使用Picasso的地方,注册这个Handler:
// 全局注册,一次注册到处能用 Picasso picasso = Picasso.with(getApplicationContext()); picasso.addRequestHandler(new BitmapRequestHandler());
最后修改适配器的加载逻辑:
@Override public void onBindViewHolder(RecyclerDataAdapter.ViewHolder viewHolder, int i) { Bitmap targetBitmap = bitmapArray.get(i); Picasso.with(context) .load(BitmapRequestHandler.createBitmapUri(targetBitmap)) .tag(targetBitmap) // 把Bitmap作为tag传进去 .resize(240, 120) .into(viewHolder.img_android); }
这个方案的优势是扩展性强,以后任何地方都能直接用Picasso加载Bitmap,还能充分利用Picasso的缓存机制,适合频繁使用的场景。
方案三:直接用ImageView显示(无需Picasso额外功能)
如果你只是想显示Bitmap,不需要Picasso的占位符、内存缓存等特性,那直接用ImageView的setImageBitmap最直接,还能省掉Picasso的转换开销:
@Override public void onBindViewHolder(RecyclerDataAdapter.ViewHolder viewHolder, int i) { Bitmap targetBitmap = bitmapArray.get(i); // 先对Bitmap进行缩放,达到你要的240x120尺寸 Bitmap resizedBitmap = Bitmap.createScaledBitmap(targetBitmap, 240, 120, true); viewHolder.img_android.setImageBitmap(resizedBitmap); }
不过要注意,这种方式需要自己管理Bitmap的内存,避免在RecyclerView滑动时出现内存泄漏或者OOM,最好配合Bitmap的回收机制使用。
内容的提问来源于stack exchange,提问作者gorp88

