Android Looper:如何实现消息循环和异步执行任务

一、了解Android消息机制

Android消息机制是指通过 Message、Handler 和 Looper 三者相互配合,实现在子线程中发送消息、处理消息,从而实现异步执行任务的方案。其中,Message 负责携带消息的内容,Handler 负责处理消息,而 Looper 则是消息循环机制的核心。在此机制下,我们可以在主线程中往子线程中发送消息,也可以在子线程中向主线程发送消息,从而实现更加灵活的多线程编程。

二、学习Looper类的基本结构

public class Looper {
    private static final Object sLock = new Object();
    private static Looper sMainLooper = null;
    final MessageQueue mQueue;
    private final Thread mThread;
    private boolean mRun;

    private Looper(boolean quitAllowed) {
        mQueue = new MessageQueue(quitAllowed);
        mThread = Thread.currentThread();
    }

    public static void prepare() {
        prepare(true);
    }

    public static void prepare(boolean quitAllowed) {
        if (sThreadLocal.get() != null) {
            throw new RuntimeException("Only one Looper may be created per thread");
        }
        sThreadLocal.set(new Looper(quitAllowed));
    }

    public static void loop() {
        final Looper me = myLooper();
        if (me == null) {
            throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
        }
        final MessageQueue queue = me.mQueue;

        for (;;) {
            Message msg = queue.next(); // might block
            if (msg == null) {
                return;
            }
            try {
                msg.target.dispatchMessage(msg);
            } finally {
                msg.recycleUnchecked();
            }
        }
    }

    public static void quit() {
        final Looper me = myLooper();
        if (me == null) {
            throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
        }
        synchronized (me.mQueue) {
            me.mRun = false;
            me.mQueue.notifyAll();
        }
    }

    public static Looper myLooper() {
        return sThreadLocal.get();
    }
}

以上是 Looper 类的源码,其中最重要的属性是 MessageQueue,它通过链表的结构保存所有需要执行的消息。Looper 自身则主要是调用 MessageQueue 的 next 方法进行轮询,然后将消息交给对应的 Handler 处理,最后将 Message 回收利用以节约资源。

三、了解Message的实现

public final class Message {
    public int what;
    public int arg1;
    public int arg2;
    public Object obj;
    public long when;
    public Handler target;
    Message next;
    public int sendingUid = -1;
    public Bundle data;

    private static final Object sPoolSync = new Object();
    private static Message sPool;

    private static int sPoolSize = 0;
    private static final int MAX_POOL_SIZE = 50;
    private static boolean gCheckRecycle = true;
    private boolean mRecycled;

    public static final int FLAG_IN_USE = 1 << 0;
    int flags;
    private static final int FLAGS_TO_CLEAR_ON_COPY_FROM = FLAG_IN_USE;

    private static boolean gCheckRecycleUnchecked = true;

    private Message() {}

    public static Message obtain(Handler h) {
        Message m = get();
        m.target = h;

        return m;
    }

    private static Message get() {
        synchronized (sPoolSync) {
            if (sPool != null) {
                Message m = sPool;
                sPool = m.next;
                m.next = null;
                m.flags = 0;
                m.sendingUid = -1;
                sPoolSize--;
                return m;
            }
        }
        return new Message();
    }

    void recycleUnchecked() {
        if (mRecycled) {
            if (gCheckRecycleUnchecked) {
                throw new IllegalStateException("This message cannot be recycled because it "
                        + "is still in use.");
            }
            return;
        }
        mRecycled = true;
        clearForRecycle();
        synchronized (sPoolSync) {
            if (sPoolSize < MAX_POOL_SIZE) {
                next = sPool;
                sPool = this;
                sPoolSize++;
            }
        }
    }

    void clearForRecycle() {
        flags = 0;
        what = 0;
        arg1 = 0;
        arg2 = 0;
        obj = null;
        when = 0;
        target = null;
        // Explicitly target data to its more specific implementation to ensure
        // that it's correctly recycled after a transfer.
        data = null;
    }
}

以上代码是 Message 类的实现代码,它主要包括消息类型和消息内容,配合 Handler 来执行对应的操作。其中 mostPoolSize 规定了该类允许缓存的最大实例数量,可以看到它通过静态 sPoolSync 锁实现了资源的共享,以此达到了 Message 回收、利用和避免浪费的效果。

四、创建一个自定义Handler进行消息处理

public class MyHandler extends Handler {
    @Override
    public void handleMessage(Message msg) {
        super.handleMessage(msg);
        // 根据不同的消息类型,执行对应的操作
        switch (msg.what) {
            case 1:
                // 执行操作1
                break;
            case 2:
                // 执行操作2
                break;
            default:
                break;
        }
    }
}

通过继承 Handler 类,我们可以在自定义的 handleMessage 方法中处理各种不同消息类型的执行操作。其中,msg.what 用于表示消息类型,可以根据不同的需求来自定义,比如用数字表示不同的操作,或者用 final 常量来表示特定的操作。

五、在子线程中使用 Looper

public class MyThread extends Thread {
    @Override
    public void run() {
        Looper.prepare();
        MyHandler handler = new MyHandler();
        Looper.loop();
    }

    public void sendMessage(Message msg) {
        if (handler != null) {
            handler.sendMessage(msg);
        }
    }
}

以上代码演示了如何在子线程中使用 Looper。通过调用 Looper 类的 prepare 方法和 loop 方法,我们可以开始一个消息循环。在此循环中,我们可以根据不同的需求,使用自定义的 Handler 来处理消息逻辑。而 sendMessage 方法则是用于在 MyThread 中发送消息所用。

六、在主线程中使用 Handler

public class MainActivity extends AppCompatActivity {
    private MyThread myThread;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        myThread = new MyThread();
        myThread.start();

        findViewById(R.id.btn_send_message).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Message msg = Message.obtain();
                msg.what = 1;
                myThread.sendMessage(msg);
            }
        });
    }
}

可以看到,MainActivity 中的 onCreate 方法中创建了一个 MyThread 线程,并在点击按钮的回调中发送了一个携带了消息类型为1的消息,这样就能够在子线程中执行对应的逻辑操作了。

七、总结

本文以 Android 中消息机制的核心类 Looper、Message 和 Handler 为中心,详细介绍了消息循环、消息获取、消息分发过程,还有如何在子线程中创建 Looper、Handler,以及如何在主线程中发送消息触发相应的处理操作。只有充分理解 Android 的消息机制,才能更好的进行多线程编程,提高应用程序的性能与良好交互体验。

原创文章,作者:小蓝,如若转载,请注明出处:https://www.506064.com/n/285441.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
小蓝小蓝
上一篇 2024-12-22 15:44
下一篇 2024-12-22 15:44

相关推荐

  • Java任务下发回滚系统的设计与实现

    本文将介绍一个Java任务下发回滚系统的设计与实现。该系统可以用于执行复杂的任务,包括可回滚的任务,及时恢复任务失败前的状态。系统使用Java语言进行开发,可以支持多种类型的任务。…

    编程 2025-04-29
  • 如何实现图像粘贴到蒙版

    本文将从多个方面介绍图像粘贴到蒙版的实现方法。 一、创建蒙版 首先,在HTML中创建一个蒙版元素,用于接收要粘贴的图片。 <div id=”mask” style=”widt…

    编程 2025-04-29
  • RabbitMQ和Yii2的消息队列应用

    本文将探讨RabbitMQ和Yii2之间的消息队列应用。从概念、安装和配置、使用实例等多个方面详细讲解,帮助读者了解和掌握RabbitMQ和Yii2的消息队列应用。 一、Rabbi…

    编程 2025-04-29
  • Saturn 定时任务用法介绍

    本文将从以下几个方面对Saturn定时任务进行详细的阐述: 一、Saturn 定时任务简介 Saturn是一个分布式任务调度系统,支持在线添加、修改定时任务,支持多种任务类型,如J…

    编程 2025-04-29
  • Django ORM如何实现或的条件查询

    在我们使用Django进行数据库操作的时候,查询条件往往不止一个,一个好的查询语句需要考虑我们的查询要求以及业务场景。在实际工作中,我们经常需要使用或的条件进行查询,本文将详细介绍…

    编程 2025-04-29
  • Python一次性输入10个数如何实现?

    Python提供了多种方法进行输入,可以手动逐个输入,也可以一次性输入多个数。在需要输入大量数据时,一次性输入十个数就非常方便。下面我们从多个方面来讲解如何一次性输入10个数。 一…

    编程 2025-04-28
  • ROS线程发布消息异常解决方法

    针对ROS线程发布消息异常问题,我们可以从以下几个方面进行分析和解决。 一、检查ROS代码是否正确 首先,我们需要检查ROS代码是否正确。可能会出现的问题包括: 是否正确初始化RO…

    编程 2025-04-28
  • 使用Python发送微信消息给别人

    问题:如何使用Python发送微信消息给别人? 一、配置微信开发者平台 首先,要想发送微信消息,需要在微信开发者平台中进行配置,来获取对应的授权信息。具体步骤如下: 1、登录微信公…

    编程 2025-04-28
  • 如何在dolphinscheduler中运行chunjun任务实例

    本文将从多个方面对dolphinscheduler运行chunjun任务实例进行详细的阐述,包括准备工作、chunjun任务配置、运行结果等方面。 一、准备工作 在运行chunju…

    编程 2025-04-28
  • Android ViewPager和ScrollView滑动冲突问题

    Android开发中,ViewPager和ScrollView是两个常用的控件。但是当它们同时使用时,可能会发生滑动冲突的问题。本文将从多个方面介绍解决Android ViewPa…

    编程 2025-04-28

发表回复

登录后才能评论