【Android 线程】在子线程中更新UI

线程 2 种基本用法

继承

//定义
class MyThread : Thread() {
   
	override fun run() {
   
	}
}
//启动
MyThread.start()

接口

//定义
class MyThread : Runnable {
   
	override fun run() {
   
	}
}
//启动
var myThread = MyThread()
Thread(myThread).start()

在子线程中更新UI

class MainActivity : AppCompatActivity() {
   
    val updateText = 1
    //1、需要在主线程当中创建一个`Handler` 对象,并重写 `handleMessage()` 方法。
	val handler = object : Handler(Looper.getMaininLooper()) {
    
		override fun handleMessage(msg: Message) {
   
			// 在这里可以进行UI操作 
			when (msg.what) {
   
				updateText -> textView.text = "Nice to meet you" }
			} 
		}
	override fun onCreate(savedInstanceState: Bundle?) {
    		
		super.onCreate(savedInstanceState) 
		setContentView(R.layout.activity_main) 
		changeTextBtn.setOnClickListener {
   
			thread {
   
				//2、当子线程中需要进行UI操作时,就创建一个 `Message` 对象,
				val msg = Message()
				msg.what = updateText
				//并通过 `Handler` 将这条消息(Message对象)发送出去。
				handler.sendMessage(msg)
			} 
		}
	}
}

之后,这条消息会被添加到 MessageQueue 的队列中等待被处理。

而,Looper 则会一直尝试从 MessageQueue 中取出待处理消息,最后分发回 HandlerhandleMessage() 方法中。

由于 Handler 的构造函数中我们传入了 Looper.getMainLooper(),所以此时 handleMessage() 方法中的代码也会在主线程中运 行,于是我们在这里就可以安心地进行UI操作了。

AsyncTask(抽象类)

/**
子类继承时,需要指定3个泛型参数:
Params:在执行AsyncTask 时需要传入的参数,可用于在后台任务中使用。 
Progress:在后台任务执行时,如果需要在界面上显示当前的进度,则使用这里指定的泛型作为进度单位。 
Result:当任务执行完毕后,如果需要对结果进行返回,则使用这里指定的泛型作为返回值类型。
*/

//Kotlin Unit = Java void
class DownloadTask : AsyncTask<Unit, Int, Boolean>() {
   
	//onPreExecute() 
	//这个方法会在后台任务开始执行之前调用。用于进行一些界面上的初始化操作,比如显示一个进度条对话框等。
	override fun onPreExecute() {
   
		progressDialog.show() // 显示进度对话框 
	}

	//doInBackground(Params...)
	//这个方法中的所有代码都会在`子线程`中运行,我们应该在这里去处理所有的耗时任务。
	//任务一旦完成,就可以通过return语句将任务的执行结果返回,如果AsyncTask 的第三个泛型参数指定的是Unit,就可以不返回任务执行结果。
	override fun doInBackground(vararg params: Unit?) = try {
    
		while (true) {
   
			val downloadPercent = doDownload() // doDownload()是一个虚构的方法
			//注意,在这个方法中是不可以进行UI 操作的,如果需要更新UI元素,比如说反馈当前任务的执行进度,可以调用 publishProgress (Progress...) 方法来完成。
			publishProgress(downloadPercent)
			if (downloadPercent >= 100) {
   
				break 
			}
		}
	    true
	} catch (e: Exception) {
   
		false
	}
	
	//onProgressUpdate(Progress...)
	//在这个方法中可以对UI进行操作,利用参数中的数值就可以对界面元素进行相应的更新。
	//当在后台任务中调用了publishProgress(Progress...)方法,onProgressUpdate (Progress...)方法就会很快被调用,该方法中携带的参数就是在后台任务中传递过来的。
	override fun onProgressUpdate(vararg values: Int?) {
    // 在这里更新下载进度
		progressDialog.setMessage("Downloaded ${
     values[0]}%") 
	}

	//onPostExecute(Result)
	//当后台任务执行完毕并通过return语句进行返回时,这个方法就很快会被调用。返回的数 据会作为参数传递到此方法中,可以利用返回的数据进行一些UI操作,比如说提醒任务执行的结果,以及关闭进度条对话框等。
	override fun onPostExecute(result: Boolean) {
    
	progressDialog.dismiss()// 关闭进度对话框 
		// 在这里提示下载结果
		if (result) {
   
			Toast.makeText(context, "Download succeeded", Toast.LENGTH_SHORT).show() 
		} else {
   
			Toast.makeText(context, " Download failed", Toast.LENGTH_SHORT).show() 
		}
	} 
}

简单来说,使用 AsyncTask 的诀窍就是,
doInBackground()方法中执行具体的耗时任务,
onProgressUpdate()方法中进行UI操作,
onPostExecute()方法中执行一些任务的收尾工作。

执行关系,
doInBackground()调用publishProgress(Progress...),触发onProgressUpdate (Progress...)
doInBackground()执行完毕返回Result,执行onPostExecute(Result)

启动任务:

DownloadTask().execute()
//当然,也可以给execute()方法传入任意数量的参数Params...,这些参数将会传递到doInBackground(Params...)方法当中。

只需要调用一下publishProgress()方法,就可以轻松地从子线程切换到UI线程了。

相关推荐

  1. Android 线线更新UI

    2023-12-05 20:28:03       57 阅读
  2. qt 线更新ui举例

    2023-12-05 20:28:03       25 阅读
  3. Android 线为什么不能更新UI

    2023-12-05 20:28:03       37 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2023-12-05 20:28:03       94 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2023-12-05 20:28:03       100 阅读
  3. 在Django里面运行非项目文件

    2023-12-05 20:28:03       82 阅读
  4. Python语言-面向对象

    2023-12-05 20:28:03       91 阅读

热门阅读

  1. spark学习一-------------------Spark算子最详细介绍

    2023-12-05 20:28:03       50 阅读
  2. 再探Docker:从Docker基础到跨服务器部署

    2023-12-05 20:28:03       34 阅读
  3. SSL证书认证对搜索引擎有影响吗?

    2023-12-05 20:28:03       64 阅读
  4. 如何判别使用的junit是4还是5

    2023-12-05 20:28:03       52 阅读
  5. 异常与junit

    2023-12-05 20:28:03       57 阅读
  6. CF 1901B Chip and Ribbon 学习笔记

    2023-12-05 20:28:03       60 阅读
  7. springcloud==ribbon

    2023-12-05 20:28:03       60 阅读
  8. 【光的波长和频率计算】

    2023-12-05 20:28:03       60 阅读
  9. prompt提示

    2023-12-05 20:28:03       47 阅读
  10. Linux C语言 32-网络编程之UDP例程

    2023-12-05 20:28:03       63 阅读
  11. STM32 基础知识

    2023-12-05 20:28:03       50 阅读