Java 如何让一个Android类等待另一个类完成它的任务?

Java 如何让一个Android类等待另一个类完成它的任务?,java,android,wait,notify,Java,Android,Wait,Notify,我正在编写一个Android消息传递应用程序,一个类正在调用另一个类,我希望调用的类在继续之前等待被调用方类完成 调用方类(MessageManagement)代码段如下: private static Messenger myMessenger; try { Message msg = Message.obtain(); msg.arg1 = constructedMessage.length(); msg.arg2 = -1; msg.obj = constructedMe

我正在编写一个Android消息传递应用程序,一个类正在调用另一个类,我希望调用的类在继续之前等待被调用方类完成

调用方类(MessageManagement)代码段如下:

private static Messenger myMessenger;

try {
  Message msg = Message.obtain();
  msg.arg1 = constructedMessage.length();
  msg.arg2 = -1;
  msg.obj = constructedMessage;
  Log.d(TAG, "Calling myMessenger.send()");
  myMessenger.send(msg);
  Log.d(TAG, "Sent");
} catch (Exception e) {
  e.printStackTrace();
}
// Wait here until myMessenger completes its task
doOtherStuff();
private Handler smsHandler = new Handler() {
  @Override
  public void handleMessage(Message msg) {
    // do some stuff
  }
};
现在,doOtherStuff()在myMessenger启动之前启动并完成。我需要我的Messenger在doOtherStuff()开始之前完成

我已经读过wait()和notify()的相关内容,但我不确定如何在这里实现它,或者它是否是正确的选择

关于程序流程的一些背景知识。它基本上是我继承的一个消息传递应用程序,所以我不太确定它的框架。从跟踪代码流可以看出:

  • 当收到SMS消息时,SMS receiver BroadcastReceiver(SmsReceiver)将处理该消息,获取发送方地址和消息正文,然后调用SMS处理程序服务(HandleSmsService),该服务随后在runnable中调用caller类,代码如下:
  • 免提服务

    public class HandleSmsService extends Service {
      private String message;
      private MessageManagement messageManager;
      private Handler timeoutHandler = new Handler();
    
      @Override
      public void onStart(Intent intent, intent startid) {
        message = intent.getExtras().getString("message");
        messageManager = new MessageManagement(this);
        timeoutHandler.postDelayed(runnable, 10);
      }
    
      private Runnable runnable = new Runnable() {
        @Override
        public void run() {
          try {
            messageManager.handleMessage(message);
            stopSelf();
          } catch (Exception e) {
            e.printStackTrace();
          }
        }
      };
    
    MessageManagement是我的调用方类,MessageManagement.handleMessage()是前面介绍的最上面的代码段

    MessageManagement.handleMessage()显然在调用myMessenger.send(msg)时调用了被调用方类中的另一个处理程序。此处理程序代码如下所示:

    private static Messenger myMessenger;
    
    try {
      Message msg = Message.obtain();
      msg.arg1 = constructedMessage.length();
      msg.arg2 = -1;
      msg.obj = constructedMessage;
      Log.d(TAG, "Calling myMessenger.send()");
      myMessenger.send(msg);
      Log.d(TAG, "Sent");
    } catch (Exception e) {
      e.printStackTrace();
    }
    // Wait here until myMessenger completes its task
    doOtherStuff();
    
    private Handler smsHandler = new Handler() {
      @Override
      public void handleMessage(Message msg) {
        // do some stuff
      }
    };
    

    我想应该是这样的:

        try {
          Message msg = Message.obtain(handler, new Runnable() {
    
                  @Override
                  public void run() {
                      doOtherStuff();
                  }
            });
          msg.arg1 = constructedMessage.length();
          msg.arg2 = -1;
          msg.obj = constructedMessage;
          Log.d(TAG, "Calling myMessenger.send()");
          msg.sendToTarget();
          Log.d(TAG, "Sent");
        } catch (Exception e) {
          e.printStackTrace();
        }
    
    另一种方法是使用本机方法:

    private static Messenger myMessenger = new Messenger(new Handler(new Handler.Callback() {
    
        @Override
        public boolean handleMessage(Message msg) {
            // do something what you need
            if (msg.getTarget() != null) {
                msg.sendToTarget();
            }
            return false;
        }
    }));
    
    try {
        final Message msg = Message.obtain();
        msg.setTarget(new Handler(new Handler.Callback() {
    
            @Override
            public boolean handleMessage(Message msg) {
                doOtherStuff();
                return false;
            }
        }));
        msg.arg1 = constructedMessage.length();
        msg.arg2 = -1;
        msg.obj = constructedMessage;
        Log.d(TAG, "Calling myMessenger.send()");
        myMessenger.send(msg);
        Log.d(TAG, "Sent");
    } catch (final Exception e) {
        e.printStackTrace();
    }
    

    我假设发布的代码是在主线程上运行的,而使用处理程序的原因是在接收消息时在另一个线程上执行了异步操作。 在这种情况下,不能在线程上使用wait,因为它会锁定UI,并可能导致应用程序不响应错误

    在不改变太多代码的情况下,一种方法是在您的constructedMessage中嵌套一个侦听器,例如

    public class DoStuffRequest {
        private OnFinishListener mOnFinishListener;
        private boolean isCanceled;
        private String mMessage;
        public interface OnFinishListener {
            public void onFinish();
        }
    
        public DoStuffRequest(String message) {
            mMessage = message;
        }        
    
        public OnFinishListener getOnFinishListener() {
            return mOnFinishListener;
        }
    
        public void setOnFinishListener(OnFinishListener onFinishListener) {
            mOnFinishListener = onFinishListener;
        }
    
        public void cancel() {
            isCanceled = true;
        }
    
        public void notifyFinish() {
            if (!isCanceled && mOnFinishListener != null) {
                mOnFinishListener.onFinish();
            }
        }
    
        public String getMessage() {
            return mMessage;
        }
    }
    
    然后沿着这条线使用一些来让球滚动:

    private static Messenger myMessenger;
    private DoStuffRequest mRequest;
    ...
    
    private void send(String message) {
        mRequest = new DoStuffRequest(message);    
        mRequest.setOnFinishListener(new ConstructedMessage.OnFinishListener() {
            @Override
            public void onFinish() {
                doOtherStuff();
            }
        });
        try {
            Message msg = Message.obtain();
            msg.arg1 = constructedMessage.length();
            msg.arg2 = -1;
            msg.obj = constructedMessage;
            Log.d(TAG, "Calling myMessenger.send()");
            myMessenger.send(msg);
            Log.d(TAG, "Sent");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    
    private void doThisIfYouWantToCancel() {
        if (mRequest != null) {
            mRequest.cancel();
        }
    }
    
    异步工作完成后,处理程序/服务代码现在可以调用
    constructedMessage.finish()
    。根据doOtherStuff()的功能(例如,在操作UI时),您可能希望在主线程上执行此操作(我上面编写的代码不是线程安全的,我假设您正在主线程上调用侦听器)。 另外,请记住调用
    constructedMessage.cancel()
    ,以防您不想再收到通知(例如,您将离开活动/片段)


    这只是一种方法,根据您的需要,其他一些方法可能是更好的选择。

    您好,我正在尝试您的第一种方法。对于noob的问题很抱歉,但是我如何声明/初始化Message.get()的处理程序参数?我假设您使用一些
    处理程序来初始化您的
    Messenger
    ,在第一种方法中,我建议使用
    Handler
    来初始化
    Message
    ,而不是
    Messenger
    。myMessenger中的处理程序存在,并且其中实现了handleMessage(),正如我更新的原始帖子所示。但是,这个处理程序似乎是私有的,所以我不能从调用函数访问它?似乎我正在从另一个公共handleMessage()调用私有handleMessage(),并且由于被调用方handleMessage()是私有的,因此调用方不会显式调用它,而是使用myMessenger.send(msg)。不确定我是否正确解释了代码。第二个方法呢?这不是将驻留在被调用方类中的同一handleMessage()代码重新实现到调用方类中吗?我尝试将msg.sendToTarget()放入被调用方类,但这导致了一个致命的异常。constructedMessage实际上只是一个字符串。我已经修改了我原来的问题,以提供代码的更多细节。只需向ConstructedMessage和getter/setter方法添加一个成员即可。它背后的思想是简单地将您想要传递给处理程序的数据包装在一个对象中,该对象包含一个可调用的侦听器和所有您想要添加的额外内容。我还检查了您的服务代码,我不确定您想要实现什么,您能解释一下吗?