【达内课程】Thread中ANR

ANR

Application Not Responding
应用程序无响应

Android 系统中,ActivityManagerService(简称AMS) 和 WindowManagerService(简称WMS) 会检测 App 的响应时间,如果 App 在特定时间无法相应屏幕触摸或键盘输入时间,或者特定事件没有处理完毕,就会出现ANR。

以下四个条件都有可能造成 ANR:
1、InputDispatching Timeout:5秒内无法响应屏幕触摸事件或键盘输入事件
2、BroadcastQueue Timeout :在执行前台广播(BroadcastReceiver)的onReceive()函数时10秒没有处理完成,后台为 60 秒。
3、Service Timeout :前台服务 20 秒内,后台服务在 200 秒内没有执行完毕。
4、ContentProvider Timeout :ContentProvider的publish在 10s 内没进行完。

所以,在Android中,尽量避免在主线程(UI线程)中作耗时操作。应该由子线程完成。处理ANR的解决办法就是开子线程。

Android UI 线程模型

在 Android 系统中,主线程用于处理 UI(User Interface) 相关操作,例如创建 View 对象,对 View 相关的操作进行响应等,所以主线程也称之为 UI线程。

系统约定了,只有创建 view 的线程才能操作 view,所以,可以小结为:只有主线程才可以调用控件的方法,而子线程不可以。

【进阶】
只有拥有 ViewRoot 的线程才可以操控 View,在 Android APP 中,主线程默认就有ViewRoot,而子线程没有

栗子1:每秒输出时间

对 Button 添加点击事件,要执行的操作是:每隔一秒打印一个时间,制造一个时钟的效果
在这里插入图片描述

MainActivity

public class MainActivity extends AppCompatActivity implements View.OnClickListener {
    private Button btn;
    private TextView tvTime;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Log.d("Thread", "MainActivity oncreate()" + Thread.currentThread().getId());

        btn = findViewById(R.id.button);
        tvTime = findViewById(R.id.textView);

        btn.setOnClickListener(this);
    }

    private class InnerThread extends Thread {
        SimpleDateFormat sdt = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Date date = new Date();

        @Override
        public void run() {
            super.run();

            for (int i = 0; i < 60; i++) {
                date.setTime(System.currentTimeMillis());

                Log.d("Thread", "Thread Id=" + getId());

                runOnUiThread(() -> {
                    tvTime.setText(sdt.format(date));
                    Log.d("Thread", "runOnUiThread()->=" + Thread.currentThread().getId());
                });

                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.button:
                InnerThread innerThread = new InnerThread();
                innerThread.start();
                break;
        }
    }
}

对代码的解释

那么为什么不直接在 onClick 代码中写相应的操作呢?

因为我们的操作需要有 60s 才能完成,可能导致程序 ANR,所以需要一个线程来完成操作。

因此写一个内部类 InnerThread 继承 Thread,重写run()方法,把需要执行的操作放进去即可。

再看 InnerThread 类中,只有拥有 ViewRoot 的线程才可以操控 View,在 Android APP 中,主线程默认就有 ViewRoot,而子线程没有因为子线程无法操作,所以写了一个runOnuiThread()方法来通知主线程来操作 view,修改 TextView 的显示
通过打印日志可知,runOnUiThread 中的run()方法就是执行在主线程的

栗子2:ProgressBar自动增长

在这里插入图片描述

MainActivity

public class MainActivity extends AppCompatActivity implements View.OnClickListener {
    private ProgressBar progressBar;
    private Button button;
    private TextView textView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        progressBar = findViewById(R.id.progressBar);
        button = findViewById(R.id.button);
        textView = findViewById(R.id.textView);
        button.setOnClickListener(this);
    }

    private class InnerThread extends Thread {
        private int i;

        @Override
        public void run() {
            Runnable runnable = () -> {
                progressBar.setProgress(i);
                textView.setText(progressBar.getProgress() + "/" + progressBar.getMax());

            };

            for (i = 0; i <= 100; i++) {
                runOnUiThread(runnable);

                try {
                    Thread.sleep(50);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    @Override
    public void onClick(View view) {
        InnerThread thread = new InnerThread();
        thread.start();
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值