2015-11-10 10 views
6

Uso Retrofit e Dagger 2. Ho implementato un OkHttp Interceptor per aggiungere il token oauth. Nel caso in cui non vi sia alcun token oauth o il timestamp non è valido, richiedo uno nuovo (tramite il servizio Retrofit) prima che venga eseguita la richiesta effettiva.OkHttp Interceptor che utilizza OkHttpClient senza ciclo di dipendenza

Questo crea un ciclo di dipendenze in cui il servizio Retrofit richiede il Interceptor ma il Interceptor richiede anche il servizio Retrofit (per il recupero del token oauth).

Esempio per il Interceptor (per semplificazione, richiede sempre il token via restService#refreshAccessToken):

@Override 
public Response intercept(Chain chain) throws IOException { 
    Request originalRequest = chain.request(); 
    Request.Builder requestBuilder = originalRequest.newBuilder(); 

    String authHeader = "Bearer " + restService.refreshAccessToken(); 
    requestBuilder.addHeader("Authorization", authHeader); 
    return chain.proceed(requestBuilder.build()); 
} 

risposta

1

tuo Interceptor avrà bisogno di iniettare se stesso nel metodo Interceptor#intercept(). In questo modo il servizio di Retrofit (inclusa la dipendenza OkHttpClient con l'intercettatore aggiunto) può essere soddisfatto senza un ciclo di dipendenze.

Il mio NetworkComponent (che fornisce il mio servizio di retrofit) vive nella mia classe Application. Ecco un esempio di iniezione usando un'applicazione Context.

public class AuthInterceptor implements Interceptor { 

    @Inject RestService restService; 

    public AuthInterceptor(Context context) { 
     mContext = context; 
    } 

    @Override 
    public Response intercept(Chain chain) throws IOException { 
     // Inject Retrofit service 
     ((MyApplication) context.getApplicationContext()) 
       .getNetworkComponent().inject(this); 

     Request originalRequest = chain.request(); 
     Request.Builder requestBuilder = originalRequest.newBuilder(); 

     String authHeader = "Bearer " + restService.refreshAccessToken(); 
     requestBuilder.addHeader("Authorization", authHeader); 
     return chain.proceed(requestBuilder.build()); 
    } 
} 

È anche possibile impostare una variabile locale senza iniettare l'intera classe, ottenendo prestazioni migliori.

RestService restService = InjectHelper.getNetworkComponent(mContext).restService(); 
+1

approccio interessante. C'è un rovescio della medaglia (ad es .: prestazioni) perché ogni richiesta/intercetta causa un'iniezione? Anche l'Applicazione deve esporre il NetworkComponent, che a me sembra un po 'strano. – Maradox

+0

Dagger 2 è costruito per essere veloce perché usa solo il codice generato, quindi essenzialmente chiamerà un metodo che imposta il 'RestService'. Ho aggiunto un modo alternativo che evita di iniettare l'intera classe alla mia risposta. Non deve essere 'Application' che lo fornisce, ma cos'altro fornirebbe i componenti' Singleton' della tua app? Memorizzare i componenti dell'intera applicazione in Applicazione è una pratica comune su tutte le cose di Dagger 2 che ho letto. –

0

Io personalmente preferisco iniezione pigro, che è un po 'più pulito

public class AuthInterceptor implements Interceptor { 

    Lazy<RestService> restService; 

    public AuthInterceptor(Lazy<RestService> restService) { 
     this.restService = restService; 
    } 

    @Override 
    public Response intercept(Chain chain) throws IOException { 
     Request originalRequest = chain.request(); 
     Request.Builder requestBuilder = originalRequest.newBuilder(); 

     String authHeader = "Bearer " + restService.get().refreshAccessToken(); 
     requestBuilder.addHeader("Authorization", authHeader); 
     return chain.proceed(requestBuilder.build()); 
    } 
} 
+0

Wow, è molto pulito! Ha ancora bisogno di un'annotazione '@ Inject'? –

+0

Spetta a voi. No, se scrivi provider –

Problemi correlati