Android Native APP开发笔记:多线程编程

news2024/11/23 21:29:20

文章目录

  • 目的
  • Java中的多线程
    • Thread
    • Runnable
    • Timer
  • Android中的多线程
    • Handler
    • AsyncTask
  • 总结

目的

Android中UI线程对于开发者和用户来说都是最主要接触到的线程。一般来说为了UI流畅、不卡顿,耗时操作是不推荐放在UI线程中的。但是耗时操作的需求又是存在的,这时候就需要用到多线程编程了,新建一条子线程去处理耗时操作。这篇文章将对相关内容进行简单介绍。

Java中的多线程

Android应用大部分都是用Java开发的,所以Java中的一些多线程编程方式在Android里也是可以使用的。

Thread

这是最基本的多线程操作:

// 定义继承自Thread的类
class MyThread extends Thread {
    // 重写run方法
    public void run() {
        // TODO
    }
}

MyThread t = new MyThread();
t.start(); // 创建新线程并启动,线程启动后会运行其中run方法
// new MyThread().start(); // 直接启动方式

在这里插入图片描述

Runnable

前面用的是继承的方式,只能继承一个类,所以更加常见的是使用下面这种方式:

// 定义类来实现Runnable接口
class MyRunnable implements Runnable {
    // 实现接口中的run方法
    public void run() {
        // TODO
    }
}

Thread t = new Thread(new MyRunnable());
t.start(); // 创建新线程,线程启动后会运行其中run方法
// new MyThread().start(); // 直接启动方式

很多时候也可以直接使用匿名内部类方式:

// 匿名内部类方式
Thread t = new Thread(new Runnable(){
    public void run() {
        // TODO
    }
});
t.start();

在这里插入图片描述

Timer

上面演示中在子线程中每隔1000ms执行一次操作,如果只是需要这种定时任务的话使用定时器更加方便些:

// import java.util.Timer;
// import java.util.TimerTask;

Timer timer = new Timer(); // Timer用来调度运行TimerTask对象
// 一个Timer可以调度多个TimerTask

TimerTask task = new TimerTask() {
    public void run() {
        // TODO
    }
};

// timer.schedule(task, 2000); // 延迟2000ms后运行一次task
timer.schedule(task, 2000, 1000); // 延迟2000ms后运行一次task,然后每隔1000ms重复运行task

在这里插入图片描述

Android中的多线程

Android中子线程是不能更新UI的,但很多时候又需要子线程处理一些耗时操作,然后根据操作结果来更新UI。针对这个业务需求Android中又提供了一些多线程机制。

Handler

Handler本身并不是多线程,它只是提供一种机制,使一个线程可以发送消息给另一个线程,通常默认情况下就是子线程发送消息给UI线程,这样UI线程就可以根据接收到的消息来做对应的处理,比如更新UI元素等。

Handler通常和前面Java的多线程方式结合使用。下面是个简单的演示:

package com.example.myapplication;

import androidx.appcompat.app.AppCompatActivity;

import android.annotation.SuppressLint;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.widget.TextView;

import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;

public class MainActivity extends AppCompatActivity {

    // 声明Handler对象并重写handleMessage方法
    @SuppressLint("HandlerLeak")
    private final Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) { // 收到消息时会触发handleMessage方法
                                                 // 这个Handler对象在哪个线程,handleMessage方法就在哪个线程执行
            TextView text = findViewById(R.id.text);
            text.setText(msg.obj.toString());
        }
    };

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

        new Timer().schedule(new TimerTask() {
            public void run() {
                Message message = new Message(); // 新建消息
                message.obj = new Date(System.currentTimeMillis()); // 填充消息内容
                handler.sendMessage(message); // 发送消息
            }
        }, 2000, 2000); // 每两秒触发一次定时器子线程
    }
}

在这里插入图片描述

上面演示中子线程可以创建 Message 对象,这个对象中可以保存 obj 等很多东西。通过 Handler 对象的一些方法,比如上面 sendMessage() 方法可以将 Message 发送给 Handler 所在线程。在 Handler 所在线程中会有 MessageQueue 用来接收这些 Message ,还有 Looper 进行消息处理,最终调用 Handler 对象的 handleMessage() 方法。在UI线程中 MessageQueueLooper 默认都会自动创建的。

现在的Android版本中上面这样的使用方式会被认为可能引起Activity泄漏,可以改用下面方式:

package com.example.myapplication;

import androidx.appcompat.app.AppCompatActivity;

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

import java.lang.ref.WeakReference;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;

public class MainActivity extends AppCompatActivity {

    private static class MyHandler extends Handler {

        //弱引用持有MainActivity , GC 回收时会被回收掉
        private final WeakReference<MainActivity> weakReference;

        public MyHandler(MainActivity activity) {
            this.weakReference = new WeakReference(activity);
        }

        @Override
        public void handleMessage(Message msg) {
            MainActivity activity = weakReference.get();
            if (activity != null) {
                TextView text = activity.findViewById(R.id.text);
                text.setText(msg.obj.toString());
            }
        }
    }

    private final MyHandler myHandler = new MyHandler(this);

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

        new Timer().schedule(new TimerTask() {
            public void run() {
                Message message = new Message();
                message.obj = new Date(System.currentTimeMillis());
                myHandler.sendMessage(message);
            }
        }, 2000, 2000);
    }
}

AsyncTask

AsyncTask是Android另一个用来异步更新UI的方式,现在(API level 30,Android 11)已被弃用,这里就不再进行介绍了。

总结

多线程的基础操作是比较简单的,相对复杂的线程间同步互斥等的问题先不在这里展开,使用时注意下不同线程对同一个资源操作的问题即可。

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

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

相关文章

Spring Cloud(八):Spring Cloud Alibaba Seata 2PC、AT、XA、TCC

事务简介 分布式事务&#xff1a;https://www.processon.com/view/link/61cd52fb0e3e7441570801ab 本地事务 JDBC 事务模式 Connection conn ... //获取数据库连接 conn.setAutoCommit(false); //开启事务 try{//...执行增删改查sqlconn.commit(); //提交事务 }catch (Exce…

【C++学习】日期类和内存管理

&#x1f431;作者&#xff1a;一只大喵咪1201 &#x1f431;专栏&#xff1a;《C学习》 &#x1f525;格言&#xff1a;你只管努力&#xff0c;剩下的交给时间&#xff01; 日期类的实现和内存管理&#x1f3ec;日期类的实现&#x1f3ec;C/C内存分布&#x1f3ec;C内存管理方…

【工具】Git-码农“吃饭的碗”要拿好

汝之观览&#xff0c;吾之幸也&#xff01;本文主要讲解的是Git的轻巧使用&#xff08;创建、下载、上传、更新、回退&#xff09;&#xff0c;我们平常都是通过idea自带的git工具&#xff0c;或者其他工具来拉取提交代码&#xff0c;这里主要用命令行的方式拉取代码&#xff0…

基于springboot+vue的心理预约咨询测试交流小程序

&#x1f496;&#x1f496;作者&#xff1a;IT跃迁谷毕设展 &#x1f499;&#x1f499;个人简介&#xff1a;曾长期从事计算机专业培训教学&#xff0c;本人也热爱上课教学&#xff0c;语言擅长Java、微信小程序、Python、Golang、安卓Android等。平常会做一些项目定制化开发…

【REST系列】详解REST架构风格 —— 带你阅读Web发展史上的一个重要技术文献

文章目录REST详解词组解释论文摘要REST架构约束一、Client–server&#xff1a;客户端-服务器二、Stateless&#xff1a;无状态三、Cacheability&#xff1a;缓存四、⭐Uniform Interface&#xff1a;统一接口 (RESTful API)五、Layered System&#xff1a;分层系统六、Code-On…

荧光生物标记物510758-19-7,5-羧基荧光素-炔烃,5-FAM alkyne

5-FAM-Alkyne 是一种高选择性和灵敏的荧光生物标记物&#xff0c;可用于标记碱性磷酸酶 (ALP)。炔烃可以通过铜催化的点击化学与多种叠氮化合物共轭。&#xff08;西安凯新生物科技有限公司​所有的试剂仅用于科研实验&#xff0c;不可用于人体试验&#xff09; 5-FAM Alkyne …

【Hadoop】P2 Hadoop简介

Hadoop是什么 Hadoop为分布式系统基础框架。主要解决海量数据的存储和海量数据的分析计算问题。 大数据解决的是海量数据的采集、存储和计算。 Hadoop三大发行版本 Apache 最原始最基础的版本&#xff0c;2006年诞生&#xff0c;开源&#xff1b; Cloudera 内部封装Apache&am…

HTML中华传统文化题材网页《中国民间年画》HTML+CSS+JavaScript

&#x1f389;精彩专栏推荐 &#x1f4ad;文末获取联系 ✍️ 作者简介: 一个热爱把逻辑思维转变为代码的技术博主 &#x1f482; 作者主页: 【主页——&#x1f680;获取更多优质源码】 &#x1f393; web前端期末大作业&#xff1a; 【&#x1f4da;毕设项目精品实战案例 (10…

Redis网络模型-IO多路复用

Redis网络模型-IO多路复用 系统IO交互 IO多路复用概念 文件描述符&#xff08;File Descriptor):简称FD&#xff0c;是一个从O开始递增的无符号整数&#xff0c;用来关联Linux中的一个文件。在Linux中&#xff0c;一切皆文件&#xff0c;例如常规文件、视频、硬件设备等&…

卷积神经网络的卷积层

文章目录卷积核正向传播反向传播参考文献附录卷积核 笔者在学会了如何运用卷积神经网路后&#xff0c;突然有一天萌发了很多问题&#xff0c;为什么要用卷积核&#xff1f;卷积核具体完成了什么工作&#xff1f;带着这些疑问&#xff0c;笔者开始查询资料&#xff0c;其中一段视…

MongoDB入门与实战-第一章-介绍

目录参考一、介绍二、概念三、预留默认库四、 MongoDB 集合五、 MongoDB 视图六、MongoDB 索引七、MongoDB ObjectIdMongoDB 性能问题定位方式参考 MongoDB 基础浅谈 一、介绍 MongoDB是为快速开发互联网Web应用而设计的数据库系统。 MongoDB的设计目标是极简、灵活、作为We…

[vue3] Tree/TreeSelect树形控件使用

✨✨个人主页:沫洺的主页 &#x1f4da;&#x1f4da;系列专栏: &#x1f4d6; JavaWeb专栏&#x1f4d6; JavaSE专栏 &#x1f4d6; Java基础专栏&#x1f4d6;vue3专栏 &#x1f4d6;MyBatis专栏&#x1f4d6;Spring专栏&#x1f4d6;SpringMVC专栏&#x1f4d6;SpringBoot专…

【定语从句练习题】That 、who、whom、省略

1. 改写训练 1.I’d like to speak to the person that wrote this letter. 主 2.The tomatoes that I bought yesterday. 宾&#xff0c;可以去掉 3.Joe’s got a motorbike that can do 200Km an hour. 主 4.Is that the computer that doesn’t work. 主 5.Those are trous…

[操作系统笔记]处理机调度

调度算法 名称英文作业调度进程调度说明特点先来先服务First-come first-served, FCFS适用适用按作业到达先后顺序&#xff08;即优先考虑等待时间最长的&#xff09;非抢占式短作业优先short job first, SJF适用适用作业越短&#xff08;即运行时间越短&#xff09;优先级越高…

SpringBoot异常:Process finished with exit code 0 | Tomcat服务没有启动 | 无法通过浏览器访问

错误信息 启动springBoot项目后&#xff0c;打印信息如下 意思是&#xff1a;我该执行的程序已执行完毕&#xff0c;并正常退出。 希望提示&#xff1a;打印Tomcat已在8080端口启动&#xff0c;可以通过浏览器访问&#xff0c;如果是这个问题&#xff0c;继续向下浏览&#xf…

标准库类型string和vector

一、命名空间 std::cinstd就是命名空间&#xff0c; 这个的含义是 &#xff1a;编译器应该从操作符左侧的名字所示的作用域std中去寻找cin。 另一种方式就是在开头显式进行说明&#xff1a; using std::cin;这样一来后续就不用再去在每条语句中显式说明了。 需要注意的是&…

微信小程序实战 wx.showNavigationBarLoading(),下拉动画配置无效

文章目录前情提要原因分析实战解析最后前情提要 下拉刷新一定是移动端常用操作&#xff0c;微信小程序官方集成了下拉刷新监听函数onPullDownRefresh(),以及显示下拉动画apiwx.showNavigationBarLoading(),但是我们在初次接触这个api发现&#xff0c;调用该函数动画不显示&…

头歌-信息安全技术-Spectre侧信道攻击过程验证

头歌-信息安全技术-Spectre侧信道攻击过程验证一、第1关&#xff1a;Cache vs Memory1、编程要求2、评测代码二、第2关&#xff1a;基于FlushReload的侧信道实现1、编程要求2、评测代码三、第3关&#xff1a;Spectre预测执行1、编程要求2、评测代码四、第4关&#xff1a;Spectr…

【Unity】关于升级到2021.3.12之后URP编译错误的问题

前几天&#xff0c;我一时兴起&#xff0c;把Unity从2021.3.11 LTS 升级到 2021.3.12 LTS&#xff0c;本来以为不会有啥区别&#xff0c;然后意想不到的是&#xff0c;居然出现了编译错误&#xff1a; 我一开始以为这个就是我的工程设置有问题&#xff0c;然后我就就新…

前端面试之Vue专题

目录 前言 MVVM模式 Vue的响应式原理 路由守卫 前言 网上有许多前端八股文&#xff0c;但是缺少便于理解的说明和案例&#xff0c;需要自行查阅资料。这篇文章我就按照面试的高频题来记录自己的理解和实操。 MVVM模式 一、三者含义 M是Model&#xff0c;数据模型&#xf…