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();
}
}
}