天天看點

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