当前位置: 首页 > news >正文

长春建站推荐大墨免费空间申请

长春建站推荐,大墨免费空间申请,网站设计公司竞争优势,住房和城乡建设部网站公布信息前言Hardware Bitmap(硬件位图)是Android8.0加入的新功能#xff0c;通过设置Bitmap的config为Bitmap.Config.HARDWARE#xff0c;创建所谓的Hardware Bitmap#xff0c;它不同与其他Config的Bitmap#xff0c;Hardware Bitmap对应的像素数据是存储在显存中#xff0c;并对…前言Hardware Bitmap(硬件位图)是Android8.0加入的新功能通过设置Bitmap的config为Bitmap.Config.HARDWARE创建所谓的Hardware Bitmap它不同与其他Config的BitmapHardware Bitmap对应的像素数据是存储在显存中并对图片仅在屏幕上绘制的场景做了优化硬件位图的介绍参考Glide文档何如使用Hardware Bitmap创建Hardware Bitmap众所周知Bitmap的创建一般是调用BitmapFactory这个工厂类来实现由于Hardware Bitmap需要配置Bitmap.Config.HARDWARE属性一个基本的获取用Hardware Bitmap的写法如下val options BitmapFactory.Options()options.inPreferredConfig Bitmap.Config.HARDWAREval bitmap BitmapFactory.decodeResource(resources, R.drawable.dog, options)复制代码主要是需要设置BitmapFactory.Options的inPreferredConfig为Bitmap.Config.HARDWARE针对HARDWARE情况BitmapFactory的提示如果设置了inPreferredConfig Bitmap.Config.HARDWARE千万不要设置options.inMutable true这样会引起报错因为Hardware Bitmap是不可变的也不能被利用另外inBitmap属性也没有必要设置因为硬件位图不需要当前进程的缓存复用如果设置inBitmap可能会替换掉之前设置的inPreferredConfig属性;使用Hardware Bitmap通过上一步的创建我们获得Bitmap对象首先我们可以通过bitmap.getConfig()获取到当前Bitmap是不是Hardware其次大多数情况下我们是把Bitmap设置给ImageView控件imageView.setImageBitmap(bitmap)复制代码一行代码搞定imageView没错这行代码一般情况下是没有问题的那么问题在哪里首先硬件位图只支持GPU的绘制言外之意是这个ImageView必须在开启硬件加速的Activity中而且当前这个ImageView不能设置软件层 (software layer type)开启硬件加速的代码//application级别开启硬件加速//activity级别开启硬件加速复制代码在View 上使用software layer typeImageView imageView …imageView.setImageBitmap(hardwareBitmap);imageView.setLayerType(View.LAYER_TYPE_SOFTWARE, null);复制代码如果我们满足硬件加速和不设置software layer type这两个条件在正真使用中还有坑其中最大的也最频繁发生的就是通过Canvas来改变Bitmap的形状或者其他的转换拿圆形图片做例子假设我们需要显示圆形图片一般解决方案有两种通过自定义控件处理和通过Glide等工具类直接剪裁Bitmap当Bitmap剪裁遇到HARDWARE就是问题的开始通过自定义控件比如CircleImageView的方案onDraw()方法如下Overrideprotected void onDraw(Canvas canvas) {if (mDisableCircularTransformation) {super.onDraw(canvas);return;}if (mBitmap null) {return;}if (mCircleBackgroundColor ! Color.TRANSPARENT) {canvas.drawCircle(mDrawableRect.centerX(), mDrawableRect.centerY(), mDrawableRadius, mCircleBackgroundPaint);}canvas.drawCircle(mDrawableRect.centerX(), mDrawableRect.centerY(), mDrawableRadius, mBitmapPaint);if (mBorderWidth 0) {canvas.drawCircle(mBorderRect.centerX(), mBorderRect.centerY(), mBorderRadius, mBorderPaint);}}复制代码这是CircleImageView重新onDraw()方法通过自定义控件实现剪切圆角在设置硬件位图Bitmap时一般都没有问题通过类似Glide等直接处理Bitmap的方式剪裁圆形图片基本代码如下:Canvas canvas new Canvas(resultBitmap);// Draw a circlecanvas.drawCircle(radius, radius, radius, CIRCLE_CROP_SHAPE_PAINT);// Draw the bitmap in the circlecanvas.drawBitmap(inBitmap, null, destRect, CIRCLE_CROP_BITMAP_PAINT);clear(canvas);复制代码通过类似工具类的形式直接对Bitmap进行修改执行到canvas.drawBitmap就会报异常异常信息是java.lang.IllegalStateException: Software rendering doesnt support hardware bitmaps;如何避免报异常我大致想了这么两个方案方案一所有关于剪切Bitmap的操作都改成自定义控件在自定义控件的onDraw中实现方案二寻找一种方案解决掉自己创建的Canvas不报异常这样就能继续用工具类来处理Bitmap方案一技术实现比较简单把项目中所用用到处理Bitmap的逻辑都换成自定义控件但是可能涉及到很多处代码的修改是一个功夫活方案二实施起来有点障碍因为除了通过new Canvas(Bitmap)获取画布还能通过什么方式能拿到Canvas对了还有SurfaceView也是可以拿到Canvas但是SurfaceView不支持硬件加速所以直接就Pass了想实现方案二我认为得弄清自定义控件onDraw()方法中Canvas从何而来;分析Canvas流程View.onDraw()中的Canvas从何而来我们知道View的绘制流程是从ViewRootImpl.performTraversals()这个方法开始performTraversals()boolean cancelDraw mAttachInfo.mTreeObserver.dispatchOnPreDraw() || !isViewVisible;if (!cancelDraw !newSurface) {if (mPendingTransitions ! null mPendingTransitions.size() 0) {for (int i 0; i mPendingTransitions.size(); i) {mPendingTransitions.get(i).startChangingAnimations();}mPendingTransitions.clear();}//调动performDraw()performDraw();} else {if (isViewVisible) {// Try againscheduleTraversals();} else if (mPendingTransitions ! null mPendingTransitions.size() 0) {for (int i 0; i mPendingTransitions.size(); i) {mPendingTransitions.get(i).endChangingAnimations();}mPendingTransitions.clear();}}复制代码performTraversals()方法调用performDraw()然后performDraw()方法中又调用draw(fullRedrawNeeded)大部门绘制的逻辑都是在draw(fullRedrawNeeded)方法中;draw(fullRedrawNeeded)if (!dirty.isEmpty() || mIsAnimating || accessibilityFocusDirty) {if (mAttachInfo.mThreadedRenderer ! null mAttachInfo.mThreadedRenderer.isEnabled()) {//省略代码mAttachInfo.mThreadedRenderer.draw(mView, mAttachInfo, this);} else {if (mAttachInfo.mThreadedRenderer ! null !mAttachInfo.mThreadedRenderer.isEnabled() mAttachInfo.mThreadedRenderer.isRequested()) {//省略代码//drawSoftwareif (!drawSoftware(surface, mAttachInfo, xOffset, yOffset, scalingRequired, dirty)) {return;}}}复制代码从draw(fullRedrawNeeded)方法可以看到如果支持硬件加速调用mAttachInfo.mThreadedRenderer.draw()方法否则调用drawSoftware()方法绘制的基本流程从这里分叉drawSoftware如何获得CanvasdrawSoftware()private boolean drawSoftware(Surface surface, AttachInfo attachInfo, int xoff, int yoff,boolean scalingRequired, Rect dirty) {// Draw with software renderer.final Canvas canvas;try {final int left dirty.left;final int top dirty.top;final int right dirty.right;final int bottom dirty.bottom;canvas mSurface.lockCanvas(dirty);Surface.lockCanvas()//noinspection ConstantConditionsif (left ! dirty.left || top ! dirty.top || right ! dirty.right|| bottom ! dirty.bottom) {attachInfo.mIgnoreDirtyState true;}canvas.setDensity(mDensity);} catch (Surface.OutOfResourcesException e) {handleOutOfResourcesException(e);return false;} catch (IllegalArgumentException e) {mLayoutRequested true;return false;}//省略代码}复制代码从drawSoftware()方法可以知道软件绘制的流程是从Surface.lockCanvas()获得Canvas对象View体系硬件加速Canvas创建过程ThreadedRenderer.draw()void draw(View view, AttachInfo attachInfo, DrawCallbacks callbacks) {attachInfo.mIgnoreDirtyState true;final Choreographer choreographer attachInfo.mViewRootImpl.mChoreographer;choreographer.mFrameInfo.markDrawStart();//调用updateRootDisplayList更新DisplayListupdateRootDisplayList(view, callbacks);}复制代码ThreadedRenderer.updateRootDisplayList()private void updateRootDisplayList(View view, DrawCallbacks callbacks) {Trace.traceBegin(Trace.TRACE_TAG_VIEW, Record View#draw());updateViewTreeDisplayList(view);if (mRootNodeNeedsUpdate || !mRootNode.isValid()) {//通过RootNode.start创建DisplayListCanvasDisplayListCanvas canvas mRootNode.start(mSurfaceWidth, mSurfaceHeight);try {final int saveCount canvas.save();canvas.translate(mInsetLeft, mInsetTop);callbacks.onPreDraw(canvas);canvas.insertReorderBarrier();canvas.drawRenderNode(view.updateDisplayListIfDirty());canvas.insertInorderBarrier();callbacks.onPostDraw(canvas);canvas.restoreToCount(saveCount);mRootNodeNeedsUpdate false;} finally {//最终调用end方法mRootNode.end(canvas);}}Trace.traceEnd(Trace.TRACE_TAG_VIEW);}复制代码View.updateDisplayListIfDirty()public RenderNode updateDisplayListIfDirty() {final RenderNode renderNode mRenderNode;//省略代码int layerType getLayerType();//创建DisplayListCanvasfinal DisplayListCanvas canvas renderNode.start(width, height);canvas.setHighContrastText(mAttachInfo.mHighContrastText);try {//判断layerTypeif (layerType LAYER_TYPE_SOFTWARE) {buildDrawingCache(true);Bitmap cache getDrawingCache(true);if (cache ! null) {canvas.drawBitmap(cache, 0, 0, mLayerPaint);}} else {computeScroll();canvas.translate(-mScrollX, -mScrollY);mPrivateFlags | PFLAG_DRAWN | PFLAG_DRAWING_CACHE_VALID;mPrivateFlags ~PFLAG_DIRTY_MASK;// Fast path for layouts with no backgroundsif ((mPrivateFlags PFLAG_SKIP_DRAW) PFLAG_SKIP_DRAW) {dispatchDraw(canvas);//dispatchDrawdrawAutofilledHighlight(canvas);if (mOverlay ! null !mOverlay.isEmpty()) {mOverlay.getOverlayView().draw(canvas);}if (debugDraw()) {debugDrawFocus(canvas);}} else {//调用draw()方法draw(canvas);}}} finally {renderNode.end(canvas);setDisplayListProperties(renderNode);}} else {mPrivateFlags | PFLAG_DRAWN | PFLAG_DRAWING_CACHE_VALID;mPrivateFlags ~PFLAG_DIRTY_MASK;}return renderNode;}复制代码从上面基本流程可以看出硬件加速下Canvas的创建是调用RenderNode.create()方法每个View都有自己的RenderNodeRenderNode的创建是在View的构造方法中View构造方法public View(Context context) {mContext context;mResources context ! null ? context.getResources() : null;mViewFlags SOUND_EFFECTS_ENABLED | HAPTIC_FEEDBACK_ENABLED | FOCUSABLE_AUTO;//省略mRenderNode RenderNode.create(getClass().getName(), this);//省略}复制代码RenderNode通过调用静态方法create得到RenderNode对象我们继续看RenderNode.create()方法RenderNode.create()/*** param name The name of the RenderNode, used for debugging purpose. May be null.* return A new RenderNode.*/public static RenderNode create(String name, Nullable View owningView) {return new RenderNode(name, owningView);}复制代码create()方法有两个参数第一个name第二个是owningView而且是可以为空的从注释上来看name只是为了调试用而且owningView可以为空我们可以用反射去创建一个简单的RenderNode;尝试创建一个Canvas回顾一下写出一个简单的创建一个硬件加速Canvas的代码第一行创建RenderNodeRenderNode node RenderNode.create(helloworld, null);第二行创建DisplayListCanvasfinal DisplayListCanvas canvas node.start(bitmapWidth, bitmapHeight);第三行执行canvas的操作canvas.xxx();第四行执行node.end()方法node.end(canvas);复制代码一个简单的DisplayListCanvas创建流程在脑海中浮现出来但是还有个问题我们执行完canvas的绘制操作之后生成的产物Bitmap从哪里得到我们回顾和ViewRootImpl打交道的硬件加速绘制相关的类是ThreadedRenderer我们刚才看了这个类的draw()方法和updateRootDisplayList()方法很有意思它还有一个这个静态的方法createHardwareBitmap(RenderNode node, int width, int height)ThreadedRenderer.createHardwareBitmap()public static Bitmap createHardwareBitmap(RenderNode node, int width, int height) {return nCreateHardwareBitmap(node.getNativeDisplayList(), width, height);}复制代码该方法根据传入的RenderNode创建一个硬件加速的Bitmap并返回要求传入的这个node必须是根root在这里一个完整的获取替换Canvas的流程应该是这样第一行创建RenderNodeRenderNode node RenderNode.create(helloworld, null);第二行创建DisplayListCanvasfinal DisplayListCanvas canvas node.start(width, height);第三行执行canvas的操作canvas.xxx();第四行执行node.end()方法node.end(canvas);第五行调用createHardwareBitmap生成Bitmapbitmap ThreadedRenderer.createHardwareBitmap(node,width,height)复制代码基于上面的伪代码分析我写了一个避免反射调优化版的Hardware Canvas基本调用如下//创建HardwareCanvasManagerval hardwareCanvasManager HardwareCanvasManager()try {//获取canvasval canvas hardwareCanvasManager.createCanvas(size, size)//画圆形or其他绘制canvas.drawCircle(radius, radius, radius, CIRCLE_CROP_SHAPE_PAINT);//画原图通过画笔设置SRC_IN属性canvas.drawBitmap(inBitmap, null, destRect, CIRCLE_CROP_BITMAP_PAINT);//得到bitmapval buildBitmap hardwareCanvasManager.buildBitmap()//将bitmap设置给ImageViewiv.setImageBitmap(buildBitmap)} finally {//清理工作hardwareCanvasManager.clean()}复制代码Github传送门总结这篇水文主要是分析View绘制下Canvas的创建流程关于硬件加速的更详细的介绍推荐大家看这篇文章www.jianshu.com/p/40f660e17…。
http://www.yutouwan.com/news/216218/

相关文章:

  • 网站如何改版做网站前景怎么样
  • 自己做网站怎么赢利企业crm销售管理系统
  • 大连网站建设讯息wordpress 搜索结果分页
  • 做网站可能存在的问题wordpress短链识别
  • 福州网站设计软件公司冠县哪做网站
  • 公司网站建设征求意见表模板设计图
  • 门户app网站建设多少钱制作一个简单的网页步骤
  • 北京市住房与城乡建设厅网站网站域名做哪个会计科目
  • 怎么开通个人网站wordpress做成仿阿里巴巴
  • 天津网站建设好公司美容加盟的网站建设
  • 网络推广怎么干杭州网站优化企业
  • 做三方网站多少钱wordpress 充值插件
  • 做网站 广州90设计怎么免费下载
  • 大连三大网络推广网站成都关键词优化排名
  • 怎么查网站权重定制网络机顶盒
  • 泊头那家做网站免费注册电子邮箱
  • 网站空白页黑链阿里云Windows网站建设
  • wordpress本地网站怎么访问tp做的网站封装成app
  • 长春市做网站的公司搜索wordpress
  • 2018年网站风格深圳网站设计公司哪种
  • 企业网站托管运营中国无法访问wordpress
  • 网站做管理后台需要知道什么网站建设策划书的撰写
  • dedecms采集规则各类网站怎么搭建个人网站
  • 小企网站建设解决方案注册公司需要什么资料和流程
  • 响应式设计的网站网站开发洽谈客户话术
  • 网站改版页面不收录开发语言有哪些
  • 重庆网站建设优化排名论坛网站开发成本
  • 带会员功能的网站discuz 企业网站 模板
  • 国际网站空间wordpress文章分页代码
  • 福建网站开发公司国内产品设计网站