Android 多线程编程实验_android UI线程

Android 多线程编程实验_android UI线程线程的基本用法Android的多线程编程与Java多线程编程基本是使用相同的语法,比如定义一个线程只需要新建一个类继承自Thread,重写父类的run()方法classMyThread:Thread(){overridefunrun(){//编写具体的逻辑}}启动这个线程也很简单,创建MyThread的实例,调用start()方法,这样run()方法中的代码就会在子线程中运行了MyThread().start().

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全家桶1年46,售后保障稳定

线程的基本用法

Android 的多线程编程与 Java 多线程编程基本是使用相同的语法,比如定义一个线程只需要新建一个类继承自 Thread,重写父类的 run() 方法

class MyThread : Thread() { 
   
    override fun run() { 
   
        // 编写具体的逻辑
    }
}

Jetbrains全家桶1年46,售后保障稳定

启动这个线程也很简单,创建 MyThread 的实例,调用 start() 方法,这样 run() 方法中的代码就会在子线程中运行了

MyThread().start()

当然,使用继承的方式耦合性有点高,可以选择实现 Runnable 接口的方式定义一个线程

class MyThread : Runnable { 
   
    override fun run() { 
   
        // 编写具体的逻辑
    }
}

如果使用这种写法,启动线程的方式也需要进行相应的改变

val myThread = MyThread()
Thread(myThread).start()

也可以使用 Lambda 的方式

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

以上几种方式相比都不陌生,Kotlin 还给我们提供了更简单的开启线程的方式,我们只需要在 Lambda 表达式中编写具体的逻辑即可,连 start() 方法都不用调用

thread { 
   
    // 编写具体的逻辑
}

异步消息处理机制

Android 的 UI 是线程不安全的,如果想更新应用程序里的 UI 元素,必须在主线程中进行,否则会出现异常。但有些时候,我们必须在子线程执行一些耗时任务,然后根据任务的执行结果更新 UI,这时可以使用 Android 提供的一套异步消息处理机制解决

class MainActivity : AppCompatActivity() { 
   

    // 定义一个整型变量 updateText,用于表示更新 UI 动作
    val updateText = 1

    val handler = object : Handler(Looper.getMainLooper()) { 
   
        override fun handleMessage(msg: Message) { 
   
            // 在这里进行 UI 操作
            when (msg.what) { 
   
                // 更新 UI
            }
        }
    }

    override fun onCreate(savedInstanceState: Bundle?) { 
   
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        button.setOnClickListener { 
   
            thread { 
   
                // 创建一个 Message 对象
                val msg = Message()
                // 指定 what 值为 updateText
                msg.what = updateText
                // 将这条 msg 发送给 handler
                handler.sendMessage(msg)
            }
        }
    }
}       

下面对 Android 的异步机制做简要介绍,主要由四个部分组成:

  1. Message

    Message 是在线程之间传递的消息,可以在内部携带少量的信息,用于不同线程之间传递数据。比如上述代码使用了 Message 的 what 字段,除此之外还可以使用 arg1 和 arg2 字段携带一些整型数据,使用 obj 字段携带一个 Object 对象

  2. Handler

    处理者,主要用于发送和处理消息。发送消息一般使用 sendMessage() 方法、post() 方法等,而发出的消息经过一系列地辗转处理后,最终会传递到 Handler 的 handlerMessage() 方法中

  3. MessageQueue

    消息队列,主要用于存放所有通过 Handler 发送的消息,这部分消息会一直存在于消息队列中,等待被处理,每个线程中只会有一个 MessageQueue 对象

  4. Looper

    Looper 是每个线程中 MessageQueue 的管家,调用 Looper 的 loop() 方法后,就会进入一个无限循环中,然后每当发现 MessageQueue 中存在一条消息时,就会将它取出,并传递到 Handler 的 handlerMessage() 方法中,每个线程只会有一个 Looper 对象

现在再来把异步消息处理的流程梳理一下:首先需要在主线程中创建一个 Handler 对象,并重写 handlerMessage() 方法。然后子线程创建一个 Message 对象,并通过 Handler 将这条消息发送出去。之后这条消息会被添加到 MessageQueue 的队列等待被处理。Looper 会一直尝试从 MessageQueue 中取出待处理消息,由 handleMessage() 方法处理

AsyncTask

AsyncTask 的实现原理也是基于异步消息处理机制,只是 Android 帮我们做了更好的封装

AsyncTask 是一个抽象类,使用时必须创建一个子类去继承它,在继承时我们可以为 AsyncTask 类指定三个泛型参数:

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

一个最简单的自定义 AsyncTask 可以写成如下形式:

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

这里我们把 AsyncTask 的第一个泛型参数指定为 Unit,表示在执行 AsyncTask 时不需要传入参数给后台任务。第二个泛型参数指定为 Int,表示使用整型数据作为进度显示单位。第三个泛型参数指定为 Boolean,表示使用布尔型数据反馈执行结果

AsyncTask 经常需要重写的方法有以下四个:

  1. onPreExecute()

    这个方法会在后台任务开始执行之前调用,用于进行一些界面上的初始化操作,比如显示一个进度条对话框

  2. doInBackgroound(Params…)

    这个方法中的所有代码都会在子线程中运行,应该在这里处理所有耗时任务,任务一旦完成,就可以通过 return 语句返回结果。如果需要更新 UI,比如反馈当前任务的执行进度,可以调用 publishProgress(Progress…) 方法来完成

  3. onProgressUpdate(Progress…)

    当调用了 publishProgress(Progress…) 方法后,该方法就会被调用,携带的参数就是后台任务中传递过来的,在这里可以对 UI 进行操作

  4. onPostExecute(Result)

    当后台任务执行完毕并通过 return 语句返回时,这个方法很快就会被调用,返回的数据会作为参数传递到此方法中,可以利用返回的数据进行一些 UI 操作

因此,一个完整的自定义 AsyncTask 就可以写成如下形式:

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

    override fun onPreExecute() { 
   
        // 显示进度对话框
        progressDialog.show()
    }

    override fun doInBackground(vararg params: Unit?) = try { 
   
        while (true) { 
   
            // 这是一个虚构的方法
            val downloadPercent = doDownload()
            publishProgress(downloadPercent)
            if (downloadPercent >= 100) { 
   
                break
            }
        }
        true
    } catch (e: Exception) { 
   
        false
    }

    override fun onProgressUpdate(vararg values: Int?) { 
   
        // 在这里更新下载进度
        progressDialog.setMessage("Download ${ 
     values[0]}%")
    }

    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()
        }
    }
}

想要启动这个任务,只需要以下代码即可

DownloadTask().execute()

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/234259.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • 【转AekdyCoin】求小于等于N的与N互质的数的和「建议收藏」

    【转AekdyCoin】求小于等于N的与N互质的数的和「建议收藏」话说我以前求这样的问题都是先求与N不互质的数,把N分解质因数,然后用容斥原理,今天看了大牛的博客,顿时觉得弱爆了。。。以下内容转大牛文章:ifgcd(n,i)=1thengcd(n,n-i)=1(1反证法:如果存在K!=1使gcd(n,n-i)=k,那么(n-i)%k==0而n%k=0那么必须保证i%k=0k是n的因子,如果i%k=0那么gcd(n,i)=k

  • JavaScript正则表达式简单教程「建议收藏」

    JavaScript正则表达式简单教程「建议收藏」1.常见的正则表达式符号?.匹配除换行符以外的任意字符\w匹配字母或数字或下划线或汉字\s匹配任意的空白符\d匹配数字\b匹配单词的开始和结束^匹配字符串的开始$匹配字符串的结束*重复零次或更多次+重复一次或更多次?重复零次或一次{n}重复n次{n,}重复n多次{n,m}重复n到m词\W匹配任意不是字母,数字,下划线,汉字的字符\S匹配任意不是空白符的字符\D匹配任意非数字的字符\B匹配不是单词开头或结尾的位置【^x】匹配除了x

  • jsp 和 servlet 有什么区别?

    jsp 和 servlet 有什么区别?jsp和servlet有什么区别?Servlet一种服务器端的Java应用程序 由Web容器加载和管理 用于生成动态Web内容 负责处理客户端请求Jsp是Servlet的扩展,本质上还是Servlet 每个Jsp页面就是一个Servlet实例 Jsp页面会被Web容器编译成Servlet,Servlet再负责响…

  • hihoCoder – 1082 – 然而沼跃鱼早就看穿了一切 (字符串处理!!)

    hihoCoder – 1082 – 然而沼跃鱼早就看穿了一切 (字符串处理!!)

  • 用户行为路径分析报告_spark用户行为分析

    用户行为路径分析报告_spark用户行为分析请看题:已知用户行为表tracking_log,大概字段有:(user_id用户编号,op_id操作编号,op_time操作时间)要求:统计每天符合以下条件的用户数:A操作之后是B操作,AB操作必须相邻。生成数据,可以在sqlfiddle中测试:createtabletracking_log(idintprimarykeyAUTO_INCREMENT,user_idintnotnull,op_idchar(4)notnull,op

  • c语言switch例题注释,switch语句例子大全 C语言switch语句例题

    c语言switch例题注释,switch语句例子大全 C语言switch语句例题CSS布局HTML小编今天和大家分享一个switch语句的例子matlab中switch语句的用法例子matlab中switch语句看了好几本教材上的例子都未看懂核心,不知谁能提供if-else-end语句所对应的是多重判断选择,而有时也会遇到多分支判断选择的问题。MATLAB语言为解决多分支判断选择提供了switch-case语句。switch-case语句的一般表达形式为:switch〈…

    2022年10月21日

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号