2016-01-27 21 views
7

Sono nuovo in Android e Retrofit e sto affrontando un problema.Come separare la logica dell'applicazione dal livello di rete in Android utilizzando Retrofit 2

Voglio avere la mia voce "ServerCommunication" (singelton) in cui tutta la magia di Retrofit è stata eseguita e avrà metodi pubblici in cui le chiamate REST sono fatte.

Desidero utilizzare questa istanza "ServerCommunication" nelle mie attività per chiamare il servizio Rest, ma è così. La logica dell'applicazione dovrebbe essere eseguita nell'attività. In questo modo, alcune attività Login chiama il metodo Login (POJORequest) in "ServerCommunication" dove viene eseguita l'effettiva chiamata REST tramite Retrofit framework e viene restituita POJOResponse. Quindi Activity non si cura della comunicazione REST mentre ServerCommunication non si cura della logica che Da

Con il retrofit 2 non capisco come posso bloccare l'attività in attesa di una risposta da retrofit e come può essere restituita. Beh, potrei pensare di poter usare alcuni metodi di callback in attività, tali metodi possono essere richiamati da ServerCommunication "in OnPostExecute() per applicare una logica basata sui dati della risposta. Penso che dovrebbe essere un approccio più semplice.

Bene, per chiarire tutto questo pasticcio sopra, immagina un caso semplice: hai dati nella tua attività principale, passi questi dati alla tua classe di comunicazione dove la chiamata REST è fatta e la risposta è ricevuta. Questa risposta deve essere convalidata per continuare. E tu vuoi che questa convalida sia fatta nell'attività principale e NON nella classe di comunicazione.

Qual è lo schema per farlo in Android con Retrofit2?

Grazie in anticipo

risposta

6

Quello che faccio normalmente:

  • Crea il tuo Interface (dove avete tutti i vostri metodi REST - GET & POST ecc)
  • Creare una classe che fa l'attuale chiama con i metodi corrispondenti (fare riferimento ai metodi REST dell'interfaccia). Lo chiamerei qualcosa come ServiceAPIImplementor. Questo è dove si crea effettivamente il tuo adattatore Retrofit.
  • Nella propria attività, creare un'istanza della classe implementor e chiamare i metodi e passare gli argomenti previsti.
  • Dopo aver chiamato i metodi, probabilmente dovresti mostrare una finestra di avanzamento per far sapere all'utente che qualcosa sta succedendo.
  • Quando il metodo onResponse o onFailure si chiama, utilizzare un modello di evento (biblioteca EventBus?) Per notificare l'attività che il funzionamento della rete è stata completata. Una volta che l'attività ha ricevuto la notifica, deve quindi chiudere la finestra di dialogo di avanzamento e aggiornare l'interfaccia utente di conseguenza, con i dati appena ricevuti o l'operazione completata (risultato previsto).

Spero che questo ti aiuti ad avvicinarti a quello che stai cercando di ottenere!

+0

Grazie per la tua risposta. Bene, EventBus ha fatto il trucco, ma sento ancora che è più simile al workaround. Devo ancora includere onEventMainThread() all'attività in cui ricevo la risposta da ServiceAPIImplementor (o qualsiasi altra cosa lo accludiamo) e l'interfaccia utente in realtà non è bloccata anche se la nascondiamo dietro una finestra di dialogo di avanzamento o semplicemente disabilitiamo i controlli. Vorrei evitare di aggiungere ulteriori pattern di pattern Event quando tutto quello che voglio fare è avere il metodo SomeResponse callRestService (SomeRequest req) in ServiceAPIImplementor – Tony

+0

e semplicemente avere una sua istanza in attività e fare qualcosa come SomeResponse resp = serv.callRestService (req) ; Retrofit 2 ha la possibilità di configurare la connessione e altri timeout, quindi bloccare l'interfaccia utente non è il problema. Quindi immagino che la soluzione migliore sarebbe se posso scegliere quando voglio effettuare chiamate REST dal thread dell'interfaccia utente e quando da sfondo. – Tony

+0

Tuttavia, se non è possibile, mi attenersi alla soluzione EventBus, ma ho una domanda. C'è qualche vantaggio nell'usare EventBus sulla soluzione quando implego semplicemente il metodo di callback in attività e lo richiamo dai metodi onResponse o onFailure in ServiceAPIImplementor? – Tony

0

Interfaccia di servizio (IPhotoService):

@GET("/photos/kudos") 
Call<String> fetchKudos(@Header("Authorization") String authorization, 
         @Query("offset") int offset, @Query("mt") boolean mt); 

impl Service (PHOTOSERVICE):

private GoApiProvider<IPhotoService> mGoProvider = new GoApiProvider<>(); 

public Promiser<List<Photo>, HttpError> fetchKudos() { 
    return new Promiser<>((resolve, reject) -> 
      mGoProvider.getService(IPhotoService.class).fetchKudos(mSession.getToken(), 
        mOffsetKudos, true).enqueue(new Callback<String>() { 
       @Override 
       public void onResponse(Call<String> call, Response<String> response) { 
        if (response.isSuccessful()) { 
         PhotoParser JSON = new PhotoParser(); 
         try { 
          mOffsetKudos = mOffsetKudos + 20; 
          resolve.run(JSON.photosFromJson(response.body())); 
         } catch (JSONException e) { 
          Log.e("fetchKudos", e.toString()); 
         } 
        } else { 
         reject.run(new HttpError(response.code(), response.message())); 
        } 
       } 

       @Override 
       public void onFailure(Call<String> call, Throwable t) { 
        reject.run(new HttpError(YPErrorType.Undefined.getType(), t.getMessage())); 
       } 
      }) 
    ); 
} 

Attività o Frammento:

private void loadPhoto() { 
    new PhotoService().fetchKudos() 
      .success(this::resultSucceeded) 
      .error(this::resultError); 
} 

private void resultSucceeded(List<Photo> photos) { 
    mPhotoAdapter.setItems(photos); 
} 

private void resultError(HttpError httpError) { 
    httpErrorToast(httpError); 
} 

Se si desidera utilizzare Promizer: Click here