Android Kotlin 多线程编程 server

news2024/11/15 21:47:04

参考: 《第一行代码 第三版》

10.1 service 是什么
Service是实现程序后台运行的解决方案,适合执行非交互,后台预先的任务,即使用户打开其他应用,Service也能够正常运行

Service需要内部手动创建子线程

10.2 多线程编程

  1. 用法:
    (1) 继承的方式(耦合较高,不推荐)
class MyThread : Thread() {
    override fun run () {
        // 编写具体逻辑
    }
}
// 启动
MyThread().start()

(2) Runnable接口定义一个线程

class MyThread : Runnable {
    override fun run () {
      // 子线程具体逻辑
    }
}
// 启动
val myThread = MyThread()
Thread(myThread).start()

简化写法:如果你不想专门定义一个类去实现Runnable接口, 可以使用Lambda方式

Thread {
 // 编写具体逻辑
}.start()

更加简化的写法:

thread {
    // 编写具体的逻辑
}
  1. 在子线程中更新UI
    Android 的UI 也是线程不安全的, 更新应用程序的UI元素, 必须在主线程中进行, 否则会出现异常
    如果在子线程中直接更新UI,会出现崩溃,提示如下错误
    android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.在这里插入图片描述

那子线程如何更新UI呢?
通过异步消息传递给主线程, 在主线程更新UI
修改MainActivity.kt

class MainActivity : AppCompatActivity() {
    val sign = 1
    val handler = object: Handler(Looper.getMainLooper()) {
        override fun handleMessage(msg: Message) {
            when (msg.what) {
                sign -> textView.text = "Nice to meet you 2"
            }
        }
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        button.setOnClickListener{
            thread {
                val msg = Message()
                msg.what = sign
                handler.sendMessage(msg)
            }
        }
    }
}

定义一个Handler对象,重写handleMessage方法
如果Message(android.os.Message)的what字段等于sign,就将UI更新

  1. 异步消息处理机制
    (1) Message 线程中传递少量消息,使用arg1和arg2携带整型数据, obj字段携带Obejct对象
    (2) Handler,用于发送和接收消息
    发送: 使用sendMessage() post() 方法
    接受: 最终会传递到handleMessage方法中
    (3) MessageQueue, 消息队列,存放Handler发送的消息,等待被处理,每个线程只会有一个MessageQueue
    (4) Looper, 是每个线程中MessageQueue的管家, 调用Looper的 loop() 方法后,会进入无限循环中,每当发现MessageQueue中存在一条消息,就取出,并传递到Handler的handleMessage方法中,每个线程用一个Looper对象

异步消息处理流程:
1 主线程创建handler对象, 重写handleMessage方法,
2 当子线程中需要进行UI操作,就创建一个Message对象,通过Handler 的sandMessage方法将消息发送出去,消息被添加到MessageQueue中等待
3 Looper一直尝试从MessageQueue中取消息,最后分发给Handler的handlerMessage方法中,由于Handler函数中传入了Looper.getMainLooper(), 此时handleMessage() 方法中的代码会在主线程中运行

  1. 使用AsyncTask
    为了方便子线程对UI操作, Android提供了一些好用的工具如AsyncTask,原来也是基于异步消息处理

(1)基本用法:
AsyncTask是一个抽象类,如果想使用它,需要一个子类继承,可以在继承时指定3个泛型参数:
params: 可在后台任务中使用
progress :在后台任务执行时, 如果需要在界面上显示的进度,使用泛型作为进度单位
Result 任务执行完后, 对结果进行返回, 返回泛型类型

最简单的形式:

class DownloadTask :AsyncTask<Unit, Int, Boolean> () {

}

当前是一个空任务,无任何实际操作,需要重写4个方法:
1 onPreExecute() 在任务执行前调用,用于初始化操作
2 doInBackground(Params…) 在子线程中执行, 执行具体耗时任务
3 onProgressUpdate(Progress…) 后台任务调用,进行UI操作
4 onPostExecute(Result) 后台任务执行完毕并通过return返回时, 收尾工作

10.3 Service 基本用法
1.定义一个Service
新建一个ServiceTest项目
右击 com.example.servicetest -> New -> Service -> Service
类名改成MyService, Exported表示将Service暴露给外部访问
Enable表示启用这个Service
生成如下代码:

class MyService : Service() { 
 override fun onBind(intent: Intent): IBinder { 
 TODO("Return the communication channel to the service.")
 } 
}

MyService 继承自Service类, 有一个onBind方法,是Service唯一抽象方法,需要在子类实现

重写一些方法:
onCreate() service创建调用

onStartCommand() 每次service启动调用

onDestory() 销毁调用

ps: Service需要在AndroidManifest.xml文件中注册(在创建service中会自动注册)

  1. 启动和停止Service
    要借助Intent实现,在ServiceTest中启动停止MyService
    添加两个按钮:
startServiceBtn.setOnClickListener { 
 val intent = Intent(this, MyService::class.java) 
 startService(intent) // 启动Service 
 } 
 stopServiceBtn.setOnClickListener { 
 val intent = Intent(this, MyService::class.java) 
 stopService(intent) // 停止Service 
 }

startServicestopService 都定义在Context类中,可以直接调用

另外可以自我停止:
在service内部调用stopSelf()方法

启动后可以在: 应用 -》显示系统应用 中找到

Android8.0后,应用在前台,service才能稳定运行,否则随时可能被系统回收

  1. Activity 与 Service通信: onBind 方法
    查看下载进度:,创建一个专门的Binder对象管理下载功能:
private val mBinder = DownloadBinder()
class DownloadBinder : Binder() {
  fun startDownload() {
    Log.d("MyService", "startDownload executed")
  }
  fun getProgress(): Int{
    Log.d("MyService", "getProgress executed")
    return 0
  }
}
override fun onBind(intent: Intent): IBinder {
  return mBinder
}

当一个Activity 和Service 绑定了之后,就可以调用该Service 里的Binder提供的方法了。

在activity中,修改:

lateinit var downloadBinder: MyService.DownloadBinder
private val connection = object : ServiceConnection {
	override fun onServiceConnected(name: ComponentName, service: IBinder) {
		 downloadBinder = service as MyService.DownloadBinder
		 downloadBinder.startDownload() 
		 downloadBinder.getProgress() 
	} 
	override fun onServiceDisconnected(name: ComponentName) {
	} 
}
...
// 绑定service
bindServiceBtn.setOnClickListener { 
	val intent = Intent(this, MyService::class.java) 
	bindService(intent, connection, Context.BIND_AUTO_CREATE) // 绑定Service 
}
// 解绑service
unbindServiceBtn.setOnClickListener { 
    unbindService(connection) // 解绑Service 
}

bindService()方法接收3个参数
第一个是Intent对象
第二个是ServiceConnection的实例
第三个是一个标志位 BIND_AUTO_CREATE 表示在Activity 和Service 进行绑定后
自动创建Service
这会使得MyService 中的onCreate()方法得到执行

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

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

相关文章

Makefile学习⑨:Makefile中的等号和shell命令的使用

Makefile学习⑨&#xff1a;Makefile中的等号和shell命令的使用 Makefile中的等号 “” 普通赋值符号&#xff0c;命令格式如下 变量值注意&#xff1a;变量的最终值为该文件中的最后进行赋值操作所赋的值。 &#xff08;不管在当前文件的何处进行赋值&#xff0c;在使用该…

【MySQL】MySQL经常使用时间日期相关函数

MySQL经常使用时间、日期相关函数 MySQL经常使用的时间、日期相关函数 1. 日期函数 显示当前日期函数&#xff1a;CURDATE(), CURRENT_DATE(), CURRENT_DATE SQL&#xff1a;select CURDATE(), CURRENT_DATE(), CURRENT_DATE from dual; 2. 时间函数 显示当前日期函数&…

Mysql专栏(五) Mysql高可用

Mysql专栏收尾之作&#xff0c;作为一名后端开发人员&#xff0c;对于Mysql的知识了解到这里已经足以应对99的场景了&#xff0c;毕竟没有必要非要跟DBA抢活儿干。 而且现在的趋势都是往云上走&#xff0c;云数据库已经帮我们处理了高可用和数据一致性的事情了&#xff0c;所以…

初阶指针的介绍

文章目录 指针是什么 指针和指针类型 野指针 指针运算 指针和数组 二级指针 指针数组 一、 指针是什么 指针理解的2个要点&#xff1a; 1. 指针是内存中一个最小单元的编号&#xff0c;也就是地址 2. 平时口语中说的指针&#xff0c;通常指的是指针变量&#xff0c;是用…

达梦8数据库优化

1.什么是执行计划&#xff1f; 一条SQL语句在数据库中执行过程或访问路径的描述。 2.如何查看达梦数据库执行计划&#xff1f; 通过explain命令&#xff1a; EXPLAIN 执行的SQL语句&#xff0c;如 SQL> EXPLAIN SELECT * FROM TEST1; 1 #NSET2: [1, 1113, 602] 2 …

Vue笔记01 模板语法,数据代理,事件处理,计算监听属性,绑定样式,列表渲染,数据监测

基本使用 引入vue 创建vue实例并关联容器 一个Vue实例只应对应一个容器 一个Vue实例可以有多个组件 模板语法 使用Vue实例中数据 root容器中代码被称为vue模板 语法分为插值语法和指令(v-xxx) 插值语法 绑定标签体内容 {{}}中的可以是js表达式&#xff08;特殊的js代码&…

CF790 div4 F(双指针) H(逆序对)

乐&#xff0c;被div4薄纱了没想到把所有出现次数>k的数放一个数组里然后双指针还有H&#xff0c;连逆序对都没看出来&#xff0c;嘻感觉以后还是写写div4算了&#xff0c;写什么div2啊&#xff0c;caibiProblem - F - Codeforces题意&#xff1a;给定一个数列&#xff0c;长…

2023万象更新!smardaten企业级无代码新版本也来啦!

2022可以说是在反复的做核酸、查绿码中度过的&#xff0c;不曾想年终一个月还是躲不过“小阳人”的命运。而这一个月&#xff0c;研发部的“阳过”们依旧加班加点给我们带来了最新版本——V8R4C70。在2022-2023跨年之际&#xff0c;smardaten这次又有哪些新的变化呢&#xff0c…

MVC三层架构的模式

大家好&#xff0c;今天给大家分享一下MVC 三层架构的模式 首先你要知道&#xff0c;所谓的MVC就是一种面向于javaee企业级开发的设计模式 这里要强调一点,MVC 不是一种技术&#xff0c;不是一种像spring 那样的框架&#xff0c;它是一种思想&#xff08;可以理解为一种解决问…

【GNSS算法工程入门】1. Git入门

写在前面笔者在GNSS算法开发岗位从业过一段时间&#xff0c;和大部分同学类似&#xff0c;在GNSS开发过程中&#xff0c;也是从工程化的小白逐渐成长起来。而在算法开发从业的过程中&#xff0c;发现有些基础的知识其实在学校学习过程中是相对缺失的。麻省理工有个课程叫计算机…

编译型语言的Docker镜像构建小技巧

最近公司需要将一个底层服务打包成docker镜像&#xff0c;作为征战docker一年的小白当然不能错过这次练手的好机会。简单介绍一下这个项目&#xff1a;该项目为一个纯restful风格的后端项目&#xff0c;后端由java开发、worker节点由python开发、管理员使用的命令行工具由rust开…

wpa_supplicant EAP状态机分析

EAP状态机分析RFC4137协议状态机设计原理模块划分SM状态定义SM状态转换SM使用到的变量及函数定义变量1.SM与LL交互使用到的变量列表2.SM与EM交互使用到的变量3.SM内部使用的变量函数wpas代码RFC4137协议 RFC4137&#xff1a;“State Machine for Extensible Authentication Pr…

强化学习笔记-01多臂老虎机问题

本文是博主对《Reinforcement Learning- An introduction》的阅读笔记&#xff0c;不涉及内容的翻译&#xff0c;主要为个人的理解和思考。 1. 多臂老虎机问题 多臂老虎机问题是指存在K个老虎机&#xff0c;每个老虎机的获胜金额是一个未知的概率分布且相互独立&#xff0c;假设…

一文解决Opencv四大经典算子——sobel算子、scharr算子、laplacian算子、canny算子

Opencv四大算子 Sobel算子Scharr算子laplacian算子canny算子总结边缘是像素值发生跃迁的位置,是图像的显著特征之一,在图像特征提取,对象检测,模式识别等方面都有重要的作用! Sobel算子 sobel算子对图像求一阶导数。一阶导数越大,说明像素在该方向的变化越大,边缘信号越…

python链接池和pymysql批量入库——从0实现大规模异步爬虫框架项目4

我将这个链接池和批量入库封装了一个工具类上传了pypi,可以直接import使用 使用也较为简单&#xff0c;导入PooledDBhelper的DBhelper&#xff0c;调用DBhelper.PooledDBhelper()方法传入数据库链接信息创建一个链接池即可 pip install PooledDBhelper1.0.0 -----------------…

虚析构函数的作用

类的析构函数是为了释放内存资源&#xff0c;析构函数不被调用的话就会造成内存泄漏。虚析构函数定义为虚析构函数是为了当用一个基类的指针删除一个派生类的对象时&#xff0c;派生类的析构函数会被调用。但并不是要把所有类的析构函数都写成虚函数。只有当一个类被用来作为基…

信息论复习—卷积码

目录 卷积码的基本概念&#xff1a; 卷积码与分组码的不同特点&#xff1a; 卷积码的构造与表示方法&#xff1a; 卷积码编码器的结构&#xff1a; 卷积码(3,1,3): 卷积码的卷积关系: 卷积码的生成矩阵: 卷积码的多项式: 系统码结构的卷积码: 卷积码的监督矩阵: 卷积…

Pipenv使用指南:轻量级虚拟环境管理工具详解

前言 终于能够挤出一点时间来总结最近学到的一些技术知识点了&#xff0c;博主这两周被居家隔离-集中隔离-居家隔离来回折腾&#xff0c;现在终于是得到解放能够空出的时间来写写博客了&#xff0c;但是项目又催的紧&#xff0c;写博文的时间还是有限&#xff0c;这周我会尽量…

正则语言的性质

正则语言的性质 一、正则语言的性质 1.正则语言的泵引理 设LLL是正则语言&#xff0c;则存在与LLL相关的常数nnn满足&#xff1a;对于任何LLL中的串www&#xff0c;如果∣w∣≥n|w|\geq n∣w∣≥n&#xff0c;则我们就能把www打断为三个串wxyzwxyzwxyz使得&#xff1a; y̸ϵ…

2011年专业408

文章目录0 结果1 题目2 思路2.1 思路1&#xff08;暴力解&#xff1a;排序&#xff09;2.2 思路2&#xff08;较优解&#xff1a;归并合并数组&#xff09;2.3 思路3&#xff08;较优解&#xff1a;数组指针后移&#xff09;2.4 思路4&#xff08;最优解&#xff1a;两个数组的…