为什么要使用多线程?
当我们需要发出一条网络请求时,由于各种原因(网速过慢、服务器繁忙),服务器不能及时响应我们的请求,若我们将此操作放在的Main Thread中就会出现界面卡顿,甚至会出现ANR问题,为了解决Main Thread被阻塞的问题,我们只能另辟蹊径——开启子线程。
主线程
Main Thread主要处理UI有关的事件,如:按钮的点击事件,用户触摸事件、绘图事件等,并把相应的事件分发给相应的组件去处理,所以主线程又被成为UI线程。
子线程
除UI线程之外的线程成为子线程,一般都处理比较耗时的操作,如下载上传,访问数据库,读写文件等
线程的三种基本使用方法
1.集成Thread,并重写run()方法
eg: class MyThread extends Thread{
@Override
public void run(){
//处理具体的逻辑
}
}
启动线程时,需要new一个MyThread的实例,然后调用它的start()方法即可
2.直接实现Runnable接口
eg: class MyThread implements Runnable{
@Override
public void run(){
//处理具体的逻辑
}
}
启动方法
MyThread myThread=new MyThread();
new Thread(myThread).start();
3.匿名内部类的方式
new Thread (new Runnable(){
@Override
public void run(){
//处理具体的逻辑
}
}).start();
主线程的主要职责是负责显示、处理、更新UI控件,管理子线程,子线程的职责是处理一些耗时的操作,若有需要也要向主线程发送更新UI的消息。但新的问题是子线程与主线程如何发送消息通信呢?在Android中,提供了两种方式解决线程通信问题。
方式一 Handler机制
android的异步处理机制有四部分组成:Meaasge、Handler、MessageQueue、Looper。
Meaasge
Meaasge是在线程之间传递消息,它可以在内部携带少量的信息,用于在不同的线程之间交换数据,如:Message的what字段,arg1和arg2字段携带一些整形数据、object携带Object对象。
Handler
主要是用于发送和处理消息,发送消息一般使用Handler的sendMessage()方法,发送的消息最终会传到Handler的handlerMessage()方法中。
MessageQueue
MessageQueue是消息队列的意思,它主要用于存放所有通过Handler发送的消息,部分消息会一直存在于消息队列中等待被处理,每个线程中只会有一个MessageQueue对象。
Looper
Looper是每个线程中MessageQueue的管家,调用Looper的loop()方法,就会进入到一个无限循环中,每当发现MeaasgeQueue中有消息,就会将该消息拿出来,并传递到Handler的handlerMessage()方法中。每个线程也只有一个Looper对象。
方式一 AsynTask
Android的AsynTask异步任务是比Handler更轻量级一些,适用于简单的异步处理。AsynTask就是一个封装过的后台任务类。我们可以将耗时的操作放在异步任务中来处理,并随时将任务执行的结果返回给我们的UI线程来更新我们的UI控件。AsynTask直接继承于Object类,位置为android.os.AsynTask,要使用AsynTask我们提供三个泛型参数并重载几个方法
AsynTask定义三种泛型类型 Params, Progress,Result
1)Params 启动任务执行的输入参数,比如HTTP求情的URL
2)Progress 后台任务执行的百分比
3)Result 后台任务执行的最终结果
使用AsynTask异步加载数据最少要重写一下这两种方法:
1) doInBackground(Params…) 后台执行,比较耗时的操作都可以放在这里处理,注意这里不能直接操作UI,此方法在后台线程执行,完成任务的主要工作,通常需要较长的时间,在执行过程中可以调用publishProgress(Progress…)来更新任务进度。
2)onPostExecute(Result) 相当于Handler处理UI的方式,在这里可以使用doInBackground得到的结果处理操作UI,此方法在主线程中执行,任务执行的结果作为此方法的参数返回。
3)onProgressUpdate(Progress…) 可以使用进度条增加用户体验度,此方法在主线程执行,用于显示任务的进度。
4)onPreExecute() 这里是最终用户调用Excute时的接口,当任务执行之前开始调用此方法,可以在这里显示对话框的进度。
5)onCancalled() 用户调用取消时要做的操作。
使用AsynTask必须遵守以下准则
1)AsynTask 的实例必须在UI Thread中创建
2)execute 方法必须在UI Thread中调用
3)不要手动调用doInBackground(Params…)、onPostExecute(Result)、onProgressUpdate(Progress…)这几个方法,该Task只能被调用执行一次,多次调用将会出现异常。