post postinvalidate invalidate

本文探讨了在Android应用中使用Timer更新UI时遇到的问题,详细解释了为何直接使用invalidate()方法可能导致UI更新失败,并提供了使用postInvalidate()方法解决线程冲突的方法,确保UI能够正确刷新。

android

Handler.post(action) 这是android提供的一种机制,handler对象将通过post方法,将里面的Runnable对象放到UI执行队列中,UI消费这个队列,调用Runnable的run方法。这里并不生成新的线程。

 

  Android中在绘图中的多线程中,invalidate和postInvalidate这两个方法是用来刷新界面的,调用这两个方法后,会调用onDraw事件,让界面重绘。

 

 

在一个没有使用线程的小游戏中想刷新一下时间进度,想到用Timer。于是写了一段代码:

 

        nStartRoundTime = System.currentTimeMillis();
        nT1 = new Timer();
        nT1.schedule(new TimerTask(){ //计划运行时间间隔
                public void run(){
                    refreshTimePaint(); //过3秒调用一下refreshTimePaint()
                }
              },0,3000);

 

 

 

    public void refreshTimePaint(){
        invalidate(); //使用invalidate();刷新
        System.out.println(System.currentTimeMillis());
        System.out.println(nGameState);
    }

 

    同时我也将System.currentTimeMillis()打印在View上。

 

运行一下,发现并不是预期那样, System.out.println的结果在Log里面都有变化,但是View却没有反应。 不但View上面没有被刷新,甚至连原来的触屏事件都没有反映了。

 

去网上查了一下,得到的一些解释有这些:

 

The best thing is to  use Handler with delayed messages.
And Timer works fine, the problem is that a Timer runs in a separate thread,   and so you are trying to modify a view owned by another thread (the main   thread that originally created it).

 

 

What I think is happening is you're falling off the UI thread. There is a single "looper" thread which handles all screen updates. If you attempt to call "invalidate()" and you're not on this thread nothing will happen.

Try using "postInvalidate()" on your view instead. It'll let you update a view when you're not in the current UI thread.

 

于是把refreshTimePaint()的代码改成:

 

public void refreshTimePaint(){
        this.postInvalidate(); //使用postInvalidate();刷新
        System.out.println(System.currentTimeMillis());
        System.out.println(nGameState);
    }

 

 

这样View就能自动刷新了~~~

 

这里有几个网页做参考:

http://stackoverflow.com/questions/522800/android-textview-timer

http://groups.google.com/group/android-developers/browse_thread/thread/5baf5a3eaa823b7b?pli=1

http://groups.google.com/group/android-developers/msg/f5765705b8c59d66

### Android 中异步调用 `invalidate` 方法进行视图重绘 在 Android 开发中,为了确保 UI 更新操作发生在主线程上,通常不建议直接在子线程中调用 `invalidate()` 或其他涉及 UI 操作的方法。然而,在某些情况下确实需要从后台线程触发视图的重绘。 对于这种情况,可以采用以下几种方式: #### 使用 Handler 发送消息至主线程 通过创建一个与主线程关联的 `Handler` 实例,可以在子线程中发送消息或运行命令给这个处理器对象,从而间接地让其在线程池之外即主线程上调用 `invalidate()` 函数完成刷新工作。 ```java // 创建handler实例并与UI线程绑定 final Handler handler = new Handler(Looper.getMainLooper()); // 子线程中执行的任务 new Thread(new Runnable() { @Override public void run() { // 执行耗时任务... // 完成后通知UI线程更新界面 handler.post(new Runnable(){ @Override public void run() { myView.invalidate(); // 调用invalidate() } }); } }).start(); ``` #### 利用 AsyncTask 的 onPostExecute 方法 当使用 `AsyncTask` 类处理长时间运行的操作时,可以在 `doInBackground()` 方法里做实际的工作,并且一旦结束就可以利用 `onPostExecute()` 来安全地修改 UI 组件的状态或者属性,此时也可以在这里面调用 `invalidate()` 进行绘制请求。 ```java private class MyAsyncTask extends AsyncTask<Void, Void, Boolean> { protected Boolean doInBackground(Void... params) { // 后台任务... return true; } protected void onPostExecute(Boolean result) { super.onPostExecute(result); if (result){ myView.invalidate(); // 在这里调用invalidate() } } } ``` #### postInvalidate 方法的应用 除了上述两种常见的做法外,还有一个更为简便的选择就是直接调用 `postInvalidate()` 。此函数的作用类似于 `invalidate()` ,但它会在适当的时候安排一次回调到事件循环中去真正执行 `invalidate()` 动作;也就是说它会自动把任务提交给 Looper 并等待合适的时机再去做具体的绘制动作。这种方式特别适合于那些已经处于非 UI 线程环境下的场景下使用[^1]。 需要注意的是,无论是哪种方案都应遵循单一线程原则(Single-threaded Principle),即所有的 UI 更改都应该发生在一个特定的线程—通常是应用程序启动之初所指定的那个默认存在的“main thread”。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值