Android 自定义View过度绘制性能优化<7>
来源:互联网 发布:linux中scp命令 编辑:程序博客网 时间:2024/05/10 23:38
在自定义View 里面如果又有很多个子View相互重叠,比如,开发者在一张canvas上面画了N张图片,而N张图片存在重叠,那么很显然就会存在过度绘制的现象.
专家分析的意见如下:
<pre class="html" name="code">前面有提到过,对不可见的UI组件进行绘制更新会导致Overdraw。例如Nav Drawer从前置可见的Activity滑出之后,如果还继续绘制那些在Nav Drawer里面不可见的UI组件,这就导致了Overdraw。为了解决这个问题,Android系统会通过避免绘制那些完全不可见的组件来尽量减少Overdraw。那些Nav Drawer里面不可见的View就不会被执行浪费资源。但是不幸的是,对于那些过于复杂的自定义的View(通常重写了onDraw方法),Android系统无法检测在onDraw里面具体会执行什么操作,系统无法监控并自动优化,也就无法避免Overdraw了。但是我们可以通过canvas.clipRect()来帮助系统识别那些可见的区域。这个方法可以指定一块矩形区域,只有在这个区域内才会被绘制,其他的区域会被忽视。这个API可以很好的帮助那些有多组重叠组件的自定义View来控制显示的区域。同时clipRect方法还可以帮助节约CPU与GPU资源,在clipRect区域之外的绘制指令都不会被执行,那些部分内容在矩形区域内的组件,仍然会得到绘制。
其余要解决这样的问题原理还是比较简单,但是实现起来就很繁琐,因为它需要通过canvas.clipRect()方法将被覆盖的部分cut掉,比如说一张图片800*800的,但是能够显示出来的只有100*100,那么其他的700*700就要全部通过clipRect()方法调整绘制范围,只能够显示出100*100的部分,剩下的700*700全部被cut掉了.这样剩下的700*700的地方在绘制其他图片的时候,就不会出现重叠,如果不出现重叠,就不会出现过度绘制了(这话似乎有点绝对).
可以做一个android 工程测试一次:
<1> : 新建android 工程如下:
<2> : 所有的程序代码如下:
DurianMainActivity.java
package org.durian.durianviewoverdraw;import android.os.Bundle;import android.support.v7.app.ActionBarActivity;import android.view.Menu;import android.view.MenuItem;public class DurianMainActivity extends ActionBarActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.durian_main); } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.menu_durian_main, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { // Handle action bar item clicks here. The action bar will // automatically handle clicks on the Home/Up button, so long // as you specify a parent activity in AndroidManifest.xml. int id = item.getItemId(); //noinspection SimplifiableIfStatement if (id == R.id.action_settings) { return true; } return super.onOptionsItemSelected(item); }}DurianView.java
package org.durian.durianviewoverdraw.view;import android.content.Context;import android.graphics.Bitmap;import android.graphics.BitmapFactory;import android.graphics.Canvas;import android.graphics.Paint;import android.util.AttributeSet;import android.util.Log;import android.view.View;import org.durian.durianviewoverdraw.R;/** * Project name : DurianViewOverDraw * Created by zhibao.liu on 2016/1/11. * Time : 14:33 * Email warden_sprite@foxmail.com * Action : durian */public class DurianView extends View { private final static String TAG="DurianView"; private Paint mpaint; private Bitmap bitmap; private Context mContext; private boolean isReject=false; public DurianView(Context context, AttributeSet attrs) { super(context, attrs); mContext=context; initView(); } private void initView(){ mpaint=new Paint(); mpaint.setColor(0x00ff00); bitmap= BitmapFactory.decodeResource(mContext.getResources(), R.drawable.back); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); for(int i=0;i<2;i++) { canvas.save();// canvas.clipRect(10+i*180,10+i*180,500*(i+1),500*(i+1)); canvas.drawBitmap(bitmap, 10+i*180, 10+i*180, null); /*if(i==1) { isReject = canvas.quickReject(10 + i * 180, 10 + i * 180, 10 + i * 180+50, 10 + i * 180+50, Canvas.EdgeType.BW); Log.i(TAG,"isReject : "+isReject); isReject = canvas.quickReject(10 , 10 , 10 +180, 10 +180, Canvas.EdgeType.BW); Log.i(TAG,"*** isReject : "+isReject); }*/ canvas.restore(); } }}
布局文件:
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <org.durian.durianviewoverdraw.view.DurianView android:id="@+id/durianview" android:layout_width="fill_parent" android:layout_height="fill_parent" /></LinearLayout>
图片资源就自行放一张图片进去吧,稍微大一点的.
<3> : 运行结果:截取部分,因为我是那nexus平板测试的:
颜色就不需要解释了,蓝色这边是1X,绿色这边是2X,这个绿色是因为打开GPU overdraw显示出来的,并不是程序显示出来的.
<4> : 在DurianView代码中,我注释掉了几行,现在打开,看一看:
看以看出,裁剪掉的有绿色变成蓝色了,但是还是有一部分显示绿色,那是因为程序没有去裁剪(计算太繁琐了,所以没去弄了),这是因为画第一张图片,这样似乎不怎么好理解,我重新把DurianView程序调整一下:
package org.durian.durianviewoverdraw.view;import android.content.Context;import android.graphics.Bitmap;import android.graphics.BitmapFactory;import android.graphics.Canvas;import android.graphics.Paint;import android.util.AttributeSet;import android.util.Log;import android.view.View;import org.durian.durianviewoverdraw.R;/** * Project name : DurianViewOverDraw * Created by zhibao.liu on 2016/1/11. * Time : 14:33 * Email warden_sprite@foxmail.com * Action : durian */public class DurianView extends View { private final static String TAG="DurianView"; private Paint mpaint; private Bitmap bitmap; private Context mContext; private boolean isReject=false; public DurianView(Context context, AttributeSet attrs) { super(context, attrs); mContext=context; initView(); } private void initView(){ mpaint=new Paint(); mpaint.setColor(0x00ff00); bitmap= BitmapFactory.decodeResource(mContext.getResources(), R.drawable.back); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); for(int i=0;i<2;i++) { canvas.save(); canvas.clipRect(10+i*250,100,10+250*(i+1),500*2); canvas.drawBitmap(bitmap, 10+i*250, 100, null); /*if(i==1) { isReject = canvas.quickReject(10 + i * 180, 10 + i * 180, 10 + i * 180+50, 10 + i * 180+50, Canvas.EdgeType.BW); Log.i(TAG,"isReject : "+isReject); isReject = canvas.quickReject(10 , 10 , 10 +180, 10 +180, Canvas.EdgeType.BW); Log.i(TAG,"*** isReject : "+isReject); }*/ canvas.restore(); } }}
运行结果:
如果不加裁剪:
一看就出现2X重绘了.
如果将程序改一下,划出4张来,把for循环里面的i<2,改为i<4即可,同时把裁剪那一行代码注释掉:
就很容看到1X,2X,3X,4X了.
然后将裁剪那一行代码释放出来:
canvas.clipRect(10+i*250,100,10+250*(i+1),500*2);
就不会存在了,全部是1X了,从而消除了过度绘制.
专家还提到canvas.quickReject()方法
if(i==1) { isReject = canvas.quickReject(10 + i * 180, 10 + i * 180, 10 + i * 180+50, 10 + i * 180+50, Canvas.EdgeType.BW); Log.i(TAG,"isReject : "+isReject); isReject = canvas.quickReject(10 , 10 , 10 +180, 10 +180, Canvas.EdgeType.BW); Log.i(TAG,"*** isReject : "+isReject); }
在上面的基础上,注释去掉.
也就是说如果图形方框没有存在重叠,返回的为true.
下面把裁剪去掉:
可以通过这个判断某个Rect区域是否存在重叠,或者所谓的子图形有边界冲突.
- Android 自定义View过度绘制性能优化<7>
- ]Android性能优化:过度绘制
- Android性能优化--过度绘制
- 性能优化过度绘制
- Android UI性能优化 -- GPU过度绘制
- Android 过度绘制性能优化<6>
- Android性能优化课程:过度绘制
- Android性能优化课程:过度绘制
- Android性能优化-过度绘制解决方案
- Android性能优化-过度绘制解决方案
- Android性能优化之减少过度绘制
- Android性能优化-过度绘制解决方案
- Android 性能优化<七>自定义view绘制优化
- Android过度绘制深度优化---View提前绘制
- Android过度绘制深度优化---View提前绘制
- ANDROID应用性能优化之优化列表头像过度绘制
- Android 优化性能之 如何避免--过度绘制
- Android 优化性能之 如何避免--过度绘制
- 哈理工OJ HLG OJ 1005Counting Subsequences(map应用)(STL应用)
- ios 微信支付 调起只出现确定按钮
- string 与char* char[]之间的转换
- IE7以下绝对定位的DIV被相对定位的DIV挡住问题
- mysql中ifnull用法
- Android 自定义View过度绘制性能优化<7>
- eclipse设置debug签名为打包release签名
- 关于@autoreleasepool的性能测试及手动释放自动释放池
- 数据库账号密码加密
- iOS~block的使用
- liunx 批量删除进程 利用xargs
- 39. Combination Sum && 40. Combination Sum II
- 数据库设计三大范式
- Ubuntu 14.04下NFS安装配置