• View转换为Bitmap及getDrawingCache


     

     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

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

    DRAWING_CACHE_ENABLED是否支持设置

    先看getDrawingCache的源码

     1   public Bitmap getDrawingCache(boolean autoScale) {
     2         if ((mViewFlags & WILL_NOT_CACHE_DRAWING) == WILL_NOT_CACHE_DRAWING) {
     3             return null;
     4         }
     5         if ((mViewFlags & DRAWING_CACHE_ENABLED) == DRAWING_CACHE_ENABLED) {
     6             buildDrawingCache(autoScale);
     7         }
     8         return autoScale ? (mDrawingCache == null ? null : mDrawingCache.get()) :
     9                 (mUnscaledDrawingCache == null ? null : mUnscaledDrawingCache.get());
    10     }

    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,而源码里可以看到这样代码:

     

    1 if (width <= 0 || height <= 0 ||  
    2                     // Projected bitmap size in bytes  
    3                    (width * height * (opaque && !use32BitCache ? 2 : 4) >  
    4                            ViewConfiguration.get(mContext).getScaledMaximumDrawingCacheSize())) {  
    5                destroyDrawingCache();  
    6                mCachingFailed = true;  
    7                return;  
    8            }  


    当我们在buildDrawingCache的时候,系统给了我们默认最大的DrawingCacheSize为屏幕宽*高*4;而我的View的CacheSize大小超过了某些设备默认值,就会导致获得为空;开始想着用反射的方法去改变这些属性,或者设置背景颜色来改变图片质量,这样一来CacheSize大小 就可能会变小,但是这样始终不能达到效果; 

     

    最终解决方案:

    查看系统buildDrawingCache方法可以看到:

      1 public void buildDrawingCache(boolean autoScale) {
           //如果没有buildDrawingCache,则执行
    2 if ((mPrivateFlags & DRAWING_CACHE_VALID) == 0 || (autoScale ? 3 (mDrawingCache == null || mDrawingCache.get() == null) : 4 (mUnscaledDrawingCache == null || mUnscaledDrawingCache.get() == null))) { 5 6 if (ViewDebug.TRACE_HIERARCHY) { 7 ViewDebug.trace(this, ViewDebug.HierarchyTraceType.BUILD_CACHE); 8 } 9 if (Config.DEBUG && ViewDebug.profileDrawing) { 10 EventLog.writeEvent(60002, hashCode()); 11 } 12 13 int width = mRight - mLeft; 14 int height = mBottom - mTop; 15 16 final AttachInfo attachInfo = mAttachInfo; 17 final boolean scalingRequired = attachInfo != null && attachInfo.mScalingRequired; 18 19 if (autoScale && scalingRequired) { 20 width = (int) ((width * attachInfo.mApplicationScale) + 0.5f); 21 height = (int) ((height * attachInfo.mApplicationScale) + 0.5f); 22 } 23 24 final int drawingCacheBackgroundColor = mDrawingCacheBackgroundColor; 25 final boolean opaque = drawingCacheBackgroundColor != 0 || isOpaque(); 26 final boolean translucentWindow = attachInfo != null && attachInfo.mTranslucentWindow; 27    //不满足这些条件不执行
    28 if (width <= 0 || height <= 0 || 29 // Projected bitmap size in bytes 30 (width * height * (opaque && !translucentWindow ? 2 : 4) > 31 ViewConfiguration.get(mContext).getScaledMaximumDrawingCacheSize())) { 32 destroyDrawingCache(); 33 return; 34 } 35 36 boolean clear = true; 37 Bitmap bitmap = autoScale ? (mDrawingCache == null ? null : mDrawingCache.get()) : 38 (mUnscaledDrawingCache == null ? null : mUnscaledDrawingCache.get()); 39 40 if (bitmap == null || bitmap.getWidth() != width || bitmap.getHeight() != height) { 41 Bitmap.Config quality; 42 if (!opaque) { 43 switch (mViewFlags & DRAWING_CACHE_QUALITY_MASK) { 44 case DRAWING_CACHE_QUALITY_AUTO: 45 quality = Bitmap.Config.ARGB_8888; 46 break; 47 case DRAWING_CACHE_QUALITY_LOW: 48 quality = Bitmap.Config.ARGB_4444; 49 break; 50 case DRAWING_CACHE_QUALITY_HIGH: 51 quality = Bitmap.Config.ARGB_8888; 52 break; 53 default: 54 quality = Bitmap.Config.ARGB_8888; 55 break; 56 } 57 } else { 58 // Optimization for translucent windows 59 // If the window is translucent, use a 32 bits bitmap to benefit from memcpy() 60 quality = translucentWindow ? Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565; 61 } 62 63 // Try to cleanup memory 64 if (bitmap != null) bitmap.recycle(); 65 66 try { 67 bitmap = Bitmap.createBitmap(width, height, quality); 68 bitmap.setDensity(getResources().getDisplayMetrics().densityDpi); 69 if (autoScale) { 70 mDrawingCache = new SoftReference<Bitmap>(bitmap); 71 } else { 72 mUnscaledDrawingCache = new SoftReference<Bitmap>(bitmap); 73 } 74 if (opaque && translucentWindow) bitmap.setHasAlpha(false); 75 } catch (OutOfMemoryError e) { 76 // If there is not enough memory to create the bitmap cache, just 77 // ignore the issue as bitmap caches are not required to draw the 78 // view hierarchy 79 if (autoScale) { 80 mDrawingCache = null; 81 } else { 82 mUnscaledDrawingCache = null; 83 } 84 return; 85 } 86 87 clear = drawingCacheBackgroundColor != 0; 88 } 89 90 Canvas canvas; 91 if (attachInfo != null) { 92 canvas = attachInfo.mCanvas; 93 if (canvas == null) { 94 canvas = new Canvas(); 95 } 96 canvas.setBitmap(bitmap); 97 // Temporarily clobber the cached Canvas in case one of our children 98 // is also using a drawing cache. Without this, the children would 99 // steal the canvas by attaching their own bitmap to it and bad, bad 100 // thing would happen (invisible views, corrupted drawings, etc.) 101 attachInfo.mCanvas = null; 102 } else { 103 // This case should hopefully never or seldom happen 104 canvas = new Canvas(bitmap); 105 } 106 107 if (clear) { 108 bitmap.eraseColor(drawingCacheBackgroundColor); 109 } 110 111 computeScroll(); 112 final int restoreCount = canvas.save(); 113 114 if (autoScale && scalingRequired) { 115 final float scale = attachInfo.mApplicationScale; 116 canvas.scale(scale, scale); 117 } 118 119 canvas.translate(-mScrollX, -mScrollY); 120 121 mPrivateFlags |= DRAWN; 122 mPrivateFlags |= DRAWING_CACHE_VALID; 123 124 // Fast path for layouts with no backgrounds 125 if ((mPrivateFlags & SKIP_DRAW) == SKIP_DRAW) { 126 if (ViewDebug.TRACE_HIERARCHY) { 127 ViewDebug.trace(this, ViewDebug.HierarchyTraceType.DRAW); 128 } 129 mPrivateFlags &= ~DIRTY_MASK; 130 dispatchDraw(canvas); 131 } else { 132 draw(canvas); 133 } 134 135 canvas.restoreToCount(restoreCount); 136 137 if (attachInfo != null) { 138 // Restore the cached Canvas for our siblings 139 attachInfo.mCanvas = canvas; 140 } 141 } 142 }

     安卓提供了方法,这个方法没有提供一个外部访问方法

     1  /**
     2      * Create a snapshot of the view into a bitmap.  We should probably make
     3      * some form of this public, but should think about the API.
     4      */
     5     Bitmap createSnapshot(Bitmap.Config quality, int backgroundColor, boolean skipChildren) {
     6         int width = mRight - mLeft;
     7         int height = mBottom - mTop;
     8 
     9         final AttachInfo attachInfo = mAttachInfo;
    10         final float scale = attachInfo != null ? attachInfo.mApplicationScale : 1.0f;
    11         width = (int) ((width * scale) + 0.5f);
    12         height = (int) ((height * scale) + 0.5f);
    13         
    14         Bitmap bitmap = Bitmap.createBitmap(width > 0 ? width : 1, height > 0 ? height : 1, quality);
    15         if (bitmap == null) {
    16             throw new OutOfMemoryError();
    17         }
    18 
    19         bitmap.setDensity(getResources().getDisplayMetrics().densityDpi);
    20         
    21         Canvas canvas;
    22         if (attachInfo != null) {
    23             canvas = attachInfo.mCanvas;
    24             if (canvas == null) {
    25                 canvas = new Canvas();
    26             }
    27             canvas.setBitmap(bitmap);
    28             // Temporarily clobber the cached Canvas in case one of our children
    29             // is also using a drawing cache. Without this, the children would
    30             // steal the canvas by attaching their own bitmap to it and bad, bad
    31             // things would happen (invisible views, corrupted drawings, etc.)
    32             attachInfo.mCanvas = null;
    33         } else {
    34             // This case should hopefully never or seldom happen
    35             canvas = new Canvas(bitmap);
    36         }
    37 
    38         if ((backgroundColor & 0xff000000) != 0) {
    39             bitmap.eraseColor(backgroundColor);
    40         }
    41 
    42         computeScroll();
    43         final int restoreCount = canvas.save();
    44         canvas.scale(scale, scale);
    45         canvas.translate(-mScrollX, -mScrollY);
    46 
    47         // Temporarily remove the dirty mask
    48         int flags = mPrivateFlags;
    49         mPrivateFlags &= ~DIRTY_MASK;
    50 
    51         // Fast path for layouts with no backgrounds
    52         if ((mPrivateFlags & SKIP_DRAW) == SKIP_DRAW) {
    53             dispatchDraw(canvas);
    54         } else {
    55             draw(canvas);
    56         }
    57 
    58         mPrivateFlags = flags;
    59 
    60         canvas.restoreToCount(restoreCount);
    61 
    62         if (attachInfo != null) {
    63             // Restore the cached Canvas for our siblings
    64             attachInfo.mCanvas = canvas;
    65         }
    66 
    67         return bitmap;
    68     }
    View Code
        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;
        }

     


     

     

  • 相关阅读:
    yii2.0数据库查询修改等方法
    yii2.0里自己写的源码上传图片
    解决yii2.0里url重写引用js路径问题(@web/的用法)
    yii2.0中解决post的400错误
    yii2.0用gii自动补全代码做的简单增删改查,以及图片上传和展示
    yii2.0中url重写实现方法
    (转)openssl 命令: openssl req 命令详解
    Nodejs搭建音视频通信-信令服务器 总结
    【转】阿里架构总监一次讲透中台架构,13页PPT精华详解
    (转)SSL工作原理
  • 原文地址:https://www.cnblogs.com/mingfeng002/p/3305051.html
Copyright © 2020-2023  润新知