如何在Firebase Messaging Service和Activity之间进行通信?Android的

Reh*_*saf 18 android static-methods android-asynctask firebase android-service-binding

我知道关于如何在服务和活动之间进行通信的问题已被多次回答,但我也希望我自己的方式对此进行审核,并了解它是否是可接受的和正确的方法来执行此操作以及什么是我如何处理它的弊端.首先,我将尽可能详细地陈述问题陈述.

我必须构建一个应用程序,我使用Firebase Messaging Service在两个设备之间进行通信.让我们说它是一个类似Uber的系统.一个应用程序用于服务提供商(驱动程序),一个用于客户(乘客).当乘客请求使用其位置旅行时,某个半径范围内的驾驶员将使用Firebase获得有效负载的推送通知.Firebase服务正在后台运行.当服务收到推送通知时,onMessageReceived将调用方法.生成一个事件.我不是在这里使用Firebase来生成通知,但实际上在我需要使用dataFirebase推送通知字段时在设备之间传输数据.现在,驱动程序应用程序将在Firebase推送通知的有效负载中接收用户想要汽车的坐标.我可以简单地在附加内容中使用此数据启动活动,并向驱动程序显示已收到请求.

现在在客户方面,在客户提交请求之后,他们将被带到下一个活动,在那里他们将被显示一种加载屏幕,告诉他们等待其中一个驱动程序接受他们的请求.当其中一个驱动程序接受此用户的请求时,此用户现在将在推送通知的有效负载中收到带有指定驱动程序信息的Firebase推送通知.同样,目的不是生成任何通知,而是在设备之间传输数据.

既然您了解了用例,我将继续讨论该问题.

当用户提交请求并进入下一个等待屏幕时会出现问题,在该屏幕上显示一个加载屏幕,告诉他们在请求等待其中一个驱动程序接受时等待.当驱动程序接受请求时,正如我所说,用户将在推送通知的有效负载中收到带有驱动程序信息的Firebase推送通知.如何在服务和活动之间进行通信,告诉活动停止显示加载屏幕并使用推送通知的有效负载中接收的数据填充TextView.

这是我如何处理这个.假设我有一个名称的活动AwaitingDriver,其中TextView将由驱动程序的数据填充.但目前活动正在显示加载屏幕,因为该请求尚未被接受.现在,用户收到推送通知,其中包含在后台运行的服务中的驱动程序信息,而不是以任何方式连接到活动.这是我的onMessageReceived方法

    @Override
    public void onMessageReceived(RemoteMessage remoteMessage){
        SharedPreferences rideInfoPref = getSharedPreferences(getString(R.string.rideInfoPref), MODE_PRIVATE);
        SharedPreferences.Editor rideInfoPrefEditor = rideInfoPref.edit();
        String msgType = remoteMessage.getData().get("MessageType");
        if (msgType.equals("RequestAccepted")){                
            rideInfoPrefEditor.putBoolean(getString(R.string.is_request_accepted), true);
            rideInfoPrefEditor.putString(getString(R.string.driver_phone), remoteMessage.getData().get("DriverPhone"));
            rideInfoPrefEditor.putString(getString(R.string.driver_lat), remoteMessage.getData().get("DriverLatitude"));
            rideInfoPrefEditor.putString(getString(R.string.driver_lng), remoteMessage.getData().get("DriverLongitude"));

            rideInfoPrefEditor.commit();
            AwaitingDriver.requestAccepted(); // A static method in AwaitingDriver Activity
        }            
    }
Run Code Online (Sandbox Code Playgroud)

AwaitingDriver.requestAccepted()是一种静态的AwaitingDriver活动方法.在AwaitingDriver活动本身内部,它显示了一个告诉客户等待的进度对话框,这是方法AwaitingDriver.requestAccepted()正在做的事情.

public static void requestAccepted(){
    try{
        awaitingDriverRequesting.dismiss(); //ProgressDialog for telling user to wait
    }catch (Exception e){
        e.printStackTrace();
    }        
    if (staticActivity != null){
        staticActivity.new TaskFindSetValues().execute();
    }
}
Run Code Online (Sandbox Code Playgroud)

staticActivityAwaitingDriver在此类中声明的活动类的静态对象.我正在设定其价值onResumeonPause方法.意思是如果活动在前面,在屏幕上显示,那么它的值staticActivity将不是null.这是onResumeonPause方法.

@Override
public void onResume(){
    super.onResume();
    staticActivity = this;
    Boolean accepted = rideInfoPref.getBoolean(getString(R.string.is_request_accepted), false);
    if (accepted){        
       new TaskFindSetValues().execute();            
    }
}
@Override
protected void onPause(){
    super.onPause();
    staticActivity = null;
}
Run Code Online (Sandbox Code Playgroud)

这里TaskFindSetValues是在AwaitingDriver活动类中定义的AsyncTask .这是代码TaskFindSetValues

public class TaskFindSetValues extends AsyncTask<String, Void, String>{
    String phone;
    String lat;
    String lng;
    @Override
    protected void onPreExecute(){
        SharedPreferences pref = getSharedPreferences(getString(R.string.rideInfoPref), MODE_PRIVATE);            
        phone = pref.getString(getString(R.string.driver_phone), "");
        lat = pref.getString(getString(R.string.driver_lat), "");
        lng = pref.getString(getString(R.string.driver_lng), "");
    }
    @Override
    protected String doInBackground(String... arg0){
        return null;
    }

    @Override
    protected void onPostExecute(String returnValue){            
        awaitingDriverPhone.setText(phone); //setting values to the TextViews
        awaitingDriverLat.setText(lat);
        awaitingDriverLng.setText(lng);
    }
}
Run Code Online (Sandbox Code Playgroud)

请查看此代码并告诉我这样做的缺点而不是其他解决方案,如果您也可以用相同的示例解释建议的方式,我将非常感激.

Vas*_*las 53

你为什么使用AsyncTask?没有意义.无论如何,如果你想与Activity通信,你可以使用它BroadcastReceiver.

public class MyFirebaseMessagingService extends FirebaseMessagingService{
    private LocalBroadcastManager broadcaster;

    @Override
    public void onCreate() {
        broadcaster = LocalBroadcastManager.getInstance(this);
    }

    @Override
    public void onMessageReceived(RemoteMessage remoteMessage) {
        Intent intent = new Intent("MyData");
        intent.putExtra("phone", remoteMessage.getData().get("DriverPhone"));
        intent.putExtra("lat", remoteMessage.getData().get("DriverLatitude"));
        intent.putExtra("lng", remoteMessage.getData().get("DriverLongitude"));
        broadcaster.sendBroadcast(intent);
    }
}
Run Code Online (Sandbox Code Playgroud)

并在您的活动中

 @Override
    protected void onStart() {
        super.onStart();
        LocalBroadcastManager.getInstance(this).registerReceiver((mMessageReceiver),
                new IntentFilter("MyData")
        );
    }

    @Override
    protected void onStop() {
        super.onStop();
        LocalBroadcastManager.getInstance(this).unregisterReceiver(mMessageReceiver);
    }

    private BroadcastReceiver mMessageReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            awaitingDriverRequesting.dismiss();
            awaitingDriverPhone.setText(intent.getExtras().getString("phone")); //setting values to the TextViews
            awaitingDriverLat.setText(intent.getExtras().getDouble("lat"));
            awaitingDriverLng.setText(intent.getExtras().getDouble("lng"));
        }
    };
Run Code Online (Sandbox Code Playgroud)

  • 取消注册需要什么?Aka,如果你不注销会怎么样? (2认同)

Sha*_*aon 5

使用 Eventbus 进行后台通信。这是最好的。

只需从您的 onMessageReceived() 函数调用中抛出一个事件

Eventbus.getDefault().post(Throw(value))
Run Code Online (Sandbox Code Playgroud)

为您的活动创建一个活动模型。每个事件模型都必须是唯一的。

class Throw(val value :Object) {}
Run Code Online (Sandbox Code Playgroud)

然后在您的活动中,只需使用您的事件模型注册所需的功能。它会在您触发事件时收到。它易于实施且更易于理解。

override fun onStart() {
    super.onStart()
    EventBus.getDefault().register(this)
}


override fun onStop() {
    EventBus.getDefault().unregister(this)
    super.onStop()
}

@Subscribe(threadMode = ThreadMode.MAIN)
fun onThrowEvent(t : Throw) {
    // Do your staff here
}
Run Code Online (Sandbox Code Playgroud)

您还可以在后台捕捉您的事件。只需更改线程模式。我会建议你试一试

@Subscribe(threadMode = ThreadMode.ASYNC)
@Subscribe(threadMode = ThreadMode.BACKGROUND)
Run Code Online (Sandbox Code Playgroud)