主线程(UI Thread)
- 当Android应用程序启动时,系统会创建一个主线程(main thread).
- 默认情况下,程序的操作都在这个主线程中进行,包括应用和用户界面UI的交互,所有main thread 也叫UI thread 也叫UI线程。
主线程阻塞
- 因为所有的工资都在UI线程,当做一些比较好使的工作(比如访问网络或者数据库查询)就会阻塞UI线程。
- 当UI线程被阻塞的时候,对于用户来说,应用程序看起来像是卡住了,更坏的情况是,如果UI线程阻塞的时间太长了(大约5秒),用户就会看到ANR(application not responding)的对话框
- 因此,应该避免阻塞UI线程。
非UI线程:子线程(Worker Thread)
- 要保证应用程序的响应性,不能阻塞UI线程,所有当操作不是即使操作,应该把它们放进另外的单线程中,(一般叫做background或者叫worker线程)。
- 不能从非UI线程来操作UI组件
异步消息机制可以实现:
- 线程之间发送消息
- 线程之间传递数据
异步消息机制实现方法
- Handler机制
- AsyncTask异步任务
Handle异步消息机制实现
- 同步调用:就是在一个函数或方法调用时,没有得到结果之前,该调用就不返回,直到返回结果。
- 异步调用:在一个异步调用发起后,被调用者立即返回给调用者,但是调用者不能立刻得到结果,被调用都在实际处理这个调用的请求完成后,通过状态、通知或回调等方式来通知调用者请求处理的结果。
- Handler提供了一种异步的线程操作方案以及异步消息处理机制,它可以把消息和Runnable对象发送到与Hanlder相关联的消息队列中。
- 通俗来讲,就是用来在线程之间发送消息的处理对象。
- 在任何线程中只要获得了另一个线程的Handle对象,就可以通过sendMessage(Messagemsg)方法向目标线程发送消息。
- Android单线程模型
- 不可以阻塞UI,在UI线程中执行耗时操作
- 在飞UI线程不能操作UI组件
- 新增一个子线程,子线程执行耗时操作后可以通过主线程的Handler向UI线程发送消息,有UI线程去更新界面。
- Handler关联一个单独的线程,拥有线程的消息队列
- 默认情况下,Handler和调用该Handler的线程关联
- Handler可以接收、调度、派发、处理消息
- 涉及到的核心类
- Looper
- 消息循环通道,Looper包含了一个Message Queue(消息队列)
- 在使用Handler处理Massge时,需要Looper(通道)来完成
- Looper不断的取出消息,交给Handler处理
- Looper
- Handler
- 主要作用是消息处理
- Message
- 消息类,主要功能是进行消息的封装,封装了消息和处理改任务的Handler。
UI主线程的消息循环
- 默认UI、
- 主线程已经具备消息循环机制
- 只需要为主线程创建一个Handler即可开始进行消息处理
- 需要注意的是:非UI线程默认没有消息循环,需要通过Looper.prepare()和Looper.loop()为其建立消息循环。
主线程Handler使用的基本步骤
- 在Activity中生成Handler对象uiHandler,并重写HandlerMessage方法。
- 在主线程中启动子线程
- 在子线程中创建消息,然后调用sendMessage方法想uiHandler发送消息。
- 在uiHandler中handleMeaage会根据消息的不用进行相应的操作,如更新UI
关键代码:uiHandler创建
//创建uiHandler
private Handler uiHandler = new Handler(){
@Override
public void handleMessage(Message msg){
super.handlerMessage(msg);
//根据消息不同做不同的处理
switch(msg.what){
case 1:{
//获取数据,并更新到UI
bm = (Bitmap)msg.obj;
previewImage();
break;
}
case 0:{
//提示用户数据获取失败
Toast.makeText(DemoSetScreenHandle.this,"子线程获取数据失败",Toast.LENGTH_SHORT).show();
break;
}
}
}
};
关键代码:子线程创建消息并发送消息
class workThread extends Thread{
@Override
public void run(){
super.run();
try{
//执行子线程任务,获取网络数据
URL url = new URL("https://www.baidu.com/img/bd_logo1.png");
URLConnection conn = url.openConection();
Bitmap bmBitmap = BitmapFactory.decodeStream(conn.getInputStream());
//创建消息
Message newmsg = new Message();
newmsg.what = 1;
newmag.obj = bmBitmap;
//发送消息
uiHandler.sendMessage(newmag);
}catch(Excrption e){
Log.e(TAG,e.getMessage());
}
}
}
AsyncTask类的应用
Android为了降低这个开发难度,提供了AsyncTask。AsyncTask就是一个封装过的后台任务类,顾名思义就是异步任务。
AsyncTask直接继承于Object类,位置为android.os.AsyncTask .
AsyncTask定义了三种泛型类型 Params,Progress和Result。
· Params 启动任务执行的输入参数,比如HTTP请求的URL。
· Progress 后台任务执行的进度百分比。
· Result 后台执行任务最终返回的结果,比如String。
一个异步任务的执行一般包括以下几个步骤:
1.execute(Params… params),执行一个异步任务,需要我们在代码中调用此方法,触发异步任务的执行。
2.onPreExecute(),在execute(Params… params)被调用后立即执行,一般用来在执行后台任务前对UI做一些标记。
3.doInBackground(Params… params),在onPreExecute()完成后立即执行,用于执行较为费时的操作,此方法将接收输入参数和返回计算结果。在执行过程中可以调用publishProgress(Progress… values)来更新进度信息。
4.onProgressUpdate(Progress… values),在调用publishProgress(Progress… values)时,此方法被执行,直接将进度信息更新到UI组件上。
5.onPostExecute(Result result),当后台操作结束时,此方法将会被调用,计算结果将做为参数传递到此方法中,直接将结果显示到UI组件上。
6.onCancelled() 用户调用取消时,要做的操作
Handler异步消息处理
Handler机制主要角色
n Message:消息,其中包含了消息ID,消息处理对象以及处理的数据等,由MessageQueue统一列队,终由Handler处理。
n Handler:处理者,负责Message的发送及处理。使用Handler时,需要实现handleMessage(Message msg)方法来对特定的Message进行处理,例如更新UI等。
n MessageQueue:消息队列,用来存放Handler发送过来的消息,并按照FIFO规则执行。当然,存放Message并非实际意义的保存,而是将Message以链表的方式串联起来的,等待Looper的抽取。
n Looper:消息泵,不断地从MessageQueue中抽取Message执行。因此,一个MessageQueue需要一个Looper。
n Thread:线程,负责调度整个消息循环,即消息循环的执行场所。