View组件显示的内容可以通过cache机制保存为bitmap, 使用到的api有

void  setDrawingCacheEnabled(boolean flag),
    Bitmap  getDrawingCache(boolean autoScale),
    void  buildDrawingCache(boolean autoScale),
    void  destroyDrawingCache()

  • 我们要获取它的cache先要通过setDrawingCacheEnable方法把cache开启,
  • 然后再调用getDrawingCache方法就可以获得view的cache图片了。
  • buildDrawingCache方法可以不用调用,因为调用getDrawingCache方法时,若果cache没有建立,系统会自动调用buildDrawingCache方法生成cache。若果要更新cache, 必须要调用destoryDrawingCache方法把旧的cache销毁,才能建立新的。
  • 当调用setDrawingCacheEnabled方法设置为false, 系统也会自动把原来的cache销毁。

android 为了提高滚动等各方面的绘制速度,可以为每一个view建立一个缓存,使用 View.buildDrawingCache为自己的view 建立相应的缓存, 
这个所谓的缓存,实际上就是一个Bitmap对象。只是 这个 bitmap 对象可以有多种格式而已,如 
     Bitmap.Config.ARGB_8888; 
     Bitmap.Config.ARGB_4444; 
     Bitmap.Config.RGB_565; 
   默认的格式是Bitmap.Config.ARGB_8888.,但大多数嵌入式设备使用的显示格式都是Bitmap.Config.RGB_565. 对于后者, 并没有 
  alpha 值,所以绘制的时候不需要计算alpha合成,速递当让快些。其次,RGB_565可以直接使用优化了的memcopy函数,效率相对高出许多。

view的getDrawingCache获得数据始终为null

setDrawingCacheEnabled

 public void setDrawingCacheEnabled(boolean enabled) {
setFlags(enabled ? DRAWING_CACHE_ENABLED : 0, DRAWING_CACHE_ENABLED);
}

DRAWING_CACHE_ENABLED是否支持设置

先看getDrawingCache的源码

   public Bitmap getDrawingCache(boolean autoScale) {
if ((mViewFlags & WILL_NOT_CACHE_DRAWING) == WILL_NOT_CACHE_DRAWING) {
return null;
}
if ((mViewFlags & DRAWING_CACHE_ENABLED) == DRAWING_CACHE_ENABLED) {
buildDrawingCache(autoScale);
}
return autoScale ? (mDrawingCache == null ? null : mDrawingCache.get()) :
(mUnscaledDrawingCache == null ? null : mUnscaledDrawingCache.get());
}

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,而我View转换为Bitmap及getDrawingCache的设备分辨率为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) {
       //如果没有buildDrawingCache,则执行
if ((mPrivateFlags & DRAWING_CACHE_VALID) == 0 || (autoScale ?
(mDrawingCache == null || mDrawingCache.get() == null) :
(mUnscaledDrawingCache == null || mUnscaledDrawingCache.get() == null))) { if (ViewDebug.TRACE_HIERARCHY) {
ViewDebug.trace(this, ViewDebug.HierarchyTraceType.BUILD_CACHE);
}
if (Config.DEBUG && ViewDebug.profileDrawing) {
EventLog.writeEvent(60002, hashCode());
} 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 translucentWindow = attachInfo != null && attachInfo.mTranslucentWindow;
   //不满足这些条件不执行

if (width <= 0 || height <= 0 ||
// Projected bitmap size in bytes
(width * height * (opaque && !translucentWindow ? 2 : 4) >
ViewConfiguration.get(mContext).getScaledMaximumDrawingCacheSize())) {
destroyDrawingCache();
return;
}

boolean clear = true;
Bitmap bitmap = autoScale ? (mDrawingCache == null ? null : mDrawingCache.get()) :
(mUnscaledDrawingCache == null ? null : mUnscaledDrawingCache.get()); if (bitmap == null || bitmap.getWidth() != width || bitmap.getHeight() != height) {
Bitmap.Config quality;
if (!opaque) {
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_4444;
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 = translucentWindow ? 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 = new SoftReference<Bitmap>(bitmap);
} else {
mUnscaledDrawingCache = new SoftReference<Bitmap>(bitmap);
}
if (opaque && translucentWindow) 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;
}
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;
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); 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();
} bitmap.setDensity(getResources().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); if (attachInfo != null) {
// Restore the cached Canvas for our siblings
attachInfo.mCanvas = canvas;
} return bitmap;
}
    public static Bitmap getViewBitmap(View v) {
v.clearFocus();
v.setPressed(false);
boolean willNotCache = v.willNotCacheDrawing();
v.setWillNotCacheDrawing(false);
// Reset the drawing cache background color to fully transparent
// for the duration of this operation
int color = v.getDrawingCacheBackgroundColor();
v.setDrawingCacheBackgroundColor(0);
if (color != 0) {
v.destroyDrawingCache();
}
v.buildDrawingCache();
Bitmap cacheBitmap = v.getDrawingCache();
if (cacheBitmap == null) {
return null;
}
Bitmap bitmap = Bitmap.createBitmap(cacheBitmap);
v.destroyDrawingCache();
v.setWillNotCacheDrawing(willNotCache);
v.setDrawingCacheBackgroundColor(color);
return bitmap;
}

View转换为Bitmap及getDrawingCache的更多相关文章

  1. Android中View转换为Bitmap及getDrawingCache=null的解决方法

    1.前言 Android中经常会遇到把View转换为Bitmap的情形,比如,对整个屏幕视图进行截屏并生成图片:Coverflow中需要把一页一 页的view转换为Bitmap.以便实现复杂的图形效果 ...

  2. 获取View的截图-将View转换为Bitmap对象

    开发中,有时候需要获取View的截图来做动画来达到动画流程的目的 原理:将View的内容画到一个Bitmap画布上,然后取出 下面封装了一个从View生成Bitmap的工具类 /** * 将View转 ...

  3. android view 转Bitmap 生成截图

    文章链接:https://mp.weixin.qq.com/s/FQmYfT-KYiDbp-0HzK_Hpw 项目中经常会用到分享的功能,有分享链接也有分享图片,其中分享图片有的需要移动端对屏幕内容进 ...

  4. 读取sd卡下图片,由图片路径转换为bitmap

    public Bitmap convertToBitmap(String path, int w, int h) {             BitmapFactory.Options opts = ...

  5. Android,View转换bitmap,bitmap转换drawable

    Android View转换Bitmap,Bitmap转换Drawable //测试设置bitmap View view1 = ViewGroup.inflate(context, R.layout. ...

  6. Universal App图片文件和图片byte[]信息转换为bitmap

    1. 打开图片文件并转换为BitmapImage类 首先要做的自然是打开一个图片文件了,可以使用FileOpenPicker来手动选择图片,总之能拿到一个StorageFile都行. //打开图片选择 ...

  7. Android开发之常用必备工具类图片bitmap转成字符串string与String字符串转换为bitmap图片格式

    作者:程序员小冰,CSDN博客:http://blog.csdn.net/qq_21376985 QQ986945193 博客园主页:http://www.cnblogs.com/mcxiaobing ...

  8. 将View兑换Bitmap

    /** * 中间View保罗转化成Bitmap * */ private Bitmap saveViewBitmap(View view) { // get current view bitmap v ...

  9. Convert View To Bitmap

    public static Bitmap convertViewToBitmap(View view) { view.destroyDrawingCache(); view.measure(View. ...

随机推荐

  1. JS计算文件的md5

    首先需要引入js文件(二选一): https://raw.github.com/satazor/SparkMD5/master/spark-md5.js https://github.com/sata ...

  2. <正则吃饺子> :关于Java的native方法(转)

    感谢作者的分享,原文地址:http://blog.csdn.net/wike163/article/details/6635321 一. 什么是Native Method   简单地讲,一个Nativ ...

  3. linux命令-vim一般模式下复制剪切粘贴

    删除光标后的一个字符 x 删除光标前的一个字符 shift+x 删除指定个数的字符 数字+x 删除一行字符 dd 剪切指定行数  数字dd  3dd 剪切3行 其实并没有删掉而是保存着剪切板里 粘贴在 ...

  4. .net 缓存之数据库缓存依赖

    当监听的指定数据库内容某张表变化时就更新缓存 先来配置数据库,启动监听服务(SQL2008下) 执行如下语句: ALTER DATABASE OumindBlog SET NEW_BROKER WIT ...

  5. 分页sql汇总

    1.oracle数据库分页 select * from (select a.*,rownum rc from 表名 where rownum<=endrow) a where a.rc>= ...

  6. Dialog 基本使用

    1   :  效果图 btnGeneral.setOnClickListener(new View.OnClickListener() { @Override public void onClick( ...

  7. sell01 环境搭建、编写持久层并进行测试

    1 环境配置 JDK 1.8 MAVEN 3.5 MYSQL 5.7 VirtualBox 5.1 2 搭建MYSQL环境 下载 VM 和 虚拟镜像文件 虚拟镜像文件:点击前往 技巧01:安装完vir ...

  8. python+selenium UI自动化不同浏览器之间的切换

    class register(): ROBOT_LIBRARY_SCOPE = 'GLOBAL' def __init__(self): pass # m默认打开chrome def open_bro ...

  9. PLSQL Developer 直接用ip访问指定数据库

  10. 【linux学习-centeros】

    1:linux的目录结构: / root —?启动Linux时使用的一些核心文件.如操作系统内核.引导程序Grub等. home —?存储普通用户的个人文件 ftp — 用户所有服务 httpd sa ...