Invalidate和postInvalidate的区别
在Android实际开发中,我们常常需要进行View的刷新(例如:自定义控件等),Android中为我们提供了两组刷新View的方法—-Invalidate和postInvalidate,前者是在UI线程中更新View,而后者是在非UI线程中更新VIew,两组方法的具体区别如下介绍:
我们都知道,在Android中,更新UI的操作要在UI线程(也就是主线程)中进行,因为Android UI操作并不是线程安全的,但是这些操作必须在UI线程中调用(单线程模式,这里就不在详细介绍了,可以自己上网查阅)。
Invalidate()方法:
对于初学者来说,我们常用的更新UI的方式不外乎就是利用Handler机制,在工作线程中执行耗时操作等,然后发消息给UI线程,进行UI操作。以下我们以自定义控件来介绍该用法(自定义控件,实现一个圆环不停的刷新大小,由小变大):
自定义控件,绘制一个圆环,并更新其大小“`
public class MyView extends View { /** * 画笔 */ private Paint mPaint ; /** * 自定义控件半径 */ private int radiu ; public MyView(Context context) { this(context, null); } public MyView(Context context, AttributeSet attrs) { super(context, attrs); // 初始化画笔 initPaint() ; } public MyView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } /** * 初始化画笔方法 */ private void initPaint() { mPaint = new Paint(Paint.ANTI_ALIAS_FLAG) ; mPaint.setStyle(Style.STROKE) ; mPaint.setColor(Color.RED) ; mPaint.setStrokeWidth(20) ; } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); // 执行绘制 canvas.drawCircle(150, 150, radiu, mPaint) ; } public synchronized void setRadiu(int radiu) { this.radiu = radiu ; // 刷新,即重新绘制 invalidate() ; }}
然后在MainActivity中:
public class MainActivity extends Activity { /** * 自定义控件对象 */ private MyView myView ; /** * 自定义控件的半径 */ private int radiu ; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); myView = (MyView) findViewById(R.id.myview) ; // 开启线程 new Thread(new Runnable() { @Override public void run() { try { // 死循环,不停的刷新View while(true) { // 当半径小于200时,开始自增 if(radiu <= 200) { radiu += 10 ; // 发送消息给Handler处理 mHandler.obtainMessage().sendToTarget() ; } else { radiu = 0 ; } // 每隔40毫秒睡一次 Thread.sleep(40) ; } } catch (InterruptedException e) { e.printStackTrace(); } } }).start() ; } @SuppressLint("HandlerLeak") private Handler mHandler = new Handler() { public void handleMessage(android.os.Message msg) { // 设置自定义控件的半径 myView.setRadiu(radiu) ; }; } ; protected void onDestroy() { super.onDestroy() ; // 界面销毁后移除Handler的引用 mHandler.removeCallbacksAndMessages(null) ; };}
以上这种方式即为在非UI线程中执行逻辑代码,然后利用Handler机制发送消息通知UI线程进行更新UI的操作。
postInvalidate()方法:
而postInvalidate()可以直接在非UI线程中刷新,不需要使用Handler机制,代码逻辑也相对比较简单:
public class MyView extends View implements Runnable { /** * 画笔 */ private Paint mPaint ; /** * 自定义控件半径 */ private int radiu ; public MyView(Context context) { this(context, null); } public MyView(Context context, AttributeSet attrs) { super(context, attrs); // 初始化画笔 initPaint() ; } public MyView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } /** * 初始化画笔方法 */ private void initPaint() { mPaint = new Paint(Paint.ANTI_ALIAS_FLAG) ; mPaint.setStyle(Style.STROKE) ; mPaint.setColor(Color.RED) ; mPaint.setStrokeWidth(20) ; } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); // 执行绘制 canvas.drawCircle(150, 150, radiu, mPaint) ; } @Override public void run() { while(true) { try { if(radiu <= 150) { radiu += 10 ; postInvalidate() ; } else { radiu = 0 ; } Thread.sleep(40) ; } catch (InterruptedException e) { e.printStackTrace(); } } }}
在MainActivity中,开启线程更新View:
public class MainActivity extends Activity { /** * 自定义控件对象 */ private MyView myView ; /** * 自定义控件的半径 */ private int radiu ; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); myView = (MyView) findViewById(R.id.myview) ; // 开启线程刷新界面 new Thread(myView).start() ; }
以上两种方式,是我在利用自定义控件时使用的,可能对于不熟悉自定义控件的初学者来说看着会有点乱,其实仔细阅读以下,就会发现,并不是那么难,第一种方式中,我们选择利用Handler机制来处理,利用消息机制来通知UI线程更新View操作,所以,调用Invalidate()的方法(即setRadiu())是运行在UI线程的,对于第二种方法,我们将更新View的方法放在了一个子线程中(即Runnable接口的run方法中),然后在调用该自定义控件时开启一个线程来操作,所以postInvalidate()方法是运行在子线程的。
我们在学习Android时,要记住一点,代码千变万化,万变不离其宗,代码稍微一改就会不一样,但其调用的实质是一样的。希望这篇博客能给大家一点帮助,若有解释不合理的地方,希望大家提出宝贵的意见。
更多相关文章
- android:padding 和 android:margin的区别
- Android(安卓)NDK 面试题汇总
- Android消息机制
- android中刷新Invalidate和postInvalidate的区别
- Android(安卓)Handler机制详解:在线程中新建Handler
- 安卓中一些常用的属性小结
- 利用HTML5开发Android笔记(中篇)
- Android工程中R.java文件的重新生成——注意资源文件的错误
- 【Android】动态链接库so的加载原理