如何在 Firebase 消息服务和 Activity 之间进行通信? Android
How to communicate between Firebase Messaging Service and Activity? Android
我知道关于如何在服务和 activity 之间进行通信的问题已经回答了很多次,但我也希望我自己的方法得到审查并知道它是否可以接受并且这样做的正确方法以及我处理它的缺点是什么。首先,我将尽可能详细地陈述问题。
我必须构建一个应用程序,我在其中使用 Firebase 消息服务在两个设备之间进行通信。假设它是一个类似 Uber 的系统。一款应用程序供服务提供商 (driver) 使用,另一款应用程序供客户(乘客)使用。当乘客请求使用他们的位置旅行时,一定半径内的 drivers 将使用 Firebase 收到带有有效负载的推送通知。 Firebase 服务在后台 运行。当服务收到推送通知时,将调用 onMessageReceived
方法。生成一个事件。我在这里没有使用 Firebase 生成通知,而是在需要使用 Firebase 推送通知的 data
字段时实际在设备之间传输数据。现在 drivers 应用程序将在 Firebase 推送通知的负载中接收用户想要汽车的位置的坐标。我可以在 extras 中使用此数据简单地启动 activity 并显示 driver 收到请求。
现在在客户方面,在客户提交请求后,他们将被带到下一个 activity,在那里他们会看到一种加载屏幕,告诉他们等待其中一个 drivers 接受他们的请求。当 driver 之一接受该用户的请求时,该用户现在将收到一个 Firebase 推送通知,在推送通知的有效负载中包含指定的 driver 的信息。同样,目的不是生成任何通知,而是在设备之间传输数据。
既然您了解了用例,我将继续解决问题。
当用户提交请求并转到下一个等待屏幕时会出现问题,在该屏幕上向他显示加载屏幕告诉他们等待,同时请求正在等待 driver秒。当 driver 接受请求时,正如我所说,用户将收到一个 Firebase 推送通知,在推送通知的有效负载中包含 driver 的信息。我如何在服务和 Activity 之间进行通信,以告知 activity 停止显示加载屏幕并使用推送通知有效负载中收到的数据填充 TextView。
我是这样处理的。假设我有一个名为 AwaitingDriver
的 activity,其中包含要由 driver 的数据填充的 TextView。但目前 activity 正在显示加载屏幕,因为请求尚未被接受。现在,用户在后台收到 driver 服务 运行 中的信息推送通知,没有以任何方式连接到 activity。这是我的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
}
}
这里,AwaitingDriver.requestAccepted()
是AwaitingDriver
activity的静态方法。在 AwaitingDriver
activity 本身内部,显示一个进度对话框告诉客户等待,这是方法 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();
}
}
此处 staticActivity
是 AwaitingDriver
activity class 的静态 object 声明在此 class 中。我在 onResume
和 onPause
方法中设置它的值。意思是如果activity在前面,显示在屏幕上,那么staticActivity
的值才不会是null
。这是 onResume
和 onPause
方法。
@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;
}
这里,TaskFindSetValues
是在AwaitingDriver
activityclass里面定义的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);
}
}
请查看此代码并告诉我这样做而不是其他解决方案的缺点,如果您也可以用相同的示例解释建议的方法,我将不胜感激。
在 onMessageReceived 方法中,您可以发送应用内广播,传输驱动程序详细信息。
然后请求接受方法将被广播接收器 onReceive 方法替换。这样就不需要写入共享首选项或使用 aSyncTask ,它基本上什么都不做,因为 doinbackground 方法只是 returns null 。您只使用了 onPreExecute 和 onPostExecute 方法,它们都在主线程上执行。
为什么不直接在 onMessageReceived 方法中创建一个意图,重新启动 activity,并在 extra 中传递驱动程序的数据?
为什么要使用 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);
}
}
在你的 Activity
@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"));
}
};
编辑
根据@xuiqzy LocalBroadcastManager
现已弃用! Google 表示改用 LiveData 或 Reactive Streams。
使用Eventbus 进行后台通信。这是最好的。
只需从您的 onMessageReceived() 函数调用中抛出一个事件
Eventbus.getDefault().post(Throw(value))
为您的活动创建一个活动模型。每个事件模型都必须是唯一的。
class Throw(val value :Object) {}
然后在您的 activity 中将所需的功能注册到您的事件模型中。当你触发一个事件时它会收到。易于实现,更易于理解。
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
}
您还可以在后台观看您的活动。只需更改 ThreadMode。我会建议你试一试
@Subscribe(threadMode = ThreadMode.ASYNC)
@Subscribe(threadMode = ThreadMode.BACKGROUND)
我知道关于如何在服务和 activity 之间进行通信的问题已经回答了很多次,但我也希望我自己的方法得到审查并知道它是否可以接受并且这样做的正确方法以及我处理它的缺点是什么。首先,我将尽可能详细地陈述问题。
我必须构建一个应用程序,我在其中使用 Firebase 消息服务在两个设备之间进行通信。假设它是一个类似 Uber 的系统。一款应用程序供服务提供商 (driver) 使用,另一款应用程序供客户(乘客)使用。当乘客请求使用他们的位置旅行时,一定半径内的 drivers 将使用 Firebase 收到带有有效负载的推送通知。 Firebase 服务在后台 运行。当服务收到推送通知时,将调用 onMessageReceived
方法。生成一个事件。我在这里没有使用 Firebase 生成通知,而是在需要使用 Firebase 推送通知的 data
字段时实际在设备之间传输数据。现在 drivers 应用程序将在 Firebase 推送通知的负载中接收用户想要汽车的位置的坐标。我可以在 extras 中使用此数据简单地启动 activity 并显示 driver 收到请求。
现在在客户方面,在客户提交请求后,他们将被带到下一个 activity,在那里他们会看到一种加载屏幕,告诉他们等待其中一个 drivers 接受他们的请求。当 driver 之一接受该用户的请求时,该用户现在将收到一个 Firebase 推送通知,在推送通知的有效负载中包含指定的 driver 的信息。同样,目的不是生成任何通知,而是在设备之间传输数据。
既然您了解了用例,我将继续解决问题。
当用户提交请求并转到下一个等待屏幕时会出现问题,在该屏幕上向他显示加载屏幕告诉他们等待,同时请求正在等待 driver秒。当 driver 接受请求时,正如我所说,用户将收到一个 Firebase 推送通知,在推送通知的有效负载中包含 driver 的信息。我如何在服务和 Activity 之间进行通信,以告知 activity 停止显示加载屏幕并使用推送通知有效负载中收到的数据填充 TextView。
我是这样处理的。假设我有一个名为 AwaitingDriver
的 activity,其中包含要由 driver 的数据填充的 TextView。但目前 activity 正在显示加载屏幕,因为请求尚未被接受。现在,用户在后台收到 driver 服务 运行 中的信息推送通知,没有以任何方式连接到 activity。这是我的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
}
}
这里,AwaitingDriver.requestAccepted()
是AwaitingDriver
activity的静态方法。在 AwaitingDriver
activity 本身内部,显示一个进度对话框告诉客户等待,这是方法 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();
}
}
此处 staticActivity
是 AwaitingDriver
activity class 的静态 object 声明在此 class 中。我在 onResume
和 onPause
方法中设置它的值。意思是如果activity在前面,显示在屏幕上,那么staticActivity
的值才不会是null
。这是 onResume
和 onPause
方法。
@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;
}
这里,TaskFindSetValues
是在AwaitingDriver
activityclass里面定义的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);
}
}
请查看此代码并告诉我这样做而不是其他解决方案的缺点,如果您也可以用相同的示例解释建议的方法,我将不胜感激。
在 onMessageReceived 方法中,您可以发送应用内广播,传输驱动程序详细信息。 然后请求接受方法将被广播接收器 onReceive 方法替换。这样就不需要写入共享首选项或使用 aSyncTask ,它基本上什么都不做,因为 doinbackground 方法只是 returns null 。您只使用了 onPreExecute 和 onPostExecute 方法,它们都在主线程上执行。
为什么不直接在 onMessageReceived 方法中创建一个意图,重新启动 activity,并在 extra 中传递驱动程序的数据?
为什么要使用 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);
}
}
在你的 Activity
@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"));
}
};
编辑
根据@xuiqzy LocalBroadcastManager
现已弃用! Google 表示改用 LiveData 或 Reactive Streams。
使用Eventbus 进行后台通信。这是最好的。
只需从您的 onMessageReceived() 函数调用中抛出一个事件
Eventbus.getDefault().post(Throw(value))
为您的活动创建一个活动模型。每个事件模型都必须是唯一的。
class Throw(val value :Object) {}
然后在您的 activity 中将所需的功能注册到您的事件模型中。当你触发一个事件时它会收到。易于实现,更易于理解。
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
}
您还可以在后台观看您的活动。只需更改 ThreadMode。我会建议你试一试
@Subscribe(threadMode = ThreadMode.ASYNC)
@Subscribe(threadMode = ThreadMode.BACKGROUND)