Android HandlerThread 使用指南

在 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 
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值