一
在安卓开发中,要求不能在主线程中做花费较长时间的UI操作,因为容易发生ANR(应用程序无响应(ANR:Application Not Responding):在一定的时间内没有做完相应的处理。)
- 在Android中,应用程序的响应性是由Activity Manager和WindowManager系统服务进行监视 。如果响应输入的事件时间超过5S,broadcastReceiver超过10S,service超过20S,就会引起ANR。 - 用户可以选择“等待”而让程序继续运行,也可以选择“强制关闭”。
避免ANR:1、不在主线程做耗时操作;2、不要让其他线程阻塞主线程的执行。
所以我们通常会把耗时操作移至子线程去操作,然后等子线程处理好耗时处理的事件,再通知UI进行变化,这时候就需要“Handle”(线程间通信)
Handler机制主要角色
Message: 消息,就是一个载体,包含消息ID,消息处理对象和处理的数据等,统一放到MessageQueue,最终由Handler处理。
Handler: 用于同一个进程的线程间通信,消息处理者,专门负责Message的发送和处理。我们使用Handler时,一般通过handleMessage(Message msg)来处理Message,也就是统一处理消息的回调,确保自己发出的消息也是自己来处理。
MessageQueue: 由名字可推出这是队列,就是存放Handler发送过来的消息,按照先进先出的顺序规则来执行。将链表的数据结构以Message来串联起来,等待Looper的抽取,为什么需要队列呢?因为同一线程在一个时间只能处理一个消息。因此需要队列来保存这些消息,然后挨个挨个拿出来处理,创建一个线程时并不会自动创建MessageQueue,但是主线程创建时会默认创建Looper对象,而Looper创建时就会创建MessageQueue,其他非主线程需要looper的时候就会通过调用prepare函数来实现。
Looper: 一个线程可以产生一个Looper对象,由它来管理此线程里的MessageQueue(消息队列),首先,一个线程即是一段可执行的代码,作为App的主线程,不能让代码执行完,因为代码执行完的时候app就会自动退出,因此不能让主线程将代码段执行完,只能在代码中插入一个死循环,这时候Looper的作用就体现出来了,将主线程变成Looper线程。并且这时主线程就会在等其他线程发消息(更新UI和Activity状态等),另外,Looper会不断从消息队列取出消息送给主线程,也就是无限循环去查找是否有消息,有就去处理,没有的话就一直等待,一个MessageQueue需要一个Looper。
Thread: 负责调度整个消息的循环。
二
使用方法
通过handle与runnable中循环,使用sendMessage与post两个方法之间进行通讯。在runnable中运行耗时的操作,然后在handle中更新界面(UI). 1.创建handler,重写handleMessage()方法,在其内容中写要显示的界面 2.创建Runnable,在run中写费时间的代码,之后通过handle对象调用sendMessage()方法,发送消息到handle 3.如果要实现循环操作,就需要在handle中调用post()方法回到run中去。
使用步骤
1.创建Handler对象,重写handlerMessage(Message msg)方法,写出要显示的东西
Handler handler = new Handler(){ @Override public void handleMessage(@NonNull Message msg) { int index = msg.arg1; if(index == 100) { removeCallbacks(run); } progressBar.setProgress(index); handler.post(run); } };
2.创建runnable对象,实现run()方法,放入耗时操作
Runnable run = new Runnable() { @Override public void run() { try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } count = count + 1; Message msg = handler.obtainMessage(); msg.arg1 = count; handler.sendMessage(msg); } };
- 在主线程中调用:
handler.sendMessage(msg);
三
此外还要一些其他的方法也是差不多的机制去做耗时操作,以后再增加。