在 Android 开发中,需要把耗时操作放到子线程中,避免阻塞主线程,从而导致程序 ANR。实现这类异步任务的方式有:
- Thread + Handler
- AsyncTask
- HandlerThread
- IntentService
本文来讲解分析下 HandlerThread,在真正开始前,我们先了解下 Handler 的使用方式。
Handler 机制
子线程中创建 Handler
public class MainActivity extends AppCompatActivity {
private Handler handler;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
new Thread(new Runnable() {
@Override
public void run() {
handler = new Handler();
}
}).start();
}
}
程序崩溃了,意思是说:在线程中没有调用 Looper.prepare() 方法,是不能创建 Handler 对象的。
原因分析:
我点进 Handler 构造函数源码看下,会发现在创建 Handler 对象时,系统会检验当前线程中是否存在 Looper 对象,如果没有,则会抛出异常。
Handler 源码:
/**
Handler.java
*/
public Handler() {
this(null, false);
}
public Handler(Callback callback, boolean async) {
if (FIND_POTENTIAL_LEAKS) {
final Class<? extends Handler> klass = getClass();
if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
(klass.getModifiers() & Modifier.STATIC) == 0) {
Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
klass.getCanonicalName());
}
}
mLooper = Looper.myLooper(); // 获取当前线程的 Looper 对象
if (mLooper == null) {
throw new RuntimeException( // 没有Looper 对象,则需要调用 Looper.prepare()创建 Looper
"Can't create handler inside thread that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
那么为什么在主线程中创建 Handler 对象,没有调用 Looper.prepare() 方法,程序没有崩溃呢?这是因为主线程在创建时,系统帮我们创建好了 Looper 对象。看下程序入口 ActivityThread.main() 源码:
/**
* ActivityThread.java
*/
public static void main(String[] args) {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain");
SamplingProfilerIntegration.start();
// CloseGuard defaults to true and can be quite spammy. We
// disable it here, but selectively enable it later (via
// StrictMode) on debug builds, but using DropBox, not logs.
CloseGuard.setEnabled(false);
Environment.initForCurrentUser();
// Set the reporter for event logging in libcore
EventLogger.setReporter(new EventLoggingReporter());
// Make sure TrustedCertificateStore looks in the right place for CA certificates
final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId());
TrustedCertificateStore.setDefaultUserDirectory(configDir);
Process.setArgV0("<pre-initialized>");
Looper.prepareMainLooper(); // 获取主线程中的Looper对象,该方法最终会调用Looper构造函数
ActivityThread thread = new ActivityThread();
thread.attach(false);
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
if (false) {
Looper.myLooper().setMessageLogging(new
LogPrinter(Log.DEBUG, "ActivityThread"));
}
// End of event ActivityThreadMain.
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
结论:在线程中创建 Handler 对象,需要存在该线程的 Looper 对象。子线程需要我们手动创建 Looper 对象,即在该线程中调用 Looper.prepare()创建,并用 Looper.loop() 方法启动轮询;主线程中系统帮我们创建好了 Looper 对象。
常规用法:
new Thread(new Runnable() {
@Override
public void run() {
Looper.prepare(); // 创建 Looper
workerHandler = new Handler();
Looper.loop(); // 开启轮询
}
}).start();
Handler 不同线程之间通信
(1)子线程向子线程发送消息
子线程和子线程发消息,就是在一个子线程中创建 Handler ,这样回调 handleMessage()就自然会在子线程中,然后,在另一个子线程中使用该 handler 进行发送消息。
public