android学习笔记----定时问题

2023-05-06 18:56:38 浏览数 (1)

两种方法:

第一种:

代码语言:javascript复制
// 5000ms后执行run方法
// 可以在这run()里面更新ui
new Handler().postDelayed(new Runnable() {
    @Override
    public void run() {
        tv.setText("呵呵呵呵呵");
        Log.d(TAG, "5s后我执行了");
    }
}, 5000);

上面效果就是5s后将TextView控件内容改为“呵呵呵呵呵”

第二种:

代码语言:javascript复制
timer = new Timer();
// 不能在这run()里面更新ui,除非使用runOnUiThread方法
timerTask = new TimerTask() {
    @Override
    public void run() {
        tv.setText("哈哈哈哈哈");
        Log.d(TAG, "任务执行");
    }
};
timer.schedule(timerTask, 2000, 2000);

timer.schedule的第三个参数是间隔多久重复一次,可以不设置,做一次性的任务。

如果设置第三个参数就要记得在OnDestroy取消,不然activity销毁后定时任务仍然存在。

如果在这里的run方法更新ui就需要使用runOnUiThread()方法。

下面效果是每隔2s将TextView控件内容设置为“哈哈哈哈哈”

代码语言:javascript复制
timer = new Timer();
// 不能在这run()里面更新ui,除非使用runOnUiThread方法
timerTask = new TimerTask() {
    @Override
    public void run() {
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                tv.setText("哈哈哈哈哈");
            }
        });
        Log.d(TAG, "任务执行");
    }
};
timer.schedule(timerTask, 2000, 2000);

否则抛异常android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its view

Android中相关的view和控件操作都不是线程安全的,所以Android才会禁止在非UI线程更新UI,对于显式的非法操作,比如说直接在Activity里创建子线程,然后直接在子线程中操作UI等,Android会直接异常退出,并提示should run on UIThread之类的错误日志信息。而对于隐式的非法操作,App不会直接简单粗暴地异常退出,只是出现奇怪的结果,Only the original thread that created a view hierarchy can touch its views便是一个例子,字面意思是只有创建视图层次结构的原始线程才能操作它的View,明显是线程安全相关的。s.说明在错误的线程更新UI。

总结点:

不能在主线程(UI线程)进行耗时的操作,比如连接网络,拷贝大数据,睡眠等操作。

比如连接谷歌网络。warning:java.net.SocketTimeoutException: connect timed out

只要主线程超时 info:The application may be doing too much work on its main thread.

在4.0之后谷歌强制要求连接网络不能在主线程进行访问

只有主线程(UI线程)才可以更新UI

定时代码如下

MainActivity .java

代码语言:javascript复制
import android.os.Bundle;
import android.os.Handler;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.widget.TextView;

import java.util.Timer;
import java.util.TimerTask;

public class MainActivity extends AppCompatActivity {
    final String TAG = "MainActivity";
    private Timer timer;
    private TimerTask timerTask;
    private TextView tv;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        tv = (TextView) findViewById(R.id.tv);
        // 5000ms后执行run方法
        // 可以在这run()里面更新ui
        new Handler().postDelayed(new Runnable() {
            @Override
            public void run() {
                tv.setText("呵呵呵呵呵");
                Log.d(TAG, "5s后我执行了");
            }
        }, 5000);
        /*timer = new Timer();
        // 不能在这run()里面更新ui,除非使用runOnUiThread方法
        timerTask = new TimerTask() {
            @Override
            public void run() {
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        tv.setText("哈哈哈哈哈");
                    }
                });
                Log.d(TAG, "任务执行");
            }
        };
        timer.schedule(timerTask, 2000, 2000);*/
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        // 终止此计时器,丢弃任何当前计划的任务。 不干扰当前执行的任务(如果存在)。
        // 比如说定时器重复10个任务,cancel调用,我正在执行的任务就是最后一个任务,剩下的9个任务我不做了。
        //  一旦计时器被终止,它的执行线程就会顺利地终止,并且不会再安排任务了。
        timer.cancel();// 如果是第二种定时方法需要取消定时器

        // 如果此方法发生时任务正在运行,则任务将运行到完成,但不会再运行。
        // 也就是重复任务取消,最后任务表中的所有任务你就善始善终做完吧,可能还需要做几个任务这一轮才结束
        // 从重复定时器任务的run方法中调用此方法绝对保证计时器任务不会再次运行。
        // timerTask.cancel();
        Log.d(TAG, "onDestroy: ");
    }
}

0 人点赞