欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Android同步異步任務(wù)與多線程及Handler消息處理機(jī)制基礎(chǔ)詳細(xì)講解

 更新時間:2022年11月24日 16:12:48   作者:發(fā)飆的蝸牛YR  
這篇文章主要介紹了Android同步異步任務(wù)與多線程及Handler消息處理機(jī)制基礎(chǔ),handler其實(shí)就是主線程在起了一個子線程,子線程運(yùn)行并生成Message,Looper獲取message并傳遞給Handler,Handler逐個獲取子線程中的Message,感興趣的小伙伴快跟隨小編一起學(xué)習(xí)一下

同步與異步

同步的執(zhí)行任務(wù):在執(zhí)行程序時,如果沒有收到執(zhí)行結(jié)果,就一直等,不繼續(xù)往下執(zhí)行,直到收到執(zhí)行結(jié)果,才接著往下執(zhí)行。

異步的執(zhí)行任務(wù):在執(zhí)行程序時,如果遇到需要等待的任務(wù),就另外開辟一個子線程去執(zhí)行它,自己繼續(xù)往下執(zhí)行其他程序。子線程有結(jié)果時,會將結(jié)果發(fā)送給主線程

Android中的多線程

線程:通俗點(diǎn)講就是一個執(zhí)行過程。多線程自然就是多個執(zhí)行過程而已。

程序中可能有多個任務(wù),如果只有一個線程,那么就只能一個接一個的執(zhí)行了。類似同步執(zhí)行任務(wù)。很明顯會比較慢,因?yàn)橹挥猩弦粋€任務(wù)執(zhí)行完,才能進(jìn)行下一個。

因此,我們需要多線程來分別執(zhí)行這些任務(wù)。這也就是對應(yīng)了上面說的異步執(zhí)行任務(wù)。

Android中的多線程與主線程與子線程

類比到我們Android app程序。App一啟動,本身就是一個線程,這個線程被稱為主線程mainThread,負(fù)責(zé)顯示界面,跟用戶交互。

另外,界面通常被稱為UI(User Interface),因此,主線程也被稱為UI線程。

兩個原則:

主線程不能執(zhí)行網(wǎng)絡(luò)請求/文件讀寫等耗時操作

子線程不能執(zhí)行UI刷新

package com.example.androidnetwork;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;
public class MainActivity2 extends AppCompatActivity {
    private TextView tvContent;
    private String strFromNet;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main2);
        tvContent = findViewById(R.id.tv_content);
    }
    public void start(View view) {
        //做一個耗時任務(wù)
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                String stringFromNet = getStrFromNet();
                //子線程中執(zhí)行UI操作會報錯
                tvContent.setText(stringFromNet);
            }
        });
        thread.start();
        Toast.makeText(this, "任務(wù)完成!", Toast.LENGTH_SHORT).show();
    }
    private String getStrFromNet() {
        //假裝從網(wǎng)絡(luò)上獲取了一個字符串
        String result = " ";
        StringBuilder stringBuilder = new StringBuilder();
        //模擬一個耗時操作
        for (int i = 0; i < 100; i++) {
            stringBuilder.append("字符串" + i);
        }
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        result = stringBuilder.toString();
        return result;
    }
}

報錯:android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.

說明只有主線程才能進(jìn)行View里的UI操作進(jìn)行交互。

Handler異步通信系統(tǒng)

Handler機(jī)制主要的幾個角色:Handler、Message、Looper、MessageQueue

異步消息Handler處理機(jī)制

首先在主線程當(dāng)中創(chuàng)建一個Handler對象,并重寫handleMessage()方法。然后當(dāng)子線程中需要進(jìn)行UI操作時,就創(chuàng)建一個Message對象,并通過Handler將這條消息發(fā)送出去。之后這條消息就會被添加到MessageQueue隊(duì)列中等待被處理,而Looper則會一直嘗試從MessageQueue中取出待處理消息,最后分發(fā)回Handler的handleMessage()方法中。由于Handler是在主線程中創(chuàng)建的,所以此時handleMessage()方法中的代碼也會在主線程中運(yùn)行,所以可以安心的進(jìn)行UI操作。

這樣一條Message經(jīng)過這樣一個流程的輾轉(zhuǎn)調(diào)用后,也就從子線程進(jìn)入到了主線程,從而從不能更新UI到能更新UI。

Looper和MessageQueue會在UI線程創(chuàng)建時就存在,如果在子線程中就需要自己寫Looper。

會出現(xiàn)這樣一個警告,表示內(nèi)存泄漏,leak是泄漏的意思。

private Handler mHandler=new Handler(Looper.myLooper()){

只需要寫上Looper.myLooper()就不報警告,表示取主線程自己的Looper。

what用于區(qū)分是誰發(fā)的消息

arg1,arg2,obj相當(dāng)于一個變量,用于標(biāo)識,區(qū)分

sendMessage發(fā)送有消息的

sendEmptyMessage發(fā)送空消息,啥都沒有,觸發(fā)一下而已

下面是使用Handle機(jī)制進(jìn)行延時6s后將信息顯示到文本框上

package com.example.androidnetwork;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;
public class MainActivity2 extends AppCompatActivity {
    private TextView tvContent;
    private String strFromNet;
    //Handler處在主線程里,本身處理UI界面是沒問題的
    private Handler mHandler=new Handler(Looper.myLooper()){
        @Override
        public void handleMessage(@NonNull Message msg) {
            //此時的參數(shù)msg就是我們傳過去的message
            if(msg.what==0){
                String strData=(String)msg.obj;
                tvContent.setText(strData);
                Toast.makeText(MainActivity2.this, "主線程收到消息!", Toast.LENGTH_SHORT).show();
            }
        }
    };
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main2);
        tvContent = findViewById(R.id.tv_content);
    }
    public void start(View view) {
        //做一個耗時任務(wù)
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                String stringFromNet = getStrFromNet();
                //子線程中執(zhí)行UI操作會報錯
                //tvContent.setText(stringFromNet);
                Message message=new Message();
                message.what=0;
                message.obj=stringFromNet;
                mHandler.sendMessage(message);
            }
        });
        thread.start();
        Toast.makeText(this, "任務(wù)完成!", Toast.LENGTH_SHORT).show();
    }
    private String getStrFromNet() {
        //假裝從網(wǎng)絡(luò)上獲取了一個字符串
        String result = " ";
        StringBuilder stringBuilder = new StringBuilder();
        //模擬一個耗時操作
        for (int i = 0; i < 100; i++) {
            stringBuilder.append("字符串" + i);
        }
        try {
            Thread.sleep(6000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        result = stringBuilder.toString();
        return result;
    }
}

其實(shí)在執(zhí)行new Thread過程中就是一個異步的

比如:

public void start(View view) {
        //做一個耗時任務(wù)
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                String stringFromNet = getStrFromNet();
                //子線程中執(zhí)行UI操作會報錯
                tvContent.setText(stringFromNet);
            }
        });
        thread.start();
        Toast.makeText(this, "任務(wù)完成!", Toast.LENGTH_SHORT).show();
    }

主線程會先執(zhí)行 Thread thread = new Thread(new Runnable() {和thread.start();Toast.makeText(this, “任務(wù)完成!”, Toast.LENGTH_SHORT).show();而 @Override public void run() {

String stringFromNet = getStrFromNet();tvContent.setText(stringFromNet);}

會當(dāng)主線程執(zhí)行到了thread.start();的時候子線程才會去執(zhí)行

使用新線程計(jì)算質(zhì)數(shù)

package com.example.androidnetwork;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
import java.util.ArrayList;
import java.util.List;
public class MainActivity2 extends AppCompatActivity {
    public final static String UPPER_NUM = "upper";
    private EditText etNum;
    private CalThread mCalThread;
    class CalThread extends Thread {
        private Handler mHandler;
        @Override
        public void run() {
            Looper.prepare();
            mHandler = new Handler() {
                //定義處理消息的方法
                @Override
                public void handleMessage(@NonNull Message msg) {
                    if (msg.what == 0x123) {
                        int upper = msg.getData().getInt(UPPER_NUM);
                        List<Integer> nums = new ArrayList<>();
                        outer:
                        //計(jì)算從2開始,到upper的所有質(zhì)數(shù)
                        for (int i = 2; i <= upper; i++) {
                            //用i除以從2開始,到i的平方根的所有數(shù)
                            int j = 2;
                            while (j <= Math.sqrt(i)) {
                                //如果可以整除,則表明這個數(shù)不是質(zhì)數(shù)
                                if (i != 2 && i % j == 0) {
                                    continue outer;
                                }
                                j++;
                            }
                            nums.add(i);
                        }
                        //使用Toast顯示統(tǒng)計(jì)出來的所在質(zhì)數(shù)
                        Toast.makeText(MainActivity2.this, nums.toString(), Toast.LENGTH_SHORT).show();
                    }
                }
            };
            Looper.loop();
        }
    }
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main2);
        etNum=findViewById(R.id.et_num);
        mCalThread=new CalThread();
        //啟動新線程
        mCalThread.start();
    }
    //為按鈕的點(diǎn)擊事件提供事件處理方法
    public void cal(View view){
        Log.d("====", "cal: +ddasdsadas");
        //創(chuàng)建消息
        Message msg=new Message();
        msg.what=0x123;
        Bundle bundle=new Bundle();
        bundle.putInt(UPPER_NUM,Integer.parseInt(etNum.getText().toString()));
        msg.setData(bundle);
        //向新線程中的Handler發(fā)送消息
        mCalThread.mHandler.sendMessage(msg);
    }
}

在子線程(或新線程處理Handler消息的方法)

1.調(diào)用Looper的prepare()方法為當(dāng)前線程創(chuàng)建Looper對象,創(chuàng)建Looper對象時,它的構(gòu)造器會創(chuàng)建與之配套的MessageQueue。

2.有了Looper之后,創(chuàng)建Handler子類的實(shí)例,重寫handlerMessage()方法,該方法負(fù)責(zé)處理來自其他線程的消息。

3.調(diào)用Looper的loop()方法啟動Looper。

到此這篇關(guān)于Android同步異步任務(wù)與多線程及Handler消息處理機(jī)制基礎(chǔ)詳細(xì)講解的文章就介紹到這了,更多相關(guān)Android同步異步內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評論