Android中线程按功能分的话,能够分为两个,一个是主线程(UI线程),其余的都是子线程数组
主线程不能执行那些耗时过长的代码或任务(执行耗时过长的代码会出现应用未响应的提示),因此都是使用子线程来执行耗时过长的代码,好比说下载文件等任务安全
通常状况,子线程中执行过长的代码,都是须要进行更新UI操做。async
可是Android中,为了防止安全,是不容许在子线程更新UI的,可是咱们可使用到Android官方给予的API来实现子线程更新UI的操做(本质上,这些API也是切换回了主线程来进行更新UI)ide
**例子:**点击一个按钮,过了1s后完成了下载任务,返回了数据,此数据会显示在界面上post
具体解释:ui
点击按钮,以后开启一个子线程来模拟下载过程(线程休眠1s),以后任务执行完毕会返回数据(一个String),使用返回的数据更新UIthis
新建一个方法,用来模拟下载任务url
/** * 模拟下载 */ fun download(): String { Thread.sleep(1000) return "this is data" }
下面的使用6种方式和上面的模拟下载任务的方法,来实现上面例子的效果线程
runOnUiThread
是Activity中的方法,只有当前对象是Activity,就能够直接使用,若是当前的对象不是Activity,须要找到Activity对象,才能执行此方法code
runOnUiThread
方法的参数为一个Runnable接口,我使用的kotlin,因此有不少东西都是省略了
设置按钮的点击事件,点击按钮开启一个线程
btn_start.setOnClickListener { thread { val data = download() runOnUiThread({ //这里进行更新UI操做 tv_show.text = data }) } }
Java版
btn_start.setOnClickListener(new OnClickListener(){ new Thread(new Runnable(){ String data = download(); runOnUiThread(new Runnable(){ @Override public void run() { tv_show.setText(data); } }) }).start(); });
post方法是View对象的方法,参数也是接收一个runnable接口
这里我选用的view对象是须要进行更新textview的自己,固然也能够选用其余的View对象,只要是在当前Activity的对象均可以
btn_start.setOnClickListener { thread { val data = download() //选择当前Activity的View对象均可以 tv_show.post { tv_show.text = data } } }
此方法和上面的post方法相似,只是多一个参数,用来实现延迟更新UI的效果
btn_start.setOnClickListener { thread { val data = download() tv_show.postDelayed({ tv_show.text = data },2000) } }
上面的代码实现的效果是点击按钮以后,过了3s后才会看到界面发生改变
new一个Handler对象(全局变量)
private val handler = Handler()
使用post方法更新UI,此post方法和以前的post方法同样,参数都是为Runnable接口
btn_start.setOnClickListener { thread { val data = download() handler.post { tv_show.text = data } } }
AsyncTask是一个抽象类,必须建立一个子类类继承它
这里介绍一下关于AsyncTask的三个泛型参数和几个方法
泛型参数能够为任意类型,为空的话使用Void
参数 | 说明 |
---|---|
params | 参数泛型,doInBackground方法的参数 |
progress | 进度泛型,onProgressUpdate方法的参数 |
result | 结果泛型,onPostExecute方法的参数 |
抽象方法说明:
方法名 | 说明 |
---|---|
onPreExectute() | 此方法中,经常进行初始化操做,如进度条显示 |
doInBackground(Params...) | 此方法必须实现, |
onProgressUpdate(Progress...) | 进行更新UI的操做 |
publishProgress(Progress...) | 在doInBackground方法中调用,调用此方法后会回调执行onProgressUpdate方法进行更新UI |
onPostExcute(Result) | 任务结束以后进行更新UI |
简单来讲,若是子类继承了AsyncTask,它的抽象方法的参数都会变成泛型对应的类型
下面的代码是取自个人APP,简单地说明一下AsyncTask<String, DownloadingItem, DownloadedItem>
我传入的是3个泛型参数分别为String
,DownloadingItem
,DownloadedItem
,分别对应的params
,progress
和result
泛型
这里我是根据本身的须要而两个类DownloadingItem
和DownloadedItem
,从下面的代码能够看到,抽象方法的参数变为了咱们的泛型的类型
internal inner class DownloadingTask : AsyncTask<String, DownloadingItem, DownloadedItem>() { override fun onPreExecute() { //一些初始化操做 } override fun doInBackground(vararg params: String?): DownloadedItem { //params是一个参数数组,若是建立DownloadingTask对象只传入了一个参数,直接取下标为0的那个便可(须要转型) //耗时操做(以下载操做),得到进度数据 //将新的进度数据传递到onProgressUpdate方法,更新UI publishProgress(messageItem) //任务执行完毕,返回结果(回调onPostExecute方法) } override fun onProgressUpdate(vararg values: DownloadingItem?) { //这里使用最新的进度来进行相关UI的更新 //values是一个DownloadingItem数组,取末尾那个即为最新的进度数据 } override fun onPostExecute(result: DownloadedItem?) { //下载成功提示或者是其余更新UI的操做 } }
执行:
执行Task的时候须要在主线程(UI线程调用)
DownloadingTask().execute("参数")
批量下载:
//容许在同一时刻有5个任务正在执行,而且最多可以存储50个任务 private val exec = ThreadPoolExecutor(5, 50, 10, TimeUnit.SECONDS, LinkedBlockingQueue<Runnable>()) DownloadingTask().executeOnExecutor(exec, url)
其实,Handler机制是子进程更新UI的核心
咱们上面的五种实现子进程更新UI的方式,都是基于Handler机制实现的
具体机制本文就很少说了,网上有许多的机制说明,这里就只讲一下实现的步骤
Message中有几个属性,what
,arg1
,arg2
,这三个都是接收一个Int,因此,传递数据不是很友好,这里就不许备实现以前的例子效果了
what表示来源,arg1和arg2用来传递Int数据
通常都是规定好一个Int的常量,来表示what
private val handler =object : Handler(){ override fun handleMessage(msg: Message?) { if (msg.what == 1) { //来源为1,则 } } }
val msg = handler.obtainMessage() //通常都是规定好一个Int的常量,来表示what msg.what = 1 //传递Int数据 msg.arg1 = 20 handler.sendMessage(msg)