Hanlder简介
相比于 AsyncTask,Handler类允许准确的控制操作的运行时间,而且还可以多次使用,执行的操作会一直运行,直到被显示的停止。每个Handler实例都被包含在一个单独的线程里面。
Handler有两个主要的用途 :
- 确保一些调度信息和任务在未来的某一时刻被执行
- 让一些行为在其他的线程中表现出来
HandlerThread 介绍
HandlerThread类用于创建一个带有 Looper 的新线程,这个Looper可以用于创建Handler实例,HandlerThread 的实例必须在调用start()方法后才可以使用。
构造方法 :
- HandlerThread(String name)
- HandlerThread (String name, int priority) //priority 就是线程运行的优先级,由 Process类中的变量 来指定
方法 :
- getLooper ()
这个方法用于获取与该线程相关联的 Looper,如果该线程没有开启,也即未调用 start()方法,那么这个方法会返回一个 null值。如果线程已经开启,这个方法会被阻塞直到 Looper初始化完成。
- getThreadId ()
用于返回线程的标识符
- quit ()
停止线程中的Looper,该方法被调用后,任何对Looper 的请求都会失败。比如,sendMessage(Message)方法会返回false。使用这个方法可能是不安全的,因为在Looper被终止的时候可能还有 Message未被递交。
- quitSafely ()
和上一个方法完成的功能相同,不过这个方法更安全,因为在Looper被终止时,一些未递交的Message会因为时间的关系不再递交。
- run ()
调用Runnable对象中的run()方法,如果未设置Runnable,就什么也不做。
- onLooperPrepared ()
该方法是protected类型的,当我们需要在Looper的loop() 方法调用前需要完成一些工作,那么可以复写这个方法。
Looper 的简单介绍
Looper类用来为线程运行 消息循环,默认的Threads并不包含一个 message loop,为了创建一个,可以在线程中调用 prepare(),然后调用 loop()去处理messages
官方给出的示例
class LooperThread extends Thread {
public Handler mHandler;
public void run() {
Looper.prepare();
mHandler = new Handler() {
public void handleMessage(Message msg) {
// process incoming messages here
}
};
Looper.loop();
}
}
介绍一下Looper 类中的一些方法
- Looper getMainLooper ()
获得应用程序的主Looper,存在于主线程中
- Thread getThread ()
返回与该Looper 关联的 Thread
- void loop ()
在线程中运行message queue,与此方法对应的是quit()方法,而且这两个方法必须同时出现。
- Looper myLooper ()
返回与该线程关联的 Looper,如果该线程没有关联 Looper,就返回 null
- MessageQueue myQueue ()
返回与该线程关联的 MessageQueue,如果在未关联Looper的线程中调用该方法,会抛出NullPointerException
- void prepare ()
初始化该线程作为一个Looper
- void quit ()
- void quitSafely()
功能和上面HandlerThread中介绍的一样
异步消息处理机制
首先,在主线程中创建一个 Handler,并重写 handleMessage()方法,然后当子线程需要进行 UI 操作时,就创建一个Message 对象,并通过 Handler 将消息发送出去。之后这条消息会被添加到 MessageQueue的队列中进行等待,而 Looper 会一直尝试从 MessageQueue 中取出待处理消息,最后分发回 Handler 的 handleMessage() 方法中。由于 Handler是在主线程中创建的,此时的 handleMessage()也会在主线程中得到执行。
一个Message经过一个流程的辗转,从子线程进入到主线程,从不能更新 UI到可以更新UI,这就是异步消息处理机制的核心思想。
Hanlder 的简单使用
由于 Handler 中的方法太多,就不逐一介绍了,下面来介绍 几种给 Handler发送信息的方法。
- Message.obtain(mHanlder,FLAG,data).sendToTarget()
创建一个标识为FLAG,数据为 data的Message,立刻将其发送到 Handler去执行
- mHandler.sendEmptyMessage(FLAG)
立刻给 Handler发送一个带有标识的空消息
- mHanlder.sendEmptyMessageAtTime(FLAG,1000)
给 Handler发送一个简单的空消息,该消息会在一秒后被递交给Looper
- mHandler.sendEmptyMessageDelayed(FLAG,1000)
效果同上
下面利用 Handler 来更改 UI
public class MainActivity extends AppCompatActivity {
public static final int FLAG = 0;
private Button mButton;
private TextView mTextView;
private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
if (msg.what == FLAG) {
mTextView.setText("After Changer");
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mButton = (Button) findViewById(R.id.start);
mTextView = (TextView) findViewById(R.id.tx);
mButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
new Thread(new Runnable() {
@Override
public void run() {
mHandler.sendEmptyMessage(FLAG);
}
}).start();
}
});
}
}
注意,这个时候mHandler使用的是默认Looper,也即 MainLooper,我们也可以通过 HandlerThread来使用自己的Looper执行该操作。
public class MainActivity extends AppCompatActivity implements Handler.Callback {
public static final int FLAG = 0;
private Button mButton;
private TextView mTextView;
private HandlerThread mHandlerThread;
private Handler mHandler;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mHandlerThread = new HandlerThread("MyHandlerThread");
mHandlerThread.start();
mHandler = new Handler(mHandlerThread.getLooper(), this);
mButton = (Button) findViewById(R.id.start);
mTextView = (TextView) findViewById(R.id.tx);
mButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
new Thread(new Runnable() {
@Override
public void run() {
mHandler.sendEmptyMessage(FLAG);
}
}).start();
}
});
}
@Override
public boolean handleMessage(Message message) {
if (message.what == FLAG) {
mTextView.setText("After Change");
}
return true;
}
}
这个时候会出现一个错误,因为我们自己的Looper 是没有权限去更新 UI的,如果想要更新UI ,可以在Handler的构造方法中使用 getMainLooper()方法。
以上我们都使用使用默认的mHandler和 HandlerThread,我们也可以写一个类继承自HandlerThread或者Handler,在自定义的类中可以执行一些耗时任务,因为这个时候所有的任务都是在子线程中执行的,并不会阻塞主线程。
关于 AsyncTask和 Handler的选择,如果不是很频繁的执行一个操作,而且操作可以在较短时间内完成,使用AsyncTask是十分方便的。如果需要安排操作的时间或者需要快速间隔的执行某操作,Handler 是不错的选择。