多线程通信---Handler机制

目录

作者简介:

1. 概述:

        1.1 如何把子线程中计算的结果传给主线程?

2.handler异步通信系统

        2.1 多线程通信过程 

3.代码演示 

        3.1 子线程部分

        3.2 主线程handler部分

        3.3 MainActivity代码

        3.4 布局代码 

4.效果演示

 5.拓展


作者简介:

👨‍🎓一位20级的计科专业的新手,请各位大佬多多指教 

 🏡个人主页:XiaoChen_Android

📚学习专栏:Android专栏

🕒发布日期:2022/8/7

1. 概述:

  • 进程:进程指正在运行的程序。确切的来说,当一个程序进入内存运行,即变成一个进程,进程是处于运行过程中的程序,并且具有一定独立功能。
  • 线程:线程是进程中的一个执行单元,负责当前进程中程序的执行,一个进程中至少有一个线程。一个进程中是可以有多个线程的,这个应用程序也可以称之为多线程程序。

  • 为什么要用多线程:由于Android的主线程不能执行耗时操作,如果要进行耗时操作那么必须放在子线程当中,并且子线程中只能进行一些耗时操作,不能去操作我们的UI,更新界面等操作必须在主线程中进行。

        1.1 如何把子线程中计算的结果传给主线程?

                 本文将介绍handler机制来实现多线程中的通信。

2.handler异步通信系统

  • Handler机制主要的几个角色:HandlerMessage、Looper、MessageQueue(主要用到前两个)
  • 主线程在一开始就建立了这么一套系统

 流程:

  1. handler通过SendMessage()方法发送一个消息到消息队列里面(注意不是直接发送给主线程);
  2. Looper则充当从MessageQueue中循环拿消息,它不停的在循环,只要队列里还有消息它就会不断地从里面拿,拿出来之后把这个消息又传给了handler;
  3. handler收到之后就会调用handleMessage方法来处理消息

可能会有这个疑问:消息循环一圈又回到了原点,那么为什么不直接发送给handler呢?

可以这么解释:主线程一直在往下运行的过程中,子线程不知道主线程什么时间点有空去处理消息,主线程只能不停的去看有没有消息,它就只能去消息队列里看,而Looper的作用就是帮主线程拿新的消息,这样就不会耽误主线程的运行。

打个比方:消息队列相当于我们家里的邮箱,每条消息相当于邮件,我们就是Looper,邮递员就相当于子线程,因为我们不知道什么时候会有邮件,所以我们只有每天去邮箱里查看有没有新邮件。我们需要一个中转站----MessageQueue。

所以说这个系统很重要,但是我们其实感受不到这个系统,因为Android底层已经帮我们建立好了,在Activity创建时甚至创建之前就已经建立好了,我们只需要使用handler就好了

        2.1 多线程通信过程 

    

 了解了上面的系统之后,这个流程也就容易理解了

S1:子线程首先拿到主线程的handler

S2:用主线程的handler给主线程发消息---调用SendMessage

S3:主线程通过Looper拿到消息然后调用handleMessage就可以处理消息了

3.代码演示 

        3.1 子线程部分

    //这里主线程只执行了三行代码,其余的都是子线程执行
    public void onStart(View view){
        //做耗时操作
        //创建一个子线程
        new Thread(new Runnable() {    //这以后主线程会执行
            @Override
            public void run() { //这里的方法只有子线程才会执行,主线程不会管  子线程决定什么时候执行
                String str = getStringFromNet();
                //发送消息
                Message message = new Message();
                message.what = 0; //标识
                //这里传递的是一个Stirng类型的 所以类型要用obj的
                message.obj = str;

                mhandler.sendMessage(message);


            }
        })     //子线程执行到该处就已经结束
        .start(); //主线程会执行
        Toast.makeText(this,"任务成功!",Toast.LENGTH_SHORT).show(); //这一行主线程也会执行,并且不需要等待
    }

 

        3.2 主线程handler部分

    private Handler mhandler = new Handler(Looper.myLooper()){  //这里需要传一个参数Looper.myLooper()否则会有内存泄漏警告 这里必须传主线程自己的looper
        @Override
        public void handleMessage(@NonNull Message msg) {
            super.handleMessage(msg);
            //handler收到消息执行此处
            if(msg.what == 0){    //这里就好理解what的作用了
                String data = msg.toString();
                textView.setText(data);
                Toast.makeText(MainActivity.this,"主线程已经收到消息!",Toast.LENGTH_SHORT).show();
            }
        }
    };

        3.3 MainActivity代码

package com.example.handler;

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.Button;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity {
    private TextView textView;
    private Button button;

    private Handler mhandler = new Handler(Looper.myLooper()){  //这里需要传一个参数Looper.myLooper()否则会有内存泄漏警告 这里必须传主线程自己的looper
        @Override
        public void handleMessage(@NonNull Message msg) {
            super.handleMessage(msg);
            //handler收到消息执行此处
            if(msg.what == 0){
                String data = msg.toString();
                textView.setText(data);
                Toast.makeText(MainActivity.this,"主线程已经收到消息!",Toast.LENGTH_SHORT).show();
            }
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        textView = findViewById(R.id.tv_content);
        button = findViewById(R.id.click);



    }

    //这里主线程只执行了三行代码,其余的都是子线程执行
    public void onStart(View view){
        //做耗时操作
        //创建一个子线程
        new Thread(new Runnable() {    //这以后主线程会执行
            @Override
            public void run() { //这里的方法只有子线程才会执行,主线程不会管  子线程决定什么时候执行
                String str = getStringFromNet();
                //发送消息
                Message message = new Message();
                message.what = 0; //标识
                //这里传递的是一个Stirng类型的 所以类型要用obj的
                message.obj = str;

                mhandler.sendMessage(message);


            }
        })     //子线程执行到该处就已经结束
        .start(); //主线程会执行
        Toast.makeText(this,"任务成功!",Toast.LENGTH_SHORT).show(); //这一行主线程也会执行,并且不需要等待
    }

    //为了方便就写死了  如果要网络请求也是在此处写
    private String getStringFromNet() {
        // 假装从网络获取了一个字符串
        String result = "";

        StringBuilder stringBuilder = new StringBuilder();

        // 模拟一个耗时操作
        for (int i = 0; i < 100; i++) {
            stringBuilder.append("字符串" + i);  //拼接一百个字符串
        }

        try {
            Thread.sleep(5000); //让操作慢下来
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        result = stringBuilder.toString();

        return result;
    }
}

        3.4 布局代码 

<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".MainActivity">


    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_marginRight="10dp"
        android:orientation="vertical"
        android:paddingLeft="10dp">


        <TextView
            android:id="@+id/tv_content"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"

            android:text="结果"
            />


        <Button
            android:id="@+id/click"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="10dp"
            android:text="开始"
            android:onClick="onStart"

            android:textAllCaps="false" />

    </LinearLayout>
</ScrollView>

4.效果演示

        S1:点击开始后会执行一个耗时任务,这里我设置了耗时5秒,但是立马会执行onStart方法,且Toast会立马显示,因为主线程执行的操作不耗时;

         S2:经过5秒之后,主线程会收到子线程发出的消息,然后处理消息把文本设置,同时会弹出Toast显示收到消息,到这里通信就已经成功完成了!

 5.拓展

进行异步请求还有其他的方式,比如比较流行的是AsyncTask,它是一种轻量级的异步任务,可以在线程池中执行后台任务,然后再把执行的进度和结果传递给主线程并在主线程中更新UI。详细介绍:AsyncTask使用及解析

推荐一本书:Android开发艺术探索,实践和看书结合效果更好

如果文章对你有帮助就支持一下噢,新手尝试,不好的地方请各位大佬多多指教!

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
### 回答1: Handler线程通信机制是指在多线程环境下,通过Handler进行线程间的通信和消息传递的机制HandlerAndroid中的一个类,它主要用于异步消息的处理和线程通信。当一个Handler被创建时,它会自动和当前线程的Looper对象进行绑定,从而使得该Handler可以接收和处理与该Looper关联的消息队列中的消息。 在线程间通信中,一般会涉及到两个关键的角色:发送者和接收者。发送者通过Handler将消息封装成Message对象,然后调用Handler的sendMessage()方法将消息发送到消息队列中。而接收者则通过Handler的handleMessage()方法来处理接收到的消息。 具体的线程通信流程如下: 1. 发送者线程创建一个Handler对象,并与自己的Looper进行绑定。 2. 发送者线程创建一个Message对象,并设置消息内容。 3. 发送者线程调用Handler的sendMessage()方法,将消息发送到消息队列中。 4. 接收者线程中的Looper会不断地从消息队列中取出消息,并交给接收者线程的Handler的handleMessage()方法进行处理。 5. 接收者线程的Handler处理完消息后,可以通过sendMessage()方法将结果发送给发送者线程或其他线程。 通过Handler线程通信机制,可以实现不同线程间的通信和协调。比如在子线程中进行耗时操作,然后将结果通过Handler回传到主线程进行UI更新等操作。 ### 回答2: 在Android开发中,Handler线程通信机制是一种用于在不同线程间进行通信机制。它可以将消息和任务发送到目标线程的消息队列中,然后在目标线程中执行这些消息和任务。 1. Handler的创建和使用: 首先,我们需要在目标线程中创建一个Handler对象。可以在主线程中创建Handler对象,并传入一个Looper对象作为参数。然后,我们可以通过调用Handler对象的post()、sendMessage()或其他类似方法,将消息或任务发送到目标线程的消息队列中。 2. 消息处理: 在目标线程中,Looper对象会不断地从消息队列中获取消息,然后根据消息的类型和内容进行处理。可以通过重写Handler类的handleMessage()方法来定义如何处理特定类型的消息。当有新消息到达时,Looper会调用这个方法来处理消息。 3. 线程通信: 通过使用Handler线程通信机制,我们可以在不同线程之间传递消息和任务。例如,我们可以在后台线程中执行耗时的计算,并使用Handler将计算结果发送到主线程,然后在主线程中更新UI界面。这样,我们就可以实现后台计算和UI更新的异步处理。 4. 消息队列和消息循环: Handler线程通信机制基于消息队列和消息循环的概念。消息队列是一个先进先出的数据结构,用于存储消息和任务。消息循环是一个不断循环的过程,在每次循环中,消息队列会被检查,如果队列中有消息,就会被取出并处理。 5. 线程安全: Handler线程通信机制是线程安全的,因为消息队列的访问是同步的。不同线程可以通过Handler对象将消息和任务发送到同一个消息队列中,这些消息和任务会被逐个处理,避免了多线程并发访问的问题。 总之,Handler线程通信机制Android开发中一种常用的线程间通信机制,它可以将消息和任务发送到目标线程的消息队列中,然后在目标线程中处理这些消息和任务。它在后台计算和UI更新、线程安全等方面都具有重要的作用。 ### 回答3: Handler线程通信机制Android中一种常见的线程间通信方式。HandlerAndroid中的一个类,它功能强大,可以用于创建一个与特定线程关联的消息队列,从而实现线程间的通信。 在使用Handler线程通信机制时,一般分为两个角色:发送消息的线程和接收消息的线程。发送消息的线程使用Handler对象发送消息,而接收消息的线程则通过重载Handler类的handleMessage()方法来处理接收到的消息。发送消息的线程将消息封装成Message对象,然后通过Handler的sendMessage()方法将消息发送给接收消息的线程。接收消息的线程在handleMessage()方法中根据消息的种类来处理相应的任务。 Handler线程通信机制的实现主要有以下几个步骤: 1. 创建Handler对象:在接收消息的线程中创建一个Handler对象,用于接收和处理消息。 2. 发送消息:在发送消息的线程中,通过Handler对象的sendMessage()方法将消息发送给接收消息的线程。消息可以通过Message类来创建,并且可以通过Message的arg1、arg2和obj属性来传递一些额外的数据。 3. 处理消息:接收消息的线程需要重载Handler类的handleMessage()方法,该方法用于处理接收到的消息。根据消息的种类,可以使用switch语句来处理不同的消息类型。 4. 更新UI:如果接收消息的线程和UI线程需要进行通信,可以在handleMessage()方法中更新UI相关的内容。可以使用post()方法或者runOnUiThread()方法来在UI线程中更新UI。 5. 销毁Handler:在不需要使用Handler对象的时候,应该调用Handler的removeCallbacksAndMessages()方法取消消息的发送,并且释放相关资源。 通过Handler线程通信机制,可以实现不同线程之间的通信和协作,提高应用程序的灵活性和响应性。它是Android开发中常用的一种线程间通信方式。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值