天天看点

【ANR避免和解决】ANR是什么?怎样避免和解决ANRAsyncTask使用

ANR是什么?怎样避免和解决ANR

Application Not Responding,即应用无响应

出现的原因有三种:

a)KeyDispatchTimeout(5 seconds)主要类型按键或触摸事件在特定时间内无响应

b)BroadcastTimeout(10 seconds)BoradcastReceiver在特定的时间内无法处理

c)ServiceTimeout(20 seconds)小概率类型Service在特定的时间内无法处理完成

避免ANR最核心的一点就是在主线程减少耗时操作。通常需要从那个以下几个方案下手:

a)使用子线程处理耗时IO操作

b)降低子线程优先级,使用Thread或者HandlerThread时,调用Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND)设置优先级,否则仍然会降低程序响应,因为默认Thread的优先级和主线程相同

c)使用Handler处理子线程结果,而不是使用Thread.wait()或者Thread.sleep()来阻塞主线程

d)Activity的onCreate和onResume回调中尽量避免耗时的代码

e)BroadcastReceiver中onReceiver代码也要尽量减少耗时操作,建议使用intentService处理。intentService是一个异步的,会自动停止的服务,很好解决了传统的Service中处理完耗时操作忘记停止并销毁Service的问题

AsyncTask使用

异步任务类,比handler更轻量,更适合简单的异步操作

内部实现了对Thread和Handler的封装,方便后台线程操作后UI的更新

在用AsyncTask进行UI更新时,不用额外创建Handler,直接用AsyncTask内部封装好的几个方法。

三个泛型参数

AsyncTask直接继承于Object类,位置为android.os.AsyncTask,使用AsyncTask要提供三个泛型参数,作用是控制AsyncTask的子类在执行线程任务时每个阶段的返回类型

方法 描述

Params 开始异步任务执行时传入的参数类型,对应execute()中传递的参数

Progress 异步任务执行过程中,返回任务进度值的类型

Result 异步任务执行完成后,返回的结果类型,与doInBackground()的返回值类型保持一致

核心方法:

execute(),执行AsyncTask

cancel(true),取消AsyncTask

isCancelled(),判断是否被取消

执行顺序onPreExecute->doInBackground->onProgressUpdate->onPostExecute(在执行被取消时调用onCancelled)

重写方法 描述

doinBackground() 在子线程执行(异步任务)耗时操作,执行完后有返回结果

onPreExecute() 在doinBackground执行前

onProgressUpdate() 在UI线程中更新doinBackground的执行进度

onPostExecute() 接收doinBackground执行完后的返回结果,并显示到界面上去 ,如果执行被取消则无法调用

onCancelled() 在执行被取消时调用

用例

import android.os.AsyncTask;
import android.os.Bundle;
import android.view.View;
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.TextView;

public class ProgressActivity extends AppCompatActivity {

    //初始化控件
    private TextView text;
    private ImageView start,cancel;
    private ProgressBar progressBar;
    //初始化一个AsyncTask子类
    private ProgressTask pTask;

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

        progressBar=findViewById(R.id.progress_bar);
        start=findViewById(R.id.start);
        cancel=findViewById(R.id.cancel);
        text=findViewById(R.id.text);

        //实例一个AsyncTask子类
        pTask=new ProgressTask();

        start.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //执行异步任务
                pTask.execute();
            }
        });

        cancel.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //取消异步任务
                pTask.cancel(true);
            }
        });
    }

    //子类继承AsyncTask
    class ProgressTask extends AsyncTask<Void,Integer,String>{

        //执行doInBackground之前的操作
        @Override
        protected void onPreExecute() {
            super.onPreExecute();
            text.setText("加载中");
        }

        //执行任务中的耗时操作,返回线程任务的执行结果
        @Override
        protected String doInBackground(Void... voids) {
            //模拟耗时操作
            try {
                for (int i=1;i<=100;i++){
                    publishProgress(i);
                    Thread.sleep(50);
                }
                return "加载完毕";
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return null;
        }

        //在主线程中显示线程任务的执行进度,在doInBackground方法中调用publishProgress方法则触发该方法
        @Override
        protected void onProgressUpdate(Integer... values) {
            super.onProgressUpdate(values);
            progressBar.setProgress(values[0]);
            text.setText("加载..."+values[0]+"%");
        }

        //接受线程任务的执行结果,将执行结果显示在界面上
        @Override
        protected void onPostExecute(String s) {
            super.onPostExecute(s);
            if(s!=null){
                text.setText(s);
            }
            //异步任务每次只能用一次,如果还想用,再实例一次AsyncTask子类
            pTask=new ProgressTask();
        }

        //取消cancel异步任务时触发
        @Override
        protected void onCancelled() {
            super.onCancelled();
            text.setText("已取消");
            progressBar.setProgress(0);
            //异步任务每次只能用一次,如果还想用,再实例一次AsyncTask子类
            pTask=new ProgressTask();
        }
    }
}