Android第一行代碼(十二)多線程編程

線程的基本用法:

定義一個線程只需要新建一個類繼承自Thread,然后重新父類的run()方法,并在里面編寫耗時邏輯即可

class MyThread extends Thread{
    @Override
    public void run(){
        //處理具體的邏輯
    }
}

然后啟用這個線程,只需要調(diào)用該類的start方法即可:

new MyThread().start()

但是使用繼承的方式耦合性有點高,更多時候選擇使用實現(xiàn)Runable接口的方式來定義一個線程

class MyThread implemens Runnable {
    @Override
    public void run(){
        //處理具體邏輯
    }
}

使用這種寫法,啟動線程是:

MyThread myThread = new MyThread();
new Thread(myThread).start();

Android是不允許在子線程中進行UI操作的,我們可以利用Android提供的異步消息機制,來解決在子線程中進行UI操作的問題。

public class MainActivity extends AppCompatActivity {

    public  static final int UPDATE_TEXT = 1;

    private TextView text;

    //消息接收處理的handler
    private Handler handler = new Handler(){
        @Override
        public void handleMessage(Message msg) {
              
            switch (msg.what){
                case UPDATE_TEXT:
                    Log.d("MainActivity","test");

                    //在這里進行UI操作
                    Log.d("MainActivity",""+msg.arg1);
                    text.setText("Nice to meet you");
                    break;
                default:
                    break;
            }
        }
    };

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

        text = (TextView)findViewById(R.id.text);
        Button changeText = (Button)findViewById(R.id.change_text);
        changeText.setOnClickListener(new View.OnClickListener(){
            @Override
            public void onClick(View v) {
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        //在子線程里發(fā)送更新文字的message
                        Message message = new Message();
                        message.what = UPDATE_TEXT;
                        message.arg1 = 1;
                        handler.sendMessage(message);
                    }
                }).start();
            }
        });
    }
}

解析異步消息處理機制:

Android的異步消息處理主要由4個部分組成:Message、Handler、MessageQueue和Looper

  1. Message
    Message 是在線程之間傳遞的消息,可在內(nèi)部攜帶少量的信息,用于不同線程之間交換數(shù)據(jù)。
    有what、arg1、arg2來攜帶一些整形數(shù)據(jù),使用obj字段攜帶一個Object對象
  2. Handler
    Handler 顧名思義也就是處理者的意思,它主要是用于發(fā)送和處理消息。
    發(fā)送消息一般使用Handler的sendMessage()方法;處理消息使用Handler的 handleMessage()方法
  3. MessageQueue
    MessageQueue是消息隊列的意思,它主要是用于存放所有通過Handler發(fā)送的消息。這部分消息會一直存放在消息隊列中,等待被處理。每個線程中只會有一個Message對象。
  4. Looper
    Looper是每個線程中的MessageQueue的管家,調(diào)用Looper的loop()方法后,就會進入到一個無線循環(huán)當(dāng)中,然后每當(dāng)發(fā)現(xiàn)MessageQueue中存在一條消息,就會將它取出,并傳遞到Handler的handleMessage()方法當(dāng)中
異步消息處理流程.png

使用AsyncTask

由于AsyncTask是一個抽象類,所以要使用它,就必須創(chuàng)建一個子類去繼承它。在繼承時,可以為AsyncTask類指定3個泛型參數(shù),這3個參數(shù)的用途如下:

  1. Params
    在執(zhí)行AsyncTask時需要傳入的參數(shù),可用于在后臺任務(wù)中使用
  2. Progress
    后臺任務(wù)執(zhí)行時,如果需要在界面上顯示當(dāng)前進度,則使用這里指定的泛型作為進度單位
  3. Result
    當(dāng)任務(wù)執(zhí)行完畢后,如果需要對結(jié)果進行返回,則使用這里指定的泛型作為返回值類型

使用AsyncTask還經(jīng)常需要重寫以下4個方法:

  1. onPreExecute()
    在后臺任務(wù)開始執(zhí)行之前調(diào)用,用于進行一些界面上的初始化操作,比如顯示一個進度條對話框

  2. doInBackground(Params...)
    這個方法中所有的代碼都在子線程執(zhí)行,應(yīng)該在這里處理所有的耗時任務(wù)。在這個方法中是不能進行UI操作的,只能調(diào)用publishProgress(Progress...)方法將數(shù)值傳遞出去,并觸發(fā) onProgressUpdate(Progress...)方法

  3. onProgressUpdate(Progress...)
    當(dāng)在后臺任務(wù)中調(diào)用了publishProgress(Progress...)方法后,onProgressUpdate(Progress...)方法就會很快被調(diào)用,該方法中攜帶的參數(shù)就是在后臺任務(wù)中傳遞過來的,在這個方法中可以對UI進行操作。

  4. onPostExecute(Result)
    后臺任務(wù)執(zhí)行完畢并通過return語句進行返回時,這個方法就很快被調(diào)用,返回的數(shù)據(jù)就會作為參數(shù)傳遞到此方法之中,可以利用返回的數(shù)據(jù)來進行一些UI操作。

    public class DownloadTask extends AsyncTask<Void,Integer,Boolean> {
    ProgressDialog progressDialog = new ProgressDialog();

     @Override
     protected void onPreExecute() {
         progressDialog.show(); //顯示進度對話框
     }
    
     @Override
     protected Boolean doInBackground(Void... params) {
         try {
             while (true) {
                 int downloadPercent = doDownload();
                 //此處調(diào)用publishProgress()方法,會觸發(fā) onProgressUpdate()方法
                 publishProgress(downloadPercent);
                 if (downloadPercent >= 100) {
                     break;
                 }
             }
         }catch(Exception e){
             return false;
         }
             return  true;
    
         }
     }
    
     @Override
     protected void onProgressUpdate(Integer... values) {
         //在這里進行UI操作,更新進度條
         progressDialog.setMessage("Downloaded " + values[0] + "%");
     }
    
     @Override
     protected void onPostExecute(Boolean result) {
         progressDialog.dismiss();
         //在這里提示下載結(jié)果
         if(result) {
             Toast.makeText(context, "Download successed", Toast.LENGTH_SHORT).show();
         }else {
             Toast.makeText(context, "Download faild", Toast.LENGTH_SHORT).show();
         }
     }
    

    }

啟用這個任務(wù),只需要

new DownloadTask().execute();

簡單來說,使用AsyncTask的訣竅就是,在onPreExecute()方法中進行初始化工作,在doInBackground()方法中執(zhí)行具體的耗時任務(wù),在onProgressUpdate()方法中進行UI操作,在onPostExecute()方法中執(zhí)行一些任務(wù)的收尾工作。
而調(diào)用publishProgress()方法,能夠?qū)?shù)據(jù)從后臺傳遞到主線程,觸發(fā)onProgressUpdate(Progress...)方法

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容