设为首页 加入收藏

TOP

Kotlin入门(30)多线程交互(一)
2019-09-01 23:27:17 】 浏览:73
Tags:Kotlin 入门 线程 交互

Android开发时常会遇到一些耗时的业务场景,比如后台批量处理数据、访问后端服务器接口等等,此时为了保证界面交互的及时响应,必须通过线程单独运行这些耗时任务。简单的线程可使用Thread类来启动,无论Java还是Kotlin都一样,该方式首先要声明一个自定义线程类,对应的Java代码如下所示:

    private class PlayThread extends Thread {
        @Override
        public void run() {
            //此处省略具体的线程内部代码
        }
    }

 

自定义线程的Kotlin代码与Java大同小异,具体见下:

    private inner class PlayThread : Thread() {
        override fun run() {
            //此处省略具体的线程内部代码
        }
    }

 

线程类声明完毕,接着要启动线程处理任务,在Java中调用一行代码“new PlayThread().start();”即可,至于Kotlin则更简单了,只要“PlayThread().start()”就行。如此看来,Java的线程处理代码跟Kotlin差不了多少,没发觉Kotlin比Java有什么优势。倘使这样,真是小瞧了Kotlin,它身怀多项绝技,单单是匿名函数这招,之前在介绍任务Runnabe时便领教过了,线程Thread同样也能运用匿名函数化繁为简。注意到自定义线程类均需由Thread派生而来,然后必须且仅需重写run方法,所以像类继承、函数重载这些代码都是走过场,完全没必要每次都依样画葫芦,编译器真正关心的是run方法内部的具体代码。于是,借助于匿名函数,Kotlin的线程执行代码可以简写成下面这般:

    Thread {
        //此处省略具体的线程内部代码
    }.start()

 

以上代码段看似无理,实则有规,不但指明这是个线程,而且命令启动该线程,可谓是简洁明了。

线程代码在运行过程中,通常还要根据实际情况来更新界面,以达到动态刷新的效果。可是Android规定了只有主线程才能操作界面控件,分线程是无法直接调用控件对象的,只能通过Android提供的处理器Handler才能间接操纵控件。这意味着,要想让分线程持续刷新界面,仍需完成传统Android开发的下面几项工作:
1、声明一个自定义的处理器类Handler,并重写该类的handleMessage方法,根据不同的消息类型进行相应的控件操作;
2、线程内部针对各种运行状况,调用处理器对象的sendEmptyMessage或者sendMessage方法,发送事先约定好的消息类型;
举个具体的业务例子,现在有一个新闻版块,每隔两秒在界面上滚动播报新闻,其中便联合运用了线程和处理器,先由线程根据情况发出消息指令,再由处理器按照消息指令轮播新闻。详细的业务代码示例如下:

class MessageActivity : AppCompatActivity() {
    private var bPlay = false
    private val BEGIN = 0 //开始播放新闻
    private val SCROLL = 1 //持续滚动新闻
    private val END = 2 //结束播放新闻
    private val news = arrayOf("北斗三号卫星发射成功,定位精度媲美GPS", "美国赌城拉斯维加斯发生重大枪击事件", "日本在越南承建的跨海大桥未建完已下沉", "南水北调功在当代,近亿人喝上长江水", "德国外长要求中国尊重“一个欧洲”政策")

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_message)
        tv_message.gravity = Gravity.LEFT or Gravity.BOTTOM
        tv_message.setLines(8)
        tv_message.maxLines = 8
        tv_message.movementMethod = ScrollingMovementMethod()
        btn_start_message.setOnClickListener {
            if (!bPlay) {
                bPlay = true
                //线程第一种写法的调用方式,通过具体的线程类进行构造。
                //注意每个线程实例只能启动一次,不能重复启动。
                //若要多次执行该线程的任务,则需每次都构造新的线程实例。
                //PlayThread().start()
                //线程的第二种写法,采用匿名类的形式。第二种写法无需显式构造
                Thread {
                    //发送“开始播放新闻”的消息类型
                    handler.sendEmptyMessage(BEGIN)
                    while (bPlay) {
                        //休眠两秒,模拟获取突发新闻的网络延迟
                        Thread.sleep(2000)
                        val message = Message.obtain()
                        message.what = SCROLL
                        message.obj = news[(Math.random() * 30 % 5).toInt()]
                        //发送“持续滚动新闻”的消息类型
                        handler.sendMessage(message)
                    }
                    bPlay = true
                    Thread.sleep(2000)
                    //发送“结束播放新闻”的消息类型
                    handler.sendEmptyMessage(END)
                    bPlay = false
                }.start()
            }
        }
        btn_stop_message.setOnClickListener { bPlay = false }
    }

    //自定义的处理器类,区分三种消息类型,给tv_message显示不同的文本内容
    private val handler = object : Handler() {
        override fun handleMessage(msg: Message) {
            val desc = tv_message.text.toString()
            tv_message.text = when (msg.what) {
                BEGIN -> "$desc\n${DateUtil.nowTime} 下面开始播放新闻"
                SCROLL -> "$desc\n${DateUtil.nowTime} ${msg.obj}"
                else -> "$desc\n${DateUtil.nowTime} 新闻播放结束,谢谢观看"
            }
        }
    }

}

通过线程加上处理器固然可以实现滚动播放的功能,可是想必大家也看到了,这种交互方式依旧很突兀,还有好几个难以克服的缺点:

1、自定义的处理器仍然存在类继承和函数重载的冗余写法;
2、每次操作界面都得经过发送消息、接收消息两道工序,繁琐且拖沓;
3、线程和处理器均需在指定的Activity代码中声明,无法在别处重用;
有鉴于此,Androi

首页 上一页 1 2 下一页 尾页 1/2/2
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇[Android][Recovery] Recovery下.. 下一篇Android音乐播放器的设计与实现

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目