【问题标题】:get main thread's message queue and handler获取主线程的消息队列和处理程序
【发布时间】:2011-09-27 09:03:36
【问题描述】:

如何从另一个线程获取主线程的消息队列? Looper.getMainLooper() 获取主线程的looper,但我无法找到为另一个线程的looper 获取MessageQueue 的方法。此外,我如何获得主循环器的处理程序?我找不到任何方法来获得它。

【问题讨论】:

  • 为什么?你不应该直接搞乱队列。
  • 我只是想添加一个idleHandler来检查主线程是否在做某事
  • @CommonsWare 我想检查主线程的消息队列是否为空。我是这些概念的新手,正在考虑使用 idleHandler 在队列变空时获得通知。
  • “我想检查一下主线程的消息队列是否为空”——为什么?您要解决的业务问题是什么?如果您“不熟悉这些概念”,恕我直言,您不应该进入消息队列的 10 公里范围内。因此,我正在尝试确定您希望通过这种方法实现什么,希望我能为您找到更好、更简单的解决方案。
  • 然后让主线程注册IdleHandler并通过某种监听机制通知其他方。我看不到需要其他线程来执行此操作。 “对于所有这一切,我确实必须在 Android 框架的某个地方进行更改”——这可能是相当多的更改。

标签: android message-queue handler looper


【解决方案1】:

@r.v,

我也有类似的需求。我想知道 MessageQueue 什么时候是空的,什么时候我发布了一些事情让它做,我想知道它什么时候变空而无事可做。我查看了MessageQueue.IdleHandler,发现它的行为不像我想要的那样我想出了另一个解决方案。

就我而言,我想使用 Looper/Handler 机制来顺序执行文件下载。基本上,我要执行的每个下载都包含在 Runnable 中。我一次只希望运行一个,因此这种模式运行良好,无需深入研究更复杂的螺纹解决方案的具体细节。此外,我想知道我什么时候第一次将某些东西放入队列并开始工作,并想知道它什么时候完全完成(队列为空)。

我能够使用处理程序的消息机制来实现这一点。消息与 Runnables 一起按顺序处理,因此您可以策略性地将消息放入队列中,以帮助您了解队列的情况。与 Handler 队列中的 Runnables 不同,最终提供解决方案的消息有一些查询和删除功能。

我所做的是每次向 Handler 添加一个 runnable(通过 Handler.post),我还会删除自定义 QUEUE_EMPTY 消息的所有实例,然后添加一个新的 QUEUE_EMPTY 消息。这确保了我在队列末尾有一条QUEUE_EMPTY 消息。一旦我在子类处理程序中遇到QUEUE_EMPTY 消息,我就知道我在队列的末尾。另外,如果我去添加一个runnable时在队列中没有找到QUEUE_EMPTY消息,我就知道队列是空的,线程是空闲的。

正如一些人会很快指出的那样,这种解决方案确实存在一些效率低下的问题。如果队列中有大量条目,则必须遍历队列以获取这些“标记”消息可能是一个真正的性能问题。就我而言,我一次只处理少量文件下载,因此任何性能损失都可以忽略不计。如果您有类似的情况,我认为这是一个非常合理的解决方案。如果 Android SDK 能够为MessageQueue 提供这些基本功能,那就太好了。我同意理想情况下您不想弄乱 MessageQueue,但是知道它何时空闲/工作/空似乎是合理的事情,我相信有很多情况下知道这些事情是有价值的。

    class DownloaderThread extends Thread
{
    private static final int QUEUE_EMPTY = 9999;
    private MyHandler handler;

    @Override
    public void run()
    {
        try
        {
            Looper.prepare();
            handler = new MyHandler();
            Looper.loop();
        }
        catch (Throwable t)
        {
            Log.e(TAG, "halted due to an error", t);
        }
    }

    public void post(Runnable r)
    {
        if(!handler.hasMessages(QUEUE_EMPTY))
        {
            Log.v(TAG, "Download queue was empty.  First element being added.");
        }

        handler.post(r);
        handler.removeMessages(QUEUE_EMPTY);
        handler.sendEmptyMessage(QUEUE_EMPTY);
    }

    class MyHandler extends Handler
    {
        @Override
        public void handleMessage(Message msg)
        {
            if(msg.what == QUEUE_EMPTY)
            {
                Log.v(TAG, "Download runnable queue is empty!");
            }
        }
    }
};

【讨论】:

    【解决方案2】:

    获得主线程looper后,应该只需要调用myQueue即可获得主线程MessageQueue。

    http://developer.android.com/reference/android/os/Looper.html#myQueue%28%29

    【讨论】:

    • 文档说它返回当前线程的 MessageQueue,我想在与主线程不同的线程上获取它。
    • 对不起,我误读了这个问题。 MessageQueue 是一个内部结构,我不确定 Android 是否允许您直接从线程外部访问它。得到消息队列后,你想用主线程的处理程序和循环器无法完成的事情来做什么?
    • 我想添加一个 idleHandler 来检查主线程是否没有做任何事情。顺便说一句,我还需要主线程的处理程序 - 我已经为此编辑了我的问题。
    • 请参阅上面的@CommonsWare 的 cmets。
    【解决方案3】:

    使用 Handler 类与 Looper 的消息队列进行交互。

    要与 线程的消息队列交互,

    Handler mainHandler = new Handler(Looper.getMainLooper(), new Callback() {
    
            @Override
            public boolean handleMessage(Message msg) {
                // TODO Auto-generated method stub
                return false;
            }
        });
    mainHandler.post(...);
    mainHandler.sendMessage(...);
    mainHandler.removeMessage(...);
    

    现在您可以发送、删除和接收消息了。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-12-05
      • 1970-01-01
      • 2019-01-15
      • 1970-01-01
      • 2018-07-13
      • 1970-01-01
      • 2012-12-05
      相关资源
      最近更新 更多