2015-11-10 1 views
6

J'utilise Retrofit et Dagger 2. J'ai implémenté un OkHttp Interceptor pour ajouter le jeton oauth. Dans le cas où il n'y a pas de jeton oauth ou si l'horodatage est invalide, j'en demande un nouveau (via le service Retrofit) avant que la demande réelle ne soit effectuée.OkHttp Interceptor utilisant OkHttpClient sans cycle de dépendance

Ceci crée un cycle de dépendances où le service Retrofit nécessite le Interceptor mais le Interceptor nécessite également le service Retrofit (pour récupérer le jeton oauth).

Exemple pour le Interceptor (pour simplifier, il demande toujours le jeton 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()); 
} 

Répondre

1

Votre Interceptor devra s'injecter dans la méthode Interceptor#intercept(). De cette façon, votre service Retrofit (y compris la dépendance OkHttpClient avec l'intercepteur ajouté) peut être satisfait sans cycle de dépendance.

Mon NetworkComponent (qui fournit mon service Retrofit) vit dans ma classe Application. Voici un exemple d'injection en utilisant une application Context. Vous pouvez également définir une variable locale sans injecter toute la classe, ce qui peut améliorer les performances.

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

Approche intéressante. Y a-t-il un inconvénient (par exemple: performance) parce que chaque requête/interception provoque une injection? Aussi l'application doit exposer le NetworkComponent, ce qui me semble un peu étrange. – Maradox

+0

Dagger 2 est conçu pour être rapide car il utilise uniquement du code généré, donc il va essentiellement appeler une méthode qui définit votre 'RestService'. J'ai ajouté un moyen alternatif qui évite d'injecter toute la classe à ma réponse. Il ne doit pas être 'Application' le fournissant, mais quoi d'autre fournirait les composants de votre application' Singleton'? Le stockage de vos composants à l'échelle de l'application dans Application est une pratique courante sur tous les éléments de Dagger 2 que j'ai lus. –

0

Personnellement, je préfère l'injection Lazy, ce qui est un peu plus propre

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, c'est très propre! Cela nécessite-t-il toujours une annotation '@ Inject'? –

+0

À vous de voir. Non si vous écrivez un fournisseur –