《Android 应用开发基础教程》——第十四章:Android 多线程编程与异步任务机制(Handler、AsyncTask、线程池等)

news2025/6/9 9:20:15

目录

第十四章:Android 多线程编程与异步任务机制(Handler、AsyncTask、线程池等)

🔸 14.1 为什么需要多线程?

🔸 14.2 Handler + Thread 模型

✦ 使用 Handler 与 Thread 进行线程通信

✦ 简要说明:

🔸 14.3 Handler 消息机制详解

🔸 14.4 AsyncTask(适用于早期项目)

🔸 14.5 使用 Java 原生线程池(ThreadPoolExecutor)

✦ 优点:

🔸 14.6 Kotlin 开发推荐:协程 Coroutines(了解即可)

🔸 14.7 主线程中更新 UI 的常见方式总结

✅ 总结

小Demo(原来的习题板块)

项目结构

1. activity_main.xml

2. MainActivity.java

3. AndroidManifest.xml

代码说明

1. Handler + Thread 示例

2. AsyncTask 示例

3. 线程池示例

运行效果

总结


第十四章:Android 多线程编程与异步任务机制(Handler、AsyncTask、线程池等)


        Android 应用运行在单一的 UI 主线程(也叫 主线程 / UI Thread)上。为了避免阻塞界面、提升用户体验,我们需要将耗时操作(如网络请求、数据库访问、文件读写等)放到子线程中执行。本章将系统介绍 Android 中的多线程处理机制,包括 Handler、AsyncTask(已弃用但仍有参考意义)与线程池。


🔸 14.1 为什么需要多线程?

        在 Android 中,所有的 UI 更新必须在主线程中执行。如下操作若直接在主线程执行,可能导致 ANR(应用无响应):

  • 网络请求

  • 数据库操作

  • 大文件处理

  • 解码操作(如 Bitmap)


🔸 14.2 Handler + Thread 模型

✦ 使用 Handler 与 Thread 进行线程通信

Handler handler = new Handler(Looper.getMainLooper());

new Thread(() -> {
    // 耗时操作(如模拟网络请求)
    try { Thread.sleep(2000); } catch (InterruptedException e) { }
    
    // 回到主线程更新 UI
    handler.post(() -> {
        textView.setText("任务完成");
    });
}).start();

✦ 简要说明:

  • Thread:负责在子线程中执行耗时任务

  • Handler.post():用于将 UI 更新任务发送回主线程执行


🔸 14.3 Handler 消息机制详解

Handler handler = new Handler(Looper.getMainLooper()) {
    @Override
    public void handleMessage(Message msg) {
        if (msg.what == 1) {
            textView.setText("收到消息:" + msg.obj.toString());
        }
    }
};

new Thread(() -> {
    Message message = handler.obtainMessage();
    message.what = 1;
    message.obj = "数据加载完成";
    handler.sendMessage(message);
}).start();


🔸 14.4 AsyncTask(适用于早期项目)

⚠️ 从 Android 11 开始已被官方标记为 deprecated,但仍可用于了解异步结构设计思路。

 
private class MyTask extends AsyncTask<Void, Void, String> {

    @Override
    protected void onPreExecute() {
        // 主线程:任务开始前(初始化 UI)
        progressBar.setVisibility(View.VISIBLE);
    }

    @Override
    protected String doInBackground(Void... voids) {
        // 子线程:执行耗时操作
        return "任务结果";
    }

    @Override
    protected void onPostExecute(String result) {
        // 主线程:任务完成后(更新 UI)
        progressBar.setVisibility(View.GONE);
        textView.setText(result);
    }
}

// 调用方式:
new MyTask().execute();


🔸 14.5 使用 Java 原生线程池(ThreadPoolExecutor)

ExecutorService executor = Executors.newFixedThreadPool(4);

executor.execute(() -> {
    // 执行耗时任务
    String data = loadData();

    // 回主线程更新 UI
    runOnUiThread(() -> textView.setText(data));
});

✦ 优点:

  • 避免频繁创建销毁线程

  • 支持并发执行多个任务

  • 适合批量任务,如多个图片下载


🔸 14.6 Kotlin 开发推荐:协程 Coroutines(了解即可)

虽然本书采用 Java 编写,但需要了解,Kotlin 开发中主流推荐使用协程 (CoroutineScope, launch, suspend 等),比 AsyncTask 和 Handler 更轻便灵活。


🔸 14.7 主线程中更新 UI 的常见方式总结

场景方法
Thread → 主线程Handler.post()runOnUiThread()
AsyncTask → 主线程onPostExecute()
ExecutorService → 主线程runOnUiThread()

✅ 总结

  • Android 中的 UI 必须在主线程更新,耗时任务需放入子线程执行

  • Handler 是 Android 最基础的线程通信工具

  • AsyncTask 封装了常见的异步模式(但已被弃用)

  • Executor 提供了线程池管理机制,适合并发任务

  • Kotlin 推荐使用协程,Java 可用线程池 + Handler 配合实现异步任务


📢 下一章预告:

第十五章:Android 动画机制详解(属性动画、帧动画、过渡动画)


小Demo(原来的习题板块)

项目结构

MainActivity.java
activity_main.xml
AndroidManifest.xml

1. activity_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"
    android:padding="16dp">

    <TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="点击按钮开始任务"
        android:textSize="18sp"
        android:gravity="center" />

    <ProgressBar
        android:id="@+id/progressBar"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:visibility="gone" />

    <Button
        android:id="@+id/btnHandler"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Handler + Thread 示例" />

    <Button
        android:id="@+id/btnAsyncTask"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="AsyncTask 示例" />

    <Button
        android:id="@+id/btnThreadPool"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="线程池示例" />
</LinearLayout>

2. MainActivity.java

package com.example.demo;

import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.widget.Button;
import android.widget.ProgressBar;
import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class MainActivity extends AppCompatActivity {

    private TextView textView;
    private ProgressBar progressBar;

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

        textView = findViewById(R.id.textView);
        progressBar = findViewById(R.id.progressBar);

        Button btnHandler = findViewById(R.id.btnHandler);
        Button btnAsyncTask = findViewById(R.id.btnAsyncTask);
        Button btnThreadPool = findViewById(R.id.btnThreadPool);

        // Handler + Thread 示例
        btnHandler.setOnClickListener(v -> startHandlerThreadExample());

        // AsyncTask 示例
        btnAsyncTask.setOnClickListener(v -> startAsyncTaskExample());

        // 线程池示例
        btnThreadPool.setOnClickListener(v -> startThreadPoolExample());
    }

    // Handler + Thread 示例
    private void startHandlerThreadExample() {
        progressBar.setVisibility(ProgressBar.VISIBLE);

        Handler handler = new Handler(Looper.getMainLooper()) {
            @Override
            public void handleMessage(Message msg) {
                if (msg.what == 1) {
                    String result = (String) msg.obj;
                    textView.setText(result);
                    progressBar.setVisibility(ProgressBar.GONE);
                }
            }
        };

        new Thread(() -> {
            try {
                // 模拟耗时操作
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            // 发送消息到主线程
            Message message = handler.obtainMessage();
            message.what = 1;
            message.obj = "Handler + Thread 示例完成";
            handler.sendMessage(message);
        }).start();
    }

    // AsyncTask 示例
    private void startAsyncTaskExample() {
        new MyTask().execute();
    }

    private class MyTask extends AsyncTask<Void, Void, String> {

        @Override
        protected void onPreExecute() {
            super.onPreExecute();
            progressBar.setVisibility(ProgressBar.VISIBLE);
        }

        @Override
        protected String doInBackground(Void... voids) {
            try {
                // 模拟耗时操作
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "AsyncTask 示例完成";
        }

        @Override
        protected void onPostExecute(String result) {
            super.onPostExecute(result);
            textView.setText(result);
            progressBar.setVisibility(ProgressBar.GONE);
        }
    }

    // 线程池示例
    private void startThreadPoolExample() {
        progressBar.setVisibility(ProgressBar.VISIBLE);

        ExecutorService executor = Executors.newFixedThreadPool(4);
        executor.execute(() -> {
            try {
                // 模拟耗时操作
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            // 回到主线程更新 UI
            runOnUiThread(() -> {
                textView.setText("线程池示例完成");
                progressBar.setVisibility(ProgressBar.GONE);
            });
        });
    }
}

3. AndroidManifest.xml

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.demo">

    <application
        android:allowBackup="true"
        android:label="多线程与异步任务示例"
        android:theme="@style/Theme.AppCompat.Light.DarkActionBar">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>
</manifest>

代码说明

1. Handler + Thread 示例
  • 使用 Handler 和 Thread 进行线程通信。
  • 子线程完成耗时任务后,通过 Handler 将结果发送回主线程更新 UI。
2. AsyncTask 示例
  • 使用 AsyncTask 执行耗时操作:
    • onPreExecute():在主线程中运行,用于初始化 UI。
    • doInBackground():在子线程中运行,执行耗时任务。
    • onPostExecute():在主线程中运行,用于更新 UI。
3. 线程池示例
  • 使用 ExecutorService 创建固定大小的线程池。
  • 子线程完成任务后,通过 runOnUiThread() 更新主线程 UI。

运行效果

  1. Handler + Thread 示例

    • 点击按钮后,进度条显示,2 秒后更新文本为“Handler + Thread 示例完成”。
  2. AsyncTask 示例

    • 点击按钮后,进度条显示,2 秒后更新文本为“AsyncTask 示例完成”。
  3. 线程池示例

    • 点击按钮后,进度条显示,2 秒后更新文本为“线程池示例完成”。

总结

  1. Handler 是线程间通信的基础工具,适合简单的线程交互。
  2. AsyncTask 已被弃用,但在旧项目中仍常见,适合轻量级异步任务。
  3. 线程池 提供更高效的线程管理,适合复杂的多线程场景。
  4. 在现代开发中,推荐使用 Kotlin 的协程(Coroutines)或 RxJava 来处理异步任务。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2386312.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【JVM 01-引言入门篇】

JVM 引言篇01 笔记记录 1. 什么是JVM&#xff1f;2. 学习JVM有什么用&#xff1f;3. 常见的JVM4. 学习路线 学习资料来源-b站黑马 1. 什么是JVM&#xff1f; 定义&#xff1a;Java虚拟机&#xff08;Java Virtual Machine 简称JVM&#xff09;是运行所有Java程序的抽象计算机&a…

Pandas数据规整

&#xff08;1&#xff09;层次化索引 1.创建带层次化索引的df 第一种&#xff0c;直接创建 import pandas as pd import numpy as npdata pd.Series(np.random.randn(9),index [[a, a, a, b, b, c, c, d, d],[1, 2, 3, 1, 3, 1, 2, 2, 3]]) print(data) # a 1 -0.6416…

ThreadLocal线程本地变量在dubbo服务使用时候遇到的一个坑

我昨天遇到一个问题&#xff0c;就是我springboot项目里面有一个提供代办服务审核的dubbo接口&#xff0c;这个接口给房源项目调用&#xff0c;但是碰到一个问题就是&#xff0c;房源项目每天凌晨5点会查询满足条件过期的数据&#xff0c;然后调用我这边的代办审核dubbo接口&am…

从 0 到 1:Spring Boot 与 Spring AI 深度实战(基于深度求索 DeepSeek)

在人工智能技术与企业级开发深度融合的今天&#xff0c;传统软件开发模式与 AI 工程化开发的差异日益显著。作为 Spring 生态体系中专注于 AI 工程化的核心框架&#xff0c;Spring AI通过标准化集成方案大幅降低 AI 应用开发门槛。本文将以国产大模型代表 ** 深度求索&#xff…

upload-labs通关笔记-第20关 文件上传之杠点绕过

系列目录 upload-labs通关笔记-第1关 文件上传之前端绕过&#xff08;3种渗透方法&#xff09; upload-labs通关笔记-第2关 文件上传之MIME绕过-CSDN博客 upload-labs通关笔记-第3关 文件上传之黑名单绕过-CSDN博客 upload-labs通关笔记-第4关 文件上传之.htacess绕过-CSDN…

Vscode +Keil Assistant编译报错处理

Vscode Keil Assistant编译报错处理 1.报错图片内容 所在位置 行:1 字符: 25 chcp.com 65001 -Command & c:\Users\92170.vscode\extensions\cl.keil-a … ~ 不允许使用与号(&)。& 运算符是为将来使用而保留的&#xff1b;请用双引号将与号引起来(“&”)&…

VSCode C/C++ 开发环境完整配置及一些扩展用途(自用)update:2025/3/31

这里主要记录了一些与配置相关的内容。由于网上教程众多&#xff0c;部分解决方法并不能完全契合我遇到的问题&#xff0c;因此我选择以自己偏好的方式&#xff0c;对 VSCode 进行完整的配置&#xff0c;并记录在使用过程中遇到的问题及解决方案。后续内容也会持续更新和完善。…

Docker系列(二):开机自启动与基础配置、镜像加速器优化与疑难排查指南

引言 docker 的快速部署与高效运行依赖于两大核心环节&#xff1a;基础环境搭建与镜像生态优化。本期博文从零开始&#xff0c;系统讲解 docker 服务的管理配置与镜像加速实践。第一部分聚焦 docker 服务的安装、权限控制与自启动设置&#xff0c;确保环境稳定可用&#xff1b…

a16z:AI带来了全新的9种开发软件的模式

非常有启发的9条新兴模式&#xff0c;推荐给已经上手 vibeCoding 的读者们。 开发者正在将 AI 从简单的工具转变为构建软件的新基础。许多核心概念&#xff0c;如版本控制、模板、文档&#xff0c;甚至用户的定义&#xff0c;都在被重新思考。代理&#xff08;Agent&#xff09…

在 Excel 使用macro————仙盟创梦IDE

Dim filePath As StringDim fileContent As StringDim lines() As StringDim dataArray() As StringDim lineCount As LongDim maxCols As LongDim i As Long, j As Long 文件路径filePath "" 检查文件是否存在If Dir(filePath) "" ThenMsgBox "文件…

鸿蒙devEco studio如何创建模拟器

官网原文链接&#xff1a;https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/ide-emulator-create 操作步骤 点击菜单栏的Tools > Device Manager&#xff0c;点击右下角的Edit设置模拟器实例的存储路径Local Emulator Location&#xff0c;Mac默认存储在~/…

鸿蒙路由参数传递

页面test.ets 代码如下&#xff1a; import router from ohos.router Entry Component struct Test {State message: string Hello WorldState username: string huState password: string 1build() {Row() {Column() {Text(this.message).fontSize(50).fontWeight(FontWe…

springboot 控制层调用业务逻辑层,注入报错,无法自动装配 解决办法

报错&#xff1a; 解决&#xff1a;愿意是业务逻辑层&#xff0c;即service层的具体实现类没有加注解Service导致的&#xff0c;加上解决了&#xff01;&#xff01;

MySQL:11_事务

事务 一.CURD不加控制&#xff0c;会有什么问题&#xff1f; 二.什么是事务&#xff1f; 事务就是一组DML语句组成&#xff0c;这些语句在逻辑上存在相关性&#xff0c;这一组DML语句要么全部成功&#xff0c;要么全部失败&#xff0c;是一个整体。MySQL提供一种机制&#xf…

Linux中的文件系统和软硬连接

磁盘的访问方式 CHS&#xff08;柱面&#xff0c;磁头&#xff0c;扇区&#xff09; 法&#xff08;磁盘硬件查找&#xff09;&#xff1a; 确定柱面&#xff08;C&#xff09; 磁头臂移动到对应的柱面位置。例如&#xff0c;柱面号为 5&#xff0c;则磁头移动到第 5 个磁道组…

Spring AI:Java开发者的AI开发新利器

目录 一、引言 二、Spring AI 是什么 三、核心功能与特性 3.1 统一的 API 抽象 3.2 丰富的模型支持 3.3 低代码集成 3.4 结构化数据输出 3.5 流式数据响应 四、应用场景 4.1 智能客服系统 4.2 图像识别应用 4.3 数据分析与预测 五、快速上手 5.1 环境搭建 5.2 创…

Spring Cloud Sleuth与Zipkin深度整合指南:微服务链路追踪实战

上篇文章简单介绍了SpringCloud系列熔断器&#xff1a;Sentinel的搭建及基本用法&#xff0c;今天继续讲解下SpringCloud的微服务链路追踪&#xff1a;Zipkin的使用&#xff01;在分享之前继续回顾下本次SpringCloud的专题要讲的内容&#xff1a; 前置知识说明 在开始本教程前…

spring-ai 集成 mcp 之投机取巧

主旨 这篇文章主旨就一点&#xff0c;罗列spring-ai对mcp集成导致出现的一系列问题 分析 由于mcp未问世之前&#xff0c;就早就已经有了工具调用&#xff0c;源码如下&#xff1a; public interface ToolCallback {/*** Definition used by the AI model to determine when a…

大语言模型的完整训练周期从0到1的体系化拆解

以下部分内容参考了AI。 要真正理解大语言模型&#xff08;LLM&#xff09;的创生过程&#xff0c;我们需要将其拆解为一个完整的生命周期&#xff0c;每个阶段的关键技术相互关联&#xff0c;共同支撑最终模型的涌现能力。以下是体系化的训练流程框架&#xff1a; 阶段一&am…

历年北京邮电大学保研上机真题

2025北京邮电大学保研上机真题 2024北京邮电大学保研上机真题 2023北京邮电大学保研上机真题 在线测评链接&#xff1a;https://pgcode.cn/problem?classification1 32位二进制串加法 题目描述 输入一个32位的二进制01串&#xff0c;输出这个数1和3后的32位二进制串。 输入…