扯扯淡
最近研究了幾個便簽app兼砖,主要是做富文本編輯奸远。通過root的手機(jī)可以了解了錘子便簽和魅族便簽的存儲方式,其中魅族便簽采用的應(yīng)該是recyclerView的多種布局方案讽挟,當(dāng)然我也選用的這種方案懒叛,同步對便簽的不斷完善,這個過程可以涉及很多知識的深入處理耽梅,圖片芍瑞、音視頻等等,全面知識的融合褐墅。
開始截圖
在網(wǎng)上找了一些解決方案拆檬,實(shí)踐了其中一種對每個item進(jìn)行截圖然后拼到一個大的bitmap中,但是這樣會遇到單個item過長引起oom妥凳,系統(tǒng)為了避免這個問題的出現(xiàn)竟贯,直接在buildDrawingCacheImpl方法中進(jìn)行了限制,這樣獲取的DrawingCache就為null
final long projectedBitmapSize = width * height * (opaque && !use32BitCache ? 2 : 4);
final long drawingCacheSize =
ViewConfiguration.get(mContext).getScaledMaximumDrawingCacheSize();
if (width <= 0 || height <= 0 || projectedBitmapSize > drawingCacheSize) {
if (width > 0 && height > 0) {
Log.w(VIEW_LOG_TAG, getClass().getSimpleName() + " not displayed because it is"
+ " too large to fit into a software layer (or drawing cache), needs "
+ projectedBitmapSize + " bytes, only "
+ drawingCacheSize + " available");
}
destroyDrawingCache();
mCachingFailed = true;
return;
}
然后只能采取滾動截圖的方式進(jìn)行截圖逝钥,引用網(wǎng)上的圖屑那,原理如此
image
上代碼(還需要review,重構(gòu))
@MainThread
public void screenShot(List<EditBaseCell> data, RecyclerView mRecyclerView) {
if (data == null || data.isEmpty() || mRecyclerView == null) {
return;
}
Paint paint = new Paint();
bitmapList = new ArrayList<>();
int measuredHeight = mRecyclerView.getMeasuredHeight();
WLog.e(TAG, "measureHeight:" + measuredHeight);
int shotHeight = 0;
//每個item計(jì)算高度時需要重新onBindViewHolder
for (EditBaseCell cell : data) {
shotHeight += cell.getHeight(mRecyclerView);
}
while (mRecyclerView.canScrollVertically(-1)) {
mRecyclerView.scrollBy(0, -measuredHeight);
}
//繪制截圖的背景
Bitmap bigBitmap = Bitmap.createBitmap(mRecyclerView.getMeasuredWidth(), shotHeight, Bitmap.Config.RGB_565);
Canvas bigCanvas = new Canvas(bigBitmap);
Drawable lBackground = mRecyclerView.getBackground();
if (lBackground instanceof ColorDrawable) {
ColorDrawable lColorDrawable = (ColorDrawable) lBackground;
int lColor = lColorDrawable.getColor();
bigCanvas.drawColor(lColor);
}
int drawOffset = 0;
while (mRecyclerView.canScrollVertically(1)) {
WLog.e(TAG, "drawOffset" + drawOffset);
//每次重新獲取新的布局
mRecyclerView.setDrawingCacheEnabled(true);
// getDrawingCache()中已經(jīng)調(diào)用
// mRecyclerView.buildDrawingCache();
Bitmap bitmap = mRecyclerView.getDrawingCache();
//調(diào)用這個方法會銷毀當(dāng)前的bitmap cache
// mRecyclerView.setDrawingCacheEnabled(false);
bigCanvas.drawBitmap(bitmap, 0, drawOffset, paint);
drawOffset += measuredHeight;
mRecyclerView.scrollBy(0, measuredHeight);
}
//不足一屏?xí)r的處理
int top = measuredHeight - (shotHeight - drawOffset);
WLog.e(TAG, "last" + top);
if (top > 0) {
mRecyclerView.setDrawingCacheEnabled(true);
Bitmap bitmap = mRecyclerView.getDrawingCache();
bigCanvas.drawBitmap(bitmap, new Rect(0, top, bitmap.getWidth(), bitmap.getHeight()),
new Rect(0, drawOffset, bigBitmap.getWidth(), bigBitmap.getHeight()), paint);
}
//恢復(fù)位置艘款,可以先放置一張截圖持际,或者是創(chuàng)建一個新的recyclerView來截圖,同時可以截圖時進(jìn)行不同的處理
// while (mRecyclerView.canScrollVertically(-1)) {
// mRecyclerView.scrollBy(0, -measuredHeight);
// }
// mRecyclerView.scrollBy(0, scrollOffset);
// int i1 = scrollOffset / measuredHeight;
// for (int i = 0; i < i1; i++) {
// mRecyclerView.scrollBy(0, measuredHeight);
// }
// 保存圖片哗咆,回調(diào)主線程
Observable.create(new ObservableOnSubscribe<Boolean>() {
@Override
public void subscribe(ObservableEmitter<Boolean> e) throws Exception {
ImageUtil.saveBitmap(DirsUtils.getDir(DirsUtils.PICS) + "screenShot.jpeg", bigBitmap);
e.onNext(true);
}
}).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(new Consumer<Boolean>() {
@Override
public void accept(Boolean aBoolean) throws Exception {
ToastUtils.makeTextShort("screen shot ok");
mRecyclerView.destroyDrawingCache();
BitmapTools.recycleBitmap(bigBitmap);
// for (Bitmap bitmap:bitmapList){
// BitmapTools.recycleBitmap(bitmap);
// }
//
// bitmapList = null;
}
});
}
代碼中只是粗略的實(shí)現(xiàn)了截圖的功能蜘欲,測試截圖達(dá)到5M很長的圖片依然不會出現(xiàn)crash的現(xiàn)象,在內(nèi)存回收方面晌柬,雖然在內(nèi)存不足時會回收姥份,但是不能進(jìn)行一個及時的回收郭脂,還需要繼續(xù)跟進(jìn)。
getDrawingCache獲取的bitmao在自己處理回收時會發(fā)生RuntimeException,通過分析源碼可以看到澈歉,系統(tǒng)是有自己的回收處理的展鸡,可以不再進(jìn)行處理。
任務(wù)還在繼續(xù)
- 截圖時埃难,隱藏或規(guī)避滾動莹弊,嘗試新建一個recyclerView處理截圖的數(shù)據(jù)并且方便給便簽加上水印等處理,類似錘子便簽中分享圖片的處理
- 加入padding涡尘,margin的處理
- 提取更通用的截圖工具類