开发者

Android: how to take over message loop of Activity, like GetMessage/PostMessage in Win32?

开发者 https://www.devze.com 2023-03-09 04:30 出处:网络
My original goal is to build my own modal dialog. At some point, I have to run an inner loop, which would do really close to what GetMessage/PostMessage do in Win32, if you got Win32 experience then y

My original goal is to build my own modal dialog. At some point, I have to run an inner loop, which would do really close to what GetMessage/PostMessage do in Win32, if you got Win32 experience then you are quite familiar with this. The inner loop will block current workflow but still process events. The pseudo code would be like,

private void doModal() {

    doSth();

    // start loop and process events
    while (!isQuit) {
        Message msg = nextMessage();

        // process all wanted msgs, and simply discard all unexpected msgs
        if (isWantedMsg) {
            sendToTarget(msg);
        }
    }
}

I've looked into source code, Looper.loop(), which was,

public static final void loop() {
    Looper me = myLooper();
    MessageQueue queue = me.mQueue;
    while (true) {
        Message msg = queue.next(); // might block
        if (msg != null) {
            if (msg.target == null) {
                // No target is a magic identifier for the quit message.
                return;
            }
            msg.target.dispatchMessage(msg);
            msg.recycle();
        }
    }
}

Basically I'd like to write such a loop, then I'm able to receive all msgs and process or drop them accordingly. Unfortunately, MessageQueue belongs to package android.os, I have no privilege to access most of its interfaces. Activity.dispatchTouchEvent is just a handler, not my case.

How could I do? Thanks.

==========================SOLUTION=====================================

I solved it by reflection, I exactly copied source of Looper.loop(), see below,

private void startModal() {
    Class clsMsgQueue = null;
    Method nextMethod = null;
    Class clsMsg = null;

    mQuitModal = false;

    MessageQueue queue = Looper.myQueue();
    clsMsgQueue = queue.getClass();
    try {
        nextMethod = clsMsgQueue.getDeclaredMethod("next", new Class[]{});
    } catch (SecurityException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (NoSuchMethodException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    nextMethod.setAccessible(true);

    while (!mQuitModal) {

            Message msg = null;
            try {
                msg = (Message)nextMethod.invoke(queue, new Object[]{});
            } catch (IllegalArgumentException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }

            if (msg != null) {
                clsMsg = msg.getClass();
                Field targetFiled = null;
                try {
                    targetFiled = clsMsg.getDeclaredField("target");
                } catch (SecurityException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                } catch (NoSuchFieldException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                targetFiled.setAccessible(true);

                Handler target = null;
                try {
                    target = (Handler) targetFiled.get(msg);
                } catch (IllegalArgumentException e) {
                    // TODO Auto-gen开发者_开发知识库erated catch block
                    e.printStackTrace();
                } catch (IllegalAccessException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }

                if (target == null) {
                    // No target is a magic identifier for the quit message.
                    mQuitModal = true;
                }

                target.dispatchMessage(msg);

                msg.recycle();
            }
        }
    }

When dialog was dismissed, mQuitModal was set to true either.

If don't care much about performance issue, it worked.


Sorry, Android deliberately does not support nested event loops like this. You just will have to structure your code a different way -- for dialogs you will typically start the dialog, return to the event loop, and implement callbacks to handle the result from it.

0

精彩评论

暂无评论...
验证码 换一张
取 消