6

Wiem, że pytanie o sposób komunikacji między usługą a działaniem zostało wielokrotnie potwierdzone, ale chcę również, aby mój własny sposób sprawdzania tego był sprawdzany i wiedzieć, czy jest to akceptowalny i właściwy sposób, aby to zrobić i jakie są wady tego, jak sobie z tym poradziłem. Najpierw opiszę stwierdzenie problemu tak szczegółowo, jak tylko mogę.Jak komunikować się między usługą przesyłania wiadomości Firebase a działaniem? Android

Muszę zbudować aplikację, w której używam usługi przesyłania komunikatów Firebase do komunikacji między dwoma urządzeniami. Powiedzmy, że jest to system podobny do Ubera. Jedna aplikacja jest dla usługodawcy (sterownik) i jedna dla klienta (pasażera). Kiedy pasażer zażąda podróży ze swoją lokalizacją, kierowcy w określonym promieniu otrzymają powiadomienie push z ładunkiem za pomocą Firebase. Usługa Firebase działa w tle. Gdy usługa otrzymuje powiadomienie push, wywoływana jest metoda onMessageReceived. Wydarzenie jest generowane. Nie używam tutaj Firebase do generowania powiadomień, ale w rzeczywistości przesyłam dane między urządzeniami, gdy potrzebuję skorzystać z pola powiadomień wypychania Firebase. Teraz aplikacja sterowników otrzyma współrzędne miejsca, w którym użytkownik chce, aby samochód znajdował się w ładowności powiadomienia wypychania Firebase. Mogę po prostu rozpocząć działanie z tymi danymi w dodatkach i pokazać sterownikowi, że odebrano żądanie.

Teraz po stronie klienta, po tym jak klient przesyła wniosek, przechodzi do następnej czynności, w której wyświetla się rodzaj ekranu ładowania, w którym oczekuje, że jeden z kierowców zaakceptuje ich prośbę. Gdy jeden z sterowników zaakceptuje żądanie tego użytkownika, ten użytkownik otrzyma powiadomienie push z Firebase z informacjami o wyznaczonym kierowcy w ładunku powiadomienia wypychania. Ponownie celem nie jest generowanie żadnych powiadomień, ale przesyłanie danych między urządzeniami.

Teraz, gdy zrozumiesz przypadek użycia, przejdę do problemu.

Problem pojawia się, gdy użytkownik przesyła żądanie i przechodzi do następnego ekranu oczekiwania, na którym jest wyświetlany ekran ładowania, nakazujący mu czekać, gdy żądanie oczekuje na przyjęcie przez jednego z kierowców. Kiedy kierowca zaakceptuje żądanie, jak już powiedziałem, użytkownik otrzyma powiadomienie push od Firebase z informacjami o kierowcy w ładunku powiadomienia wypychania. W jaki sposób mogę komunikować się między usługą a działaniem, aby powiadomić aktywność, aby przestała wyświetlać ekran ładowania i wypełniła pola tekstowe danymi odebranymi w treści powiadomienia wypychania.

Oto, jak sobie z tym poradziłem. Załóżmy, że mam działanie o nazwie AwaitingDriver, które ma tekstView do wypełnienia danymi kierowcy. Ale obecnie działanie pokazuje ekran ładowania, ponieważ żądanie nie zostało jeszcze zaakceptowane. Teraz użytkownik otrzymuje powiadomienie push z informacjami o sterowniku w usłudze działającej w tle, bez połączenia z działaniem w żaden sposób. Oto moja metoda 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 
     }    
    } 

tutaj, AwaitingDriver.requestAccepted() jest statyczną metodą AwaitingDriver działalności. Wewnątrz samej aktywności AwaitingDriver, która pokazuje okno dialogowe postępu informujące klienta o konieczności oczekiwania, oto, co robi metoda 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(); 
    } 
} 

Tutaj staticActivity jest statycznym obiektem AwaitingDriver klasy działalności zadeklarowanej wewnątrz tej klasy. Ustalam jego wartość w metodach onResume i . Znaczenie, jeśli aktywność jest z przodu, pokazując na ekranie, tylko wtedy wartość staticActivity nie będzie null. Oto metody onResume i .

@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; 
} 

Tutaj TaskFindSetValues jest AsyncTask zdefiniowane wewnątrz AwaitingDriver klasy aktywności. Oto kod dla 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); 
    } 
} 

Przejrzyj ten kod i powiedz mi o wad w ten sposób zamiast innych rozwiązań, jeśli można również wyjaśnić sugerowany sposób z tym samym przykład byłbym naprawdę wdzięczny .

Odpowiedz

18

Dlaczego używasz AsyncTask? Nie ma sensu. W każdym razie, jeśli chcesz komunikować się z Aktywnością, możesz to zrobić za pomocą 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); 
    } 
} 

aw swojej działalności

@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")); 
     } 
    }; 
+0

jaka jest potrzeba wyrejestrowania? Aka, co się stanie, jeśli nie wyrejestrujesz się? –

+0

Moja metoda onCreate w FirebaseMessagingService nigdy nie jest wywoływana. Każdy pomysł, dlaczego? – eskalera

+0

zastąpiłeś metodę 'onCreate'? I sprawdź czy masz literówkę, nazwa metody to 'onCreate()', a nie 'OnCreate()' –

2

W metodzie onMessageReceived można wysłać transmisję aplikacji, przesyłając szczegóły sterownika. Metoda zaakceptowana przez żądanie zostanie następnie zastąpiona przez metodę odbiornika odbiorczego onReceive. W ten sposób nie trzeba pisać do wspólnych preferencji ani używać funkcji aSyncTask, która w zasadzie nic nie robi, ponieważ metoda doinbackground zwraca tylko wartość null. Używasz tylko metod onPreExecute i onPostExecute, które są wykonywane w głównym wątku.

+0

użyłem AsyncTask bo nie może uzyskać dostępu do zmiennych składowych aktywności i TextView za pomocą metody statycznej 'requestAccepted()' ale mogę przez AsyncTask wykonany z metoda statyczna –

0

Dlaczego po prostu nie utworzysz intencji w metodzie onMessageReceived, nie uruchomisz ponownie działania i nie przekażesz danych kierowcy w dodatkach?

+0

Ponieważ nie chcę, aby klient widział ponowne uruchamianie działania. W przypadku użycia klient czeka na ekran ładowania. –

+0

OK, to ma sens. – Cuculus