Как установить связь между службой обмена сообщениями Firebase и активностью? Android
Я знаю, что на вопрос о том, как общаться между службой и деятельностью, ответили много раз, но я также хочу, чтобы мой собственный способ сделать это, чтобы его пересмотреть, и знать, является ли его приемлемым и правильным способом сделать это и каковы недостатки того, как я справился с этим. Во-первых, я сформулирую выражение о проблеме как можно подробнее.
Мне нужно создать приложение, в котором я использую службу сообщений Firebase для обмена данными между двумя устройствами. Скажем, его похожая на Убер система. Одно приложение предназначено для поставщика услуг (водителя) и для клиента (пассажира). Когда пассажир просит путешествовать с их местоположением, водители в определенном радиусе получат push-уведомление с полезной нагрузкой с использованием Firebase. Служба Firebase работает в фоновом режиме. Когда служба получает push-уведомление, onMessageReceived
метод onMessageReceived
. Генерируется событие. Я не использую Firebase здесь для уведомлений, но на самом деле передач данных между устройствами, когда мне нужно, используя data
поля Firebase нажимного уведомления. Теперь приложение-драйвер получит координаты того, где пользователь хочет, чтобы автомобиль находился в полезной нагрузке Push-уведомления Firebase. Я могу просто начать работу с этими данными в дополнительных функциях и показать драйверу, что запрос получен.
Теперь со стороны клиента после того, как клиент отправляет запрос, они переходят к следующему действию, где им показывают вид экрана загрузки, который говорит им ждать, пока один из драйверов примет их запрос. Когда один из драйверов принимает этот пользовательский запрос, этот пользователь теперь получит уведомление Push-Firebase с информацией о назначенных драйверах в полезной нагрузке push-уведомления. Опять же, целью является не генерировать никаких уведомлений, а передавать данные между устройствами.
Теперь, когда вы понимаете прецедент, я перейду к проблеме.
Проблема возникает, когда пользователь отправляет запрос и переходит к следующему экрану ожидания, на котором показан экран загрузки, который говорит им ждать, пока запрос ожидает, чтобы его принял один из драйверов. Когда водитель принимает запрос, как я сказал, пользователь получит уведомление Push-Firebase с информацией о драйвере в полезной нагрузке push-уведомления. Как мне установить связь между сервисом и активностью, чтобы сообщить активности прекратить показ экрана загрузки и заполнить TextView данными, полученными в полезной нагрузке push-уведомления.
Вот как я справился с этим. Предположим, что у меня есть активность с именем AwaitingDriver
, которое TextView заполняется данными драйвера. Но в настоящее время активность показывает экран загрузки, потому что запрос еще не принят. Теперь пользователь получает push-уведомление с информацией о драйвере в службе, работающей в фоновом режиме, и никак не связан с ней. Вот мой метод 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
. Внутри самой активности 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();
}
}
Здесь staticActivity
является статическим объектом класса активности AwaitingDriver
объявленного внутри этого класса. Я устанавливаю его значение в onResume
и onPause
. Значение, если активность находится впереди, показывая на экране, только тогда значение 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
- это AsyncTask, определенная внутри класса активности AwaitingDriver
. Вот код для 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);
}
}
Просмотрите этот код и расскажите мне о недостатках этого, а не о других решениях, и если бы вы также могли объяснить предлагаемый способ в том же примере, я был бы очень благодарен.
Ответы
Ответ 1
Почему вы используете 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);
}
}
и в вашей деятельности
@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"));
}
};
Ответ 2
В методе onMessageReceived вы можете отправить широковещательную передачу приложения, передав данные драйвера. Принятый метод запроса затем будет заменен приемником широковещательного вещания по методу Rеceive. Таким образом, нет необходимости писать в общие настройки или использовать aSyncTask, который в основном ничего не делает, поскольку метод doinbackground просто возвращает null. Вы используете только методы onPreExecute и onPostExecute, которые выполняются в основном потоке.
Ответ 3
Используйте Eventbus для обмена информацией. Это лучше.
Просто выделите событие из функции onMessageReceived()
Eventbus.getDefault().post(Throw(value))
Создайте модель события для вашего мероприятия. Каждая модель событий должна быть уникальной.
class Throw(val value :Object) {}
Затем в вашей деятельности просто зарегистрируйте нужную функцию с вашей моделью событий. Он будет получать, когда вы запускаете событие. Его легко реализовать и более понятно.
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)
Ответ 4
Почему бы вам просто не создать намерение в методе onMessageReceived, перезапустить действие и передать данные драйвера в дополнительных?
Ответ 5
Василис Паллас, спасибо тебе! Работает правильно