当前位置 博文首页 > 庆述倾述:HandlerThread案例学习

    庆述倾述:HandlerThread案例学习

    作者:[db:作者] 时间:2021-08-05 12:45

    Android的消息机制中,如果需要在子线程中创建Hanlder来处理消息,那么很经典的代码如下:

    new Thread(new Runnable() {
        @Override
        public void run() {
            Looper.prepare();
            handler = new Handler(Looper.myLooper()){
                @Override
                public void handleMessage(@NonNull Message msg) {
    
                }
            };
            Looper.loop();
        }
    }).start
    

    这样处理比较繁琐,有点类似于Service中的意图服务的意思。因为自己创建比较繁琐,故而官方就提供了一套封装。

    回顾一下:使用意图服务的时候,只需要自定义一个继承自IntentService的类,复写onHandleIntent方法即可,然后可在该方法中进行耗时操作,且操作完成后自动销毁Service

    那么在使用HandlerThread的时候,应该如何?

    HandlerThread 是一个包含 LooperThread,我们可以直接使用这个 Looper 创建 Handler

    HandlerThread 所做的就是在新开的子线程中创建了 Looper,那它的使用场景就是 前面提到的需要在子线程中创建Handler,来处理消息的场景。

    这里不妨看下这个类的构成:

    public class HandlerThread extends Thread {
        int mPriority;
        int mTid = -1;
        Looper mLooper;
        private @Nullable Handler mHandler;
        ...
        
        public void run() {
            mTid = Process.myTid();
            Looper.prepare();
            synchronized (this) {
                mLooper = Looper.myLooper();
                notifyAll();
            }
            Process.setThreadPriority(mPriority);
            onLooperPrepared();
            Looper.loop();
            mTid = -1;
        }
        
        public Handler getThreadHandler() {
            if (mHandler == null) {
                mHandler = new Handler(getLooper());
            }
            return mHandler;
        }
    }
    

    在上面可以看见HandlerThread是一个线程类,且在run方法中初始化了对应的Looper对象,在getThreadHandler方法中创建一个和Looper关联的Handler对象。

    那么,我们在使用的时候应该如何使用?不妨看看下面的简单案例:

    public class MainActivity extends AppCompatActivity {
    
        private Handler workHandler;
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            Button button = findViewById(R.id.id_mybutton);
    
            // 【开启子线程】开启一个子线程来处理消息  Looper+Thread+Handler
            HandlerThread handlerThread = new HandlerThread("MyHandlerThread");
            handlerThread.start();
            workHandler = new Handler(handlerThread.getLooper()){
                @Override
                public void handleMessage(@NonNull Message msg) { // 【子线程处理消息】
                    String channelId = "weizu";
                    // 1. 创建通知管理器
                    NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
                    // 2. 创建通道
                    NotificationChannel channel = new NotificationChannel(channelId,
                            "Simple Test", NotificationManager.IMPORTANCE_DEFAULT);
                    manager.createNotificationChannel(channel);
                    // 3. 创建通知对象
                    Notification.Builder builder = new Notification.Builder(MainActivity.this, channelId);
                    Intent intent = new Intent(getApplicationContext(), MainActivity.class);
                    PendingIntent pi = PendingIntent.getActivity(getApplicationContext(), 0, intent, 0);
                    Notification notification = builder.setContentTitle("Info")
                            .setContentText((String) msg.obj)
                            .setContentIntent(pi)
                            .setSmallIcon(R.drawable.ic_baseline_bluetooth_24)
                            .setAutoCancel(true)
                            .build();
                    // 4. 发送通知
                    manager.notify(1, notification);
                }
            };
    
            button.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    // 【主线程】点击事件来发送消息
                    Message msg = Message.obtain();
                    msg.what = 1;
                    msg.obj = "Hello";
                    workHandler.sendMessage(msg);
                }
            });
        }
    }
    

    在上面的结果中,我们在子线程HandlerThread中也可以在状态栏显示通知,进行了消息的处理。

    需要注意的是,子线程中不可进行更新UI操作,显然,这里的Notification不属于更新UI操作。

    注意到在run中调用了Looper.loop方法,故而是一个无限循环。

    也就是说这个HandlerThread方法不会自动停止,我们需要显示的调用quit方法,当不需要的时候,可以结束线程,即workHandler.quit();


    另在IntentService类中也有HandlerThread的影子:

    public abstract class IntentService extends Service {
        private volatile Looper mServiceLooper;
        private volatile ServiceHandler mServiceHandler;
        private final class ServiceHandler extends Handler {
            public ServiceHandler(Looper looper) {
                super(looper);
            }
    
            @Override
            public void handleMessage(Message msg) {
                onHandleIntent((Intent)msg.obj);
                stopSelf(msg.arg1);
            }
        }
        ...
        public void onCreate() {
        	super.onCreate();
            HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
            thread.start();
    
            mServiceLooper = thread.getLooper();
            mServiceHandler = new ServiceHandler(mServiceLooper);
        }
    

    在个方法中类似的关联了Looper对象、Handler对象,以及前面提到的HandlerThread线程对象。且在onCreate周期函数中的使用方式和我们的案例中类似。

    cs
    下一篇:没有了