Android利用Thread或AsyncTask進行非UI操作


在Android中調用一些操作,如網絡請求,必須強制使用非UI線程,如果在UI線程當中調用就會報錯!

因此,線程操作是Android當中使用非常普遍,在線程中進行對應操作,最后把結果回傳給UI線程,由UI線程進行結果的顯示!

這里介紹兩種線程操作!

 1、Thread+Handler

這種方法是最原始,也是最靈活的方式,完全沒有被封裝,但是使用起來相對也復雜一些!

主要的步驟為:

1)創建Handler,用於接收線程完成后回傳的結果

private Handler resultHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            
            // 關閉加載控件
            if(progressDialog != null && progressDialog.isShowing()) {
                    progressDialog.dismiss();
            }
            
            // 處理返回結果
            if(msg.what == 0) {
              // 調用成功,顯示結果
              ResultData resultData = (ResultData) msg.obj;
              
              tv_name.SetText(resultData.name);
            }
            else {
                // 調用失敗
                String err = (String) msg.obj;
                
                Toast.makeText(context, err, Toast.LENGTH_SHORT).show();
            }
        }
}

 

 

2)創建Thread,在當中進行耗時操作

// 調用前顯示加載控件
progressDialog = ProgressDialog.show(ReservationListActivity.this, "提示", "正在加載數據...");

// 開始線程並加載數據
new Thread(new Runnable() {
            
            @Override
            public void run() {
                // 線程處理過程
                ...
                
                // 返回成功結果
                ResultData resultData = new ResultData();
                resultData.name = "張三";
                
                Message msg = Message.obtain();
                msg.what = 0;
                msg.obj = resultData;
                resultHandler.sendMessage(msg);
                
                
                // 返回失敗結果
                Message msg = Message.obtain();
                msg.what = -1;
                msg.obj = "結果不存在";
                resultHandler.sendMessage(msg);
            }
        }).start();

 

這種方法其實比較簡單,通過Thread執行耗時操作,在操作完成后,向Handler發送消息,同時把結果傳遞進去;

之后Handler接收到傳遞過來的消息,根據消息的內容進行不同的處理,如成功、失敗等!

多個Thread的返回可以共用一個Handler,只需要在結果那里處理好區分即可。

也有許多人將此操作封裝成一個類,這樣調用起來更簡便,原理是一樣的。

 

 

2、AsyncTask

 

這種方法是Google推薦的方法,原理與Thread+Handler類似,但是Google進行了封裝,使用起來更方便一些。

使用時,需要對AsyncTask進行繼承,其原型為:AsyncTask<Params,Progress,Result>,這里需要說明一下:

Params        啟動任務時輸入的參數類型

Progress      后台任務執行中返回進度值的類型

Result          后台任務執行完成后返回結果的類型

這樣傳參,進度,返回都已經包含在內了,如果傳參,返回的數據較復雜,可定義為類進行傳輸

AsyncTask主要的重載函數包括:

doInBackground      必須重寫,異步執行后台線程要完成的任務,耗時操作將在此方法中完成.

onPreExecute          執行后台耗時操作前被調用,通常用於進行初始化操作.

onPostExecute        當doInBackground方法完成后,系統將自動調用此方法,並將doInBackground方法返回的值傳入此方法.通過此方法進行UI的更新.

onProgressUpdate  當在doInBackground方法中調用publishProgress方法更新任務執行進度后,將調用此方法.通過此方法我們可以知曉任務的完成進度.

一般我們只需要用到 doInBackground 和 onPostExecute。

// 調用前顯示加載控件
progressDialog = ProgressDialog.show(ReservationListActivity.this, "提示", "正在加載數據...");

// 這里定義輸入參數為String類型,輸出參數為ReaultData類型
new AsyncTask<String, Void, ReaultData>(){
    
            // 在后台執行的過程函數,所有耗時操作放在此函數中執行
            @Override
            protected AsyncFilesData doInBackground(String... params) {
                // params 即傳入的參數,此例中就是 "http://www.abc.com/api/getinfo?id=10"
                url = params[0];
                
                // 定義返回結果對象
                ResultData resultData = new ReaultData();
                
                try {
                    String str = geturl(url);
                    resultData = JSONObject.parseObject(str, ResultData.class);
                    return resultData;
                }
                catch(Exception ex) {
                    resultData.result = -1;
                    resultData.msg = ex.getMessage();
                    return resultData;
                }
            }
            
            
            // doInBackground返回結果后會自動調用此函數
            // 此函數是在 UI 線程當中被調用,因此可將對UI的操作放在當中執行
            @Override
            protected void onPostExecute(ResultData resultData) {
                // 關閉加載控件
                if(progressDialog != null && progressDialog.isShowing()) {
                        progressDialog.dismiss();
                }
                
                // 處理返回結果
                if(resultData.result == 0) {
                  // 調用成功,顯示結果
                  tv_name.SetText(resultData.name);
                }
                else {
                    // 調用失敗
                    String err = resultData.msg;
                    
                    Toast.makeText(context, err, Toast.LENGTH_SHORT).show();
                }
            }
            // 傳入的參數是調用一個Webapi獲取指定ID的info
        }.execute("http://www.abc.com/api/getinfo?id=10");    

AsyncTask的優勢是書寫簡單,且 onPostExecute 已在UI線程當中,不必再處理線程向UI線程同步問題。

 

這就是今天介紹的兩種線程調用同步方法!

 

 

 


注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
粤ICP备14056181号  © 2014-2020 ITdaan.com