IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> Android | 第4章 | Handler多线程消息传递机制 | Bundle封装数据 | Message消息发送 +Demo -> 正文阅读

[移动开发]Android | 第4章 | Handler多线程消息传递机制 | Bundle封装数据 | Message消息发送 +Demo

1. Java Thread多线程


Adnroid官方文档

两种方式创建并启动线程

  • 方式一: 继承 java.lang.Thread 并重写run()
class myThread extends Thread{
    // 成员变量
    private int num;
    myThread(int num){
        this.num = num;
    }
    @Override
    public void run(){
        //... 
    }
}
// 启动线程
new myThread(10).start();
  • 方式二:实现 Runnable 接口
class myThread implements Runnable{
    private int num;
    myThread(int num){
        this.num = num;
    }
    @Override
    public void run(){
        //...
    }
}
// 启动线程
new Thread(new myThread(10)).start();

2. Handler


Handler : 线程之间传递消息的即时接口,生产线程和消费线程调用以下操作使用Handler:

  • 在消息队列创建、插入或移除消息
  • 在消费线程中处理消息

每个Handler有一个与之相关的 Looper 和消息队列MessageQueue。

同一线程的多个Handler分享一个同样的消息队列,因为他们分享的Looper对象是同一个。

关于Handler的构造函数官方文档

函数名描述
Handler()已弃用
Handler(Handler.Callback callback)已弃用
Handler(Looper looper)使用提供的looper对象
Handler(Looper looper, Handler.Callback callback)使用提供的looper对象和回调接口来处理消息

在构造函数中,looper对象可以通过Looper.myLooper() 创建并获取

3. Message


官方文档

Message 是容纳任意数据的容器,是Handler接收与处理的消息对象。

生产消息发送消息给Handler,Hadnler将消息加入到消息队列中。

该对象提供三种信息,以便Handler和消息队列处理时使用:

  • what 一种标识符,Hander能使用它区分不同消息,从而采取不同的处理方法
  • time 告知消息队列何时处理消息
  • target 表示哪一个Handler 应当处理消息

该对象的创建方式有:

Handler.obtainMessage();	
Handler.obtainMessage(int what);
Handler.obtainMessage(int what, Object obj);
Handler.obtainMessage(int what, int arg1, int arg2);
Handler.obtainMessage(int what, int arg1, int arg2, Object obj);

通过Bundle对象设置消息的数据

public void setData (Bundle data);

4. MessageQueue


官方文档

消息队列(为方便阅读,简写为MQ),以FIFO方式管理所有的Message对象。

是一个LinkedList集合

  • 在初始化Looper对象时会创建一个与之关联的MQ
  • 每个线程最多只有一个MQ
  • MQ通常是由 Looper 管理
  • 主线程创建时,会创建一个默认的Looper对象,从而自动创建一个MQ

5. Looper


官方文档

负责从消息队列MessageQueue中读取消息,然后分发给对应的Handler处理。

每个线程只能管理一个Looper。

使用范例:

 class LooperThread extends Thread {
      public Handler mHandler;

      public void run() {
          Looper.prepare();

          mHandler = new Handler(Looper.myLooper()) {
              public void handleMessage(Message msg) {
                  // process incoming messages here
              }
          };

          Looper.loop();
      }
  }

6. AtomicBoolean


作为 java.util.concurrent.atomic 包下的一个类,指原子性的Boolean类型

该类实现的是在多线程环境下,具有排他性,不会被打断,常用方法:

方法名描述
get()获取当前的值返回true或false
set(Boolean nueValue)设置新的布尔值

构造方法:initialValue(Boolean b)

7. Handler使用总结


首先在AppCompatActivity.java类中创建 h a n d l e r handler handler 对象,传入两个参数,第一个是 l o o p e r looper looper,第二个是 C a l l b a c k ( ) Callback() Callback()接口的实现类,

该接口方法实现的是当线程接收到消息 m e s s a g e message message 时做出的响应,在倒计时的案例里就是更新 T e x t V i e w TextView TextView,即显示当前的数字。

综上,Handler作为线程之间传递消息的接口,实现步骤为:

  • App主类负责编写handler对象接收到消息后的处理逻辑
  • 线程类负责存储handler对象,以及在run方法里编写向Handler传递消息的具体实现

Handler传输的消息对象Message里的数据是通过对Java的数据类型或对象进行封装后的Bundle对象来传输的。

8. 案例


8.1 倒计时

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;

class TimeCountThread extends Thread{
    private Handler handler;
    private int timecount;
    public TimeCountThread(Handler handler, int timecount){
        this.handler = handler;
        this.timecount = timecount;
    }

    @Override
    public void run() {
        for(int i = timecount; i >= 0; i--) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            Message message = handler.obtainMessage();
            Bundle bundle = new Bundle();
            bundle.putInt("Now", i);
            message.setData(bundle);
            handler.sendMessage(message);
        }
    }
}
public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        TextView tv = findViewById(R.id.TextView);
        Handler handler = new Handler(Looper.myLooper(), new Handler.Callback() {
            @Override
            public boolean handleMessage(@NonNull Message message) {
                tv.setText(message.getData().getInt("Now") + "");
                return false;
            }
        });
        new TimeCountThread(handler, 100).start();
    }
}

8.2 计时器

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aJWYkNig-1641100059067)(AndroidLearn-Handler.assets/image-20211109191727880.png)]

layout_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <TextView
        android:id="@+id/tv_result"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="0.00" />

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="horizontal"
        >


        <Button
            android:id="@+id/b_start"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:layout_marginHorizontal="10px"
            android:text="Start"
            />

        <Button
            android:id="@+id/b_stop"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:enabled="false"
            android:layout_marginHorizontal="10px"
            android:text="Stop" />
    </LinearLayout>

</LinearLayout>

TimerCounterThread.java

package com.example.ycc_task4_1;

import android.os.Bundle;
import android.os.Handler;
import android.os.Message;

import java.util.concurrent.atomic.AtomicBoolean;

public class TimerCounterThread extends Thread{
    public static final String KEY_TIME_COUNTER = "key_time_counter";
    private Handler handler;
    private AtomicBoolean isRunning;
    private float timeCount=0.0f;

    public TimerCounterThread(Handler handler) {
        this.handler = handler;
        isRunning = new AtomicBoolean(false);
    }

    @Override
    public void run() {
        super.run();
        isRunning.set(true);
        while(isRunning.get()){
            try{
                Thread.sleep(100);
                timeCount += 0.10f;
                sendCounter();
            } catch (InterruptedException e){
                e.printStackTrace();
            }
        }
    }
    private void sendCounter(){
        Message mes = handler.obtainMessage();
        Bundle bundle = new Bundle();
        bundle.putFloat(KEY_TIME_COUNTER, timeCount);
        mes.setData(bundle);
        handler.sendMessage(mes);
    }
    public void stopTimer(){
        isRunning.set(false);
    }
}

MainActivity.java

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 java.util.concurrent.atomic.AtomicBoolean;

public class MainActivity extends AppCompatActivity {
    Button b_start, b_stop;
    TextView tv;
    TimerCounterThread thread;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.layout_main);
        b_start = findViewById(R.id.b_start);
        b_stop = findViewById(R.id.b_stop);
        tv = findViewById(R.id.tv_result);

        // 创建 Handler
        final Handler handler = new Handler(Looper.myLooper(), new Handler.Callback(){
            @Override
            public boolean handleMessage(@NonNull Message message) {
                Bundle data = message.getData();
                float timeCounter = data.getFloat(TimerCounterThread.KEY_TIME_COUNTER);
                tv.setText(String.format("%.2f", timeCounter));
                return false;
            }
        });

        b_start.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                thread = new TimerCounterThread(handler);
                thread.start();
                b_start.setEnabled(false);
                b_stop.setEnabled(true);
            }
        });
        b_stop.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                thread.stopTimer();
                b_start.setEnabled(true);
                b_stop.setEnabled(false);
            }
        });

    }
}

8.3 获取网页内容

首先需要在项目的 mainifests/AndroidMainifest.xml 里的 <application>标签添加

<uses-permission android:name="android.permission.INTERNET"></uses-permission>

允许项目进行网络访问

在这里插入图片描述

layout_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical"
    >

    <EditText
        android:id="@+id/editText"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="https://www.baidu.com" />

    <Button
        android:id="@+id/button"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Get Web" />

    <ScrollView
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical" >

            <TextView
                android:id="@+id/tv_ack"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:text="" />
        </LinearLayout>
    </ScrollView>
</LinearLayout>

JsoupGetThread.java

package com.example.ycc_task4_2;

import android.os.Bundle;
import android.os.Handler;
import android.os.Message;

import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;

import java.io.IOException;

public class JsoupGetThread extends Thread{
    private static final String HTML_ACK = "html_ack";
    private String url;
    private Handler handler;

    public JsoupGetThread(String url, Handler handler) {
        this.url = url;
        this.handler = handler;
    }
    public static String getMessage(Message mes){
        Bundle data = mes.getData();
        return data.getString(HTML_ACK);
    }

    @Override
    public void run() {
        String ack;
        try{
            Document doc = Jsoup.connect(url).timeout(10000).get();
            ack = doc.toString();
        } catch (IOException e){
            e.printStackTrace();
            ack = e.toString();
        }
        Message mes = handler.obtainMessage();
        Bundle bundle = new Bundle();
        bundle.putString(HTML_ACK, ack);
        mes.setData(bundle);
        handler.sendMessage(mes);
    }
}

MainActivity.java

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {

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

        TextView tv = findViewById(R.id.tv_ack);
        Handler handler = new Handler(new Handler.Callback(){
            @Override
            public boolean handleMessage(@NonNull Message message) {
                String s = JsoupGetThread.getMessage(message);
                tv.setText(s);
                return false;
            }
        });
        EditText et = findViewById(R.id.editText);
        Button bt = findViewById(R.id.button);
        bt.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                String url = et.getText().toString();
                new JsoupGetThread(url, handler).start();
            }
        });
    }
}

参考博文(侵删)

  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2022-01-03 16:13:34  更:2022-01-03 16:14:49 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 10:02:11-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码