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
是不错的选择。