如何通过Handler与绑定服务进行通信?

时间:2012-06-18 17:12:36

标签: android android-service android-handler android-binder

我目前正在通过我的应用使用的插件与外部服务进行通信。

绑定服务最终会启动一个活动,然后通知主应用程序活动已完成。

问题是,本地广播通知服务。我已将Messenger msg.replyTo存储到变量中,因此我可以在Handler完成后访问它,但服务仍然受限制。

它确实有效,但我想完全确定没有NullPointer可能,所以我不太喜欢这种方法。

是否有更好的方式与Binder通信,而不是将Messenger存储在变量中?

以下是一些可以更好理解的代码:

private BroadcastReceiver mMessageReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            try {
                if (intent.getAction().equals("activity_closed") && mReplyMessenger != null) {

                mReplyMessenger.send(Message.obtain(null, MSG_RESULT_ACTIVITY_FINISHED));

            }
        } catch (RemoteException e) {
            e.printStackTrace();
        }
};



class IncomingHandler extends Handler {
    @Override
    public void handleMessage(Message msg) {
        mReplyMessenger = null;
        try {
            switch (msg.what) {
            case MSG_START_ACTIVITY: {
                mReplyMessenger = msg.replyTo;

[...]

                BridgeBinder.this.startActivity(i);
                break;
            }
[...]

            default:
                super.handleMessage(msg);
            }
        } catch (RemoteException e) {
            e.printStackTrace();
        }
    }
}

final Messenger mMessenger = new Messenger(new IncomingHandler());

@Override
public IBinder onBind(Intent arg0) {
    return mMessenger.getBinder();
}

2 个答案:

答案 0 :(得分:0)

我以同样的方式实现双向Messenger。我真的没有看到你的Handler在你的Activity中得到陈旧的引用(因此也就是NPE),但如果你想要格外谨慎,你可以尝试每次在onResume()方法中更新引用,甚至每次都是你收到一条消息。

答案 1 :(得分:0)

如果需要我的课程:

MessageManager.java

import android.os.Bundle;
import android.os.IBinder;
import android.os.Message;
import android.os.Messenger;
import android.os.RemoteException;

import com.ubikinformatica.it.lib.commons.modules.log.EMaxLogger;

import java.util.ArrayList;
import java.util.List;

public class MessageManager {

    public interface IOnHandleMessage{
        // Message Whats
        int MSG_HANDSHAKE = 0x1;

        void onHandleMessage(Message msg);
    }

    private static final String TAG = MessageManager.class.getSimpleName();

    private Messenger mMsgSender;
    private Messenger mMsgReceiver;
    private List<Message> mMessages;

    public MessageManager(IOnHandleMessage callback, IBinder target){
        mMsgReceiver = new Messenger(new MessageHandler(this, callback, MessageHandler.TYPE_ACTIVITY));
        mMsgSender = new Messenger(target);
        mMessages = new ArrayList<>();
    }

    public MessageManager(IOnHandleMessage callback){
        mMsgReceiver = new Messenger(new MessageHandler(this, callback, MessageHandler.TYPE_SERVICE));
        mMsgSender = null;
        mMessages = new ArrayList<>();
    }

    /** Getter & Setter Methods **/
    public Messenger getMsgSender() {
        return mMsgSender;
    }

    public void setMsgSender(Messenger sender) {
        this.mMsgSender = sender;
    }

    public Messenger getMsgReceiver() {
        return mMsgReceiver;
    }

    public void setMsgReceiver(Messenger receiver) {
        this.mMsgReceiver = receiver;
    }

    public List<Message> getLastMessages() {
        return mMessages;
    }

    public void addMessage(Message message) {
        this.mMessages.add(message);
    }

    /** Public Methods **/
    public void sendMessage(int what, int arg1, int arg2, Bundle msgData){
        if(mMsgSender != null && mMsgReceiver != null) {
            try {
                Message msg = Message.obtain(null, what, arg1, arg2);
                msg.replyTo = mMsgReceiver;
                if(msgData != null){
                    msg.setData(msgData);
                }
                mMsgSender.send(msg);
            } catch (RemoteException rE) {
                EMaxLogger.onException(TAG, rE);
            }
        }
    }

    public void sendHandshake(){
        if(mMsgSender != null && mMsgReceiver != null){
            sendMessage(IOnHandleMessage.MSG_HANDSHAKE, 0, 0, null);
        }
    }

}

MessageHandler.java

    import android.os.Handler;
import android.os.Message;

public class MessageHandler extends Handler {

    // Types
    final static int TYPE_SERVICE = 0x1;
    final static int TYPE_ACTIVITY = 0x2;

    private MessageManager mMessageManager;
    private MessageManager.IOnHandleMessage mCallback;
    private int mType;

    public MessageHandler(MessageManager msgManager, MessageManager.IOnHandleMessage callback, int type){
        this.mMessageManager = msgManager;
        this.mCallback = callback;
        this.mType = type;
    }

    /** Override Handler Methods **/
    @Override
    public void handleMessage(Message msg){
        this.mMessageManager.addMessage(msg);
        switch(msg.what){
            case MessageManager.IOnHandleMessage.MSG_HANDSHAKE:
                switch(mType){
                    case TYPE_SERVICE:
                        this.mMessageManager.setMsgSender(msg.replyTo);
                        this.mMessageManager.sendHandshake();
                        break;
                    case TYPE_ACTIVITY:
                        break;
                }
                break;
            default:
                if(mCallback != null){
                    mCallback.onHandleMessage(msg);
                }
                break;
        }
    }

}

此处的我的帖子中的更多信息:CHECK MY POST HERE

实际上,新的JobService和JobIntentService存在一些问题,因为它们不能返回除JobScheduler IBinder引擎之外的另一个IBinder,但是我现在想解决它们:D

希望这很有帮助,编码不错:D 再见

[重要编辑于:02/05/2019-10:57]

确定问题解决了,您可以将Messenger放在一个包裹中,然后通过意图将其发送到服务中。 因此,通过这种方式,在JobIntentService中,“ onBind”方法将返回JobScheduler IBinder引擎,并且您可以在意图内获得Messenger的活页夹!

因此,您仅通过回调在活动中初始化MessageManager,然后通过“ enqueueWork”启动服务,并有意将MessengerReceiver放入该服务。在JobIntentService内部,可以通过在Messenger的“ onBind”和“ onHandleWork”方法中使用Messenger的“ getBinder()”方法来获取IBinder,从而初始化MessageManager。 当您拥有活动的MessengerReceiver的IBinder时,可以使用构造函数“回调+活页夹”来初始化MessageManager。 然后在“服务”中发送“握手”,在活动中他将设置“发件人”。

要执行此操作:

您必须更改MessageHandler的“ handleMessage”替代方法: 现在的方法是这样:

@Override
    public void handleMessage(Message msg){
        this.mMessageManager.addMessage(msg);
        switch(msg.what){
            case MessageManager.IOnHandleMessage.MSG_HANDSHAKE:
                switch(mType){
                    case TYPE_SERVICE:
                        this.mMessageManager.setMsgSender(msg.replyTo);
                        this.mMessageManager.sendHandshake();
                        break;
                    case TYPE_ACTIVITY:
                        break;
                }
                break;
            default:
                if(mCallback != null){
                    mCallback.onHandleMessage(msg);
                }
                break;
        }
    }

您需要删除类型,因为您不再需要它。 因此,在获取和握手时,在类“ MessageHandler”内的“ handleMessage”方法的切换中,您必须执行以下操作:

    [...]
case MessageManager.IOnHandleMessage.MSG_HANDSHAKE:
    if(this.mMessageManager.getMsgSender() == null){
        this.mMessageManager.setMsgSender(msg.replyTo);
        this.mMessageManager.sendHandshake();
    }
    [...]

这样可以解决JobIntentService的问题;) 希望这对您有所帮助! 编码不错<3