http://blog.csdn.net/huangbiao86/article/details/9053429
这两天帮同事解决一个问题;
View.getDrawingCache获得数据始终为null,但是在某些设备上并不为null,纠结够 久啊,网上说了一些原因:
1) (mViewFlags & WILL_NOT_CACHE_DRAWING) == WILL_NOT_CACHE_DRAWING 这个值为true
2) (mViewFlags & DRAWING_CACHE_ENABLED) == DRAWING_CACHE_ENABLED 为false,buildDrawingCache没执行
3) buildDrawingCache执行失败
这些在源码中都可以看到,在获得缓存数据的时候,跟背景色(drawingCacheBackgroundColor),透明度 isOpaque,use32BitCache这些有关系,看是细看这些东西都是表面的,是系统在buildDrawingCache的时候,根据 View或都系统设置而来的;有些属性是不能更改的;这样一来当一个固定大小的View在不同的设备上生成的图片就可能有所不同,我同事这边存在的问题就 是,设置View的固定大小为1360*768,而我的设备分辨率为1024*600,而源码里可以看到这样代码:
- if (width <= 0 || height <= 0 ||
- // Projected bitmap size in bytes
- (width * height * (opaque && !use32BitCache ? 2 : 4) >
- ViewConfiguration.get(mContext).getScaledMaximumDrawingCacheSize())) {
- destroyDrawingCache();
- mCachingFailed = true;
- return;
- }
当我们在buildDrawingCache的时候,系统给了我们默认最大的DrawingCacheSize为屏幕宽*高*4;而我的View的 CacheSize大小超过了某些设备默认值,就会导致获得为空;开始想着用反射的方法去改变这些属性,或者设置背景颜色来改变图片质量,这样一来 CacheSize大小 就可能会变小,但是这样始终不能达到效果;
最终解决方案:
查看系统buildDrawingCache方法可以看到:
- public void buildDrawingCache(boolean autoScale) {
- if ((mPrivateFlags & DRAWING_CACHE_VALID) == 0 || (autoScale ?
- mDrawingCache == null : mUnscaledDrawingCache == null)) {
- mCachingFailed = false;
- if (ViewDebug.TRACE_HIERARCHY) {
- ViewDebug.trace(this, ViewDebug.HierarchyTraceType.BUILD_CACHE);
- }
- int width = mRight - mLeft;
- int height = mBottom - mTop;
- final AttachInfo attachInfo = mAttachInfo;
- final boolean scalingRequired = attachInfo != null && attachInfo.mScalingRequired;
- if (autoScale && scalingRequired) {
- width = (int) ((width * attachInfo.mApplicationScale) + 0.5f);
- height = (int) ((height * attachInfo.mApplicationScale) + 0.5f);
- }
- final int drawingCacheBackgroundColor = mDrawingCacheBackgroundColor;
- final boolean opaque = drawingCacheBackgroundColor != 0 || isOpaque();
- final boolean use32BitCache = attachInfo != null && attachInfo.mUse32BitDrawingCache;
- if (width <= 0 || height <= 0 ||
- // Projected bitmap size in bytes
- (width * height * (opaque && !use32BitCache ? 2 : 4) >
- ViewConfiguration.get(mContext).getScaledMaximumDrawingCacheSize())) {
- destroyDrawingCache();
- mCachingFailed = true;
- return;
- }
- boolean clear = true;
- Bitmap bitmap = autoScale ? mDrawingCache : mUnscaledDrawingCache;
- if (bitmap == null || bitmap.getWidth() != width || bitmap.getHeight() != height) {
- Bitmap.Config quality;
- if (!opaque) {
- // Never pick ARGB_4444 because it looks awful
- // Keep the DRAWING_CACHE_QUALITY_LOW flag just in case
- switch (mViewFlags & DRAWING_CACHE_QUALITY_MASK) {
- case DRAWING_CACHE_QUALITY_AUTO:
- quality = Bitmap.Config.ARGB_8888;
- break;
- case DRAWING_CACHE_QUALITY_LOW:
- quality = Bitmap.Config.ARGB_8888;
- break;
- case DRAWING_CACHE_QUALITY_HIGH:
- quality = Bitmap.Config.ARGB_8888;
- break;
- default:
- quality = Bitmap.Config.ARGB_8888;
- break;
- }
- } else {
- // Optimization for translucent windows
- // If the window is translucent, use a 32 bits bitmap to benefit from memcpy()
- quality = use32BitCache ? Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565;
- }
- // Try to cleanup memory
- if (bitmap != null) bitmap.recycle();
- try {
- bitmap = Bitmap.createBitmap(width, height, quality);
- bitmap.setDensity(getResources().getDisplayMetrics().densityDpi);
- if (autoScale) {
- mDrawingCache = bitmap;
- } else {
- mUnscaledDrawingCache = bitmap;
- }
- if (opaque && use32BitCache) bitmap.setHasAlpha(false);
- } catch (OutOfMemoryError e) {
- // If there is not enough memory to create the bitmap cache, just
- // ignore the issue as bitmap caches are not required to draw the
- // view hierarchy
- if (autoScale) {
- mDrawingCache = null;
- } else {
- mUnscaledDrawingCache = null;
- }
- mCachingFailed = true;
- return;
- }
- clear = drawingCacheBackgroundColor != 0;
- }
- Canvas canvas;
- if (attachInfo != null) {
- canvas = attachInfo.mCanvas;
- if (canvas == null) {
- canvas = new Canvas();
- }
- canvas.setBitmap(bitmap);
- // Temporarily clobber the cached Canvas in case one of our children
- // is also using a drawing cache. Without this, the children would
- // steal the canvas by attaching their own bitmap to it and bad, bad
- // thing would happen (invisible views, corrupted drawings, etc.)
- attachInfo.mCanvas = null;
- } else {
- // This case should hopefully never or seldom happen
- canvas = new Canvas(bitmap);
- }
- if (clear) {
- bitmap.eraseColor(drawingCacheBackgroundColor);
- }
- computeScroll();
- final int restoreCount = canvas.save();
- if (autoScale && scalingRequired) {
- final float scale = attachInfo.mApplicationScale;
- canvas.scale(scale, scale);
- }
- canvas.translate(-mScrollX, -mScrollY);
- mPrivateFlags |= DRAWN;
- if (mAttachInfo == null || !mAttachInfo.mHardwareAccelerated ||
- mLayerType != LAYER_TYPE_NONE) {
- mPrivateFlags |= DRAWING_CACHE_VALID;
- }
- // Fast path for layouts with no backgrounds
- if ((mPrivateFlags & SKIP_DRAW) == SKIP_DRAW) {
- if (ViewDebug.TRACE_HIERARCHY) {
- ViewDebug.trace(this, ViewDebug.HierarchyTraceType.DRAW);
- }
- mPrivateFlags &= ~DIRTY_MASK;
- dispatchDraw(canvas);
- } else {
- draw(canvas);
- }
- canvas.restoreToCount(restoreCount);
- canvas.setBitmap(null);
- if (attachInfo != null) {
- // Restore the cached Canvas for our siblings
- attachInfo.mCanvas = canvas;
- }
- }
- }
- /**
- * Create a snapshot of the view into a bitmap. We should probably make
- * some form of this public, but should think about the API.
- */
- Bitmap createSnapshot(Bitmap.Config quality, int backgroundColor, boolean skipChildren) {
- int width = mRight - mLeft;
- int height = mBottom - mTop;
- final AttachInfo attachInfo = mAttachInfo;
- final float scale = attachInfo != null ? attachInfo.mApplicationScale : 1.0f;
- width = (int) ((width * scale) + 0.5f);
- height = (int) ((height * scale) + 0.5f);
- Bitmap bitmap = Bitmap.createBitmap(width > 0 ? width : 1, height > 0 ? height : 1, quality);
- if (bitmap == null) {
- throw new OutOfMemoryError();
- }
- Resources resources = getResources();
- if (resources != null) {
- bitmap.setDensity(resources.getDisplayMetrics().densityDpi);
- }
- Canvas canvas;
- if (attachInfo != null) {
- canvas = attachInfo.mCanvas;
- if (canvas == null) {
- canvas = new Canvas();
- }
- canvas.setBitmap(bitmap);
- // Temporarily clobber the cached Canvas in case one of our children
- // is also using a drawing cache. Without this, the children would
- // steal the canvas by attaching their own bitmap to it and bad, bad
- // things would happen (invisible views, corrupted drawings, etc.)
- attachInfo.mCanvas = null;
- } else {
- // This case should hopefully never or seldom happen
- canvas = new Canvas(bitmap);
- }
- if ((backgroundColor & 0xff000000) != 0) {
- bitmap.eraseColor(backgroundColor);
- }
- computeScroll();
- final int restoreCount = canvas.save();
- canvas.scale(scale, scale);
- canvas.translate(-mScrollX, -mScrollY);
- // Temporarily remove the dirty mask
- int flags = mPrivateFlags;
- mPrivateFlags &= ~DIRTY_MASK;
- // Fast path for layouts with no backgrounds
- if ((mPrivateFlags & SKIP_DRAW) == SKIP_DRAW) {
- dispatchDraw(canvas);
- } else {
- draw(canvas);
- }
- mPrivateFlags = flags;
- canvas.restoreToCount(restoreCount);
- canvas.setBitmap(null);
- if (attachInfo != null) {
- // Restore the cached Canvas for our siblings
- attachInfo.mCanvas = canvas;
- }
- return bitmap;
- }
生成DrawingCache的过程貌似就是利用获得View的Canvas然后画到bitmap上,直接返回对应 的bitmap,这样一来,就是我们用getDrawingCache获得的bitmap;跟我们直接将View画到bitmap貌似区别 不是很大,受启发;如下:
自己生成Bitmap;
- public static Bitmap loadBitmapFromView(View v, boolean isParemt) {
- if (v == null) {
- return null;
- }
- Bitmap screenshot;
- screenshot = Bitmap.createBitmap(v.getWidth(), v.getHeight(), HDConstantSet.BITMAP_QUALITY);
- Canvas c = new Canvas(screenshot);
- v.draw(c);
- return screenshot;
- }
这样也就将View生成了我们需要的bitmap了,但是有些情况下:比如ViewPager在用getDrawingCache和我自己生成的 Bitmap时候,会有区别,ViewPager第一屏是正常的,滑动到第二屏幕的时候,我手动生成的Bitmap不见了,而系统 getDrawingCache方法生成 的Bitmap是可见的,郁闷,,,详细看了一下系统buildDrawingCache访求,发现在Canvas绘制Bitmap之后,多了一个步骤:
- computeScroll();
- final int restoreCount = canvas.save();
- canvas.scale(scale, scale);
- canvas.translate(-mScrollX, -mScrollY);
很明显,系统Canvas,对默认位置进行了移动,即启发:我们在用哥滑动View获得它的Bitmap时候,获得的是整个View的区域(包括隐藏的),如果想得到当前区域,需要重新定位到当前可显示的区域;自己的代码修改:
- public static Bitmap loadBitmapFromView(View v, boolean isParemt) {
- if (v == null) {
- return null;
- }
- Bitmap screenshot;
- screenshot = Bitmap.createBitmap(v.getWidth(), v.getHeight(), HDConstantSet.BITMAP_QUALITY);
- Canvas c = new Canvas(screenshot);
- c.translate(-v.getScrollX(), -v.getScrollY());
- v.draw(c);
- return screenshot;
- }
完美解决用自己生成 的Bitmap替换系统的getDrawingCache()方法;
当然系统getDrawingCache()考虑的因素很多,这一些我们也可以自己直接定义,比如透明磁,大小 ,图片质量等;最重要就是
- c.translate(-v.getScrollX(), -v.getScrollY());
这行一代码需要理解 ;
上面个人见解,如有理解不对的地方,大神留言指导啊........
相关推荐
Bitmap bitmap = view.getDrawingCache(); return bitmap; } ``` 这里,我们首先调用`buildDrawingCache`使View生成一个内部的DrawingCache,然后通过`getDrawingCache`获取Bitmap。这种方法简单直接,但有时可能...
方法1: 首先想到的思路是利用SDK提供的View.getDrawingCache()方法: public void printScreen(View view) { String imgPath = "/sdcard/test.png"; view.setDrawingCacheEnabled(true); view....
Android 中 android.view.WindowLeaked的解决办法 按字面了解,Window Leaked大概就是说一个窗体泄漏了,也就是我们常说的内存泄漏,为什么窗体会泄漏呢? 产生原因: 我们知道Android的每一个Activity都有个...
`pdfview.ocx`控件是专门用于处理PDF文件的一种组件,它允许开发者在应用程序中集成PDF阅读和操作功能,比如在C#和Wpf这样的环境中。在这个场景中,`pdfview.ocx`控件的一个关键特性是其无水印展示,这意味着用户...
Bitmap bitmap = view.getDrawingCache(); return bitmap; } ``` 在上面的代码中,我们首先需要启用View的绘制缓存,然后测量View的尺寸,接着将View布局到屏幕上,最后生成Bitmap对象。 但是,在使用View....
DDMS files not found traceview.bat问题,将traceview.bat文件放到SDK相应tools文件夹下,重启eclipse
Bitmap bitmap = Bitmap.createBitmap(view.getDrawingCache(), 0, 0, view.getMeasuredWidth(), view.getMeasuredHeight()); view.setDrawingCacheEnabled(false); view.destroyDrawingCache(); return bitmap;...
下载后放到你的SDK\tools下,重启eclipse就好了。如果你有其他的SDK,里面有该文件,直接复制进去也可以的。
`jsonview.exe`是一款实用工具,它允许用户以更直观的方式浏览和解析JSON格式的数据。在开发或调试过程中,这样的工具非常有用,因为它能将复杂的JSON结构转化为易于理解的形式,类似于JavaScript对象,使得开发者...
PDFView.ocx控件V1.30.3.0,很好用。本程序仅测试之用,请勿用于商业程序,否则责任自负
pdfview.ocx 破解版 大名鼎鼎的pdfviewer
Bitmap bitmap = view.getDrawingCache(); if (bitmap != null) { // 这里可以进一步处理Bitmap,如保存或合成 } view.setDrawingCacheEnabled(false); // 清除缓存 ``` 3. **处理Bitmap**: Bitmap是...
Bitmap bitmap = view.getDrawingCache(); return bitmap; } ``` 这种方法首先调用`buildDrawingCache()`使View缓存其绘制结果,然后通过`getDrawingCache()`获取Bitmap。然而,这种方法可能会遇到`...
PDFView.rar是一个压缩包文件,很可能包含了用于查看PDF文档的应用程序或代码示例。从标签和文件名可以推测,这可能是一个关于PDF查看器的开发资源,比如Android或iOS平台上的应用,或者是JavaScript等Web技术的实现...
"Android 兼容性问题:java.lang.UnsupportedOperationException解决办法" Android 兼容性问题:java.lang.UnsupportedOperationException解决办法是 Android 开发中常见的一种问题。该问题会导致应用程序崩溃,...
webView.measure(View.MeasureSpec.makeMeasureSpec(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED), View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED)); // 调用 layout 方法...
Android getBackground().setAlpha遇到问题解决办法 前言: 使用getBackground().setAlpha,导致其他布局背景透明度都改变的问题 从晚上9点就开始琢磨,为什么我在一个地方设置了getBackground().setAlpha(0);在别...
1. 首先,View.post() 会检查 mAttachInfo 是否为空,如果不为空,则调用 mAttachInfo.mHandler.post() 方法,这样可以将任务加入到消息队列中。 2. 如果 mAttachInfo 为空,则调用 getRunQueue().post() 方法,这样...