小伙伴们如果截取recycleview且item项中如果使用了异步加载框架,比如SimpleDraweeView,那么肯定会遇到SimpleDraweeView出现空白的尴尬场面,经过两天的摸索和多次的尝试,终于找到了方面的解决的问题
原因:在截图超过手机屏幕的时候我们使用的方法是重新绘制每个item项然后画在画布上从而生成一张bitmap,但是使用异步加载框架就会出现绘制完了图片还未加载出来的尴尬场面
解决:在截图时,将异步的加载换成同步的加载,阻塞绘制流程,只有等图片加载了才让其绘制,这样就不会有问题了,不过请注意要在子线程中完成,不然会引起anr哦
下面让我们一起来看实现:
1.首先我们定义一个adapter,里面有一个同步bind接口
public interface RecycleSyncAdapter {
void onBindViewHolderSync(RecyclerView.ViewHolder holder, int position);
}
2让我们的adapter去实现这个接口:
public class XXXAdapter extends RecyclerView.Adapter implements RecycleSyncAdapter {
//这里你原来怎么实现还是怎么实现,一点不影响
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
}
//这个就是你要实现的接口,将需要截屏处理的holder类型放在这里面处理
@Override
public void onBindViewHolderSync(RecyclerView.ViewHolder holder, int position) {
final RoundsUIModel model = mData.get(position);
switch (model.type) {
//假如我的就是ImageType类型
case ImageType: {
//todo,不管你怎么实现,反正最后实现下面这个方法
displayImageSync(uri,simpleDraweeView,failResId);
break;
}
}
}
}
3.最重要的阻塞你方法的实现,也就是将异步转化为同步的实现
public static void displayImageSync(Uri uri,final SimpleDraweeView draweeView, final int failResId) {
CountDownLatch countDownLatch = new CountDownLatch(1);
ImageRequestBuilder requestBuilder = ImageRequestBuilder.newBuilderWithSource(uri);
ImageRequest imageRequest = requestBuilder.build();
DataSource> dataSource = ImagePipelineFactory
.getInstance().getImagePipeline().fetchDecodedImage(imageRequest, null);
dataSource.subscribe(new BaseBitmapDataSubscriber() {
@Override
public void onNewResultImpl(final Bitmap bitmap) {
if (bitmap != null && !bitmap.isRecycled()) {
final Bitmap resultBitmap = bitmap.copy(bitmap.getConfig(),
bitmap.isMutable());
draweeView.setImageBitmap(resultBitmap);
countDownLatch.countDown();
}
}
@Override
public void onCancellation(DataSource> dataSource) {
super.onCancellation(dataSource);
draweeView.setImageResource(failResId);
countDownLatch.countDown();
}
@Override
public void onFailureImpl(DataSource dataSource) {
draweeView.setImageResource(failResId);
countDownLatch.countDown();
}
}, DefaultExecutor.getInstance().getExecutorService());
try {
countDownLatch.await();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
4.最最重要的的截屏函数来了,重中之重,这个函数一定要在子线程中运行,切记切记
public static Bitmap shotRecyclerView(RecyclerView view) {
RecyclerView.Adapter adapter = view.getAdapter();
Bitmap bigBitmap = null;
if (adapter != null) {
int size = adapter.getItemCount();
int height = 0;
Paint paint = new Paint();
int iHeight = 0;
final int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);
// Use 1/8th of the available memory for this memory cache.
final int cacheSize = maxMemory / 8;
LruCache bitmaCache = new LruCache<>(cacheSize);
for (int i = 0; i < size; i++) {
RecyclerView.ViewHolder holder = adapter.createViewHolder(view, adapter.getItemViewType(i));
//这一行重要,区别出同步还是异步
((RecycleSyncAdapter) adapter).onBindViewHolderSync(holder, i);
holder.itemView.measure(
View.MeasureSpec.makeMeasureSpec(view.getWidth(), View.MeasureSpec.EXACTLY),
View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));
holder.itemView.layout(0, 0, holder.itemView.getMeasuredWidth(),
holder.itemView.getMeasuredHeight());
holder.itemView.setDrawingCacheEnabled(true);
holder.itemView.buildDrawingCache();
Bitmap drawingCache = loadBitmapFromView(holder.itemView);
if (drawingCache != null) {
bitmaCache.put(String.valueOf(i), drawingCache);
}
height += holder.itemView.getMeasuredHeight();
}
bigBitmap = Bitmap.createBitmap(view.getMeasuredWidth(), height, Bitmap.Config.RGB_565);
Canvas bigCanvas = new Canvas(bigBitmap);
Drawable lBackground = view.getBackground();
if (lBackground instanceof ColorDrawable) {
ColorDrawable lColorDrawable = (ColorDrawable) lBackground;
int lColor = lColorDrawable.getColor();
bigCanvas.drawColor(lColor);
}
for (int i = 0; i < size; i++) {
Bitmap bitmap = bitmaCache.get(String.valueOf(i));
bigCanvas.drawBitmap(bitmap, 0f, iHeight, paint);
iHeight += bitmap.getHeight();
bitmap.recycle();
}
}
return bigBitmap;
}
以上就是recycleview截屏全方案,关键是理解造成它的原因以及解决办法的原理,祝大家顺利解决,如果有用请点个赞,转载请注明出处,谢谢!!!