2015-10-15 1 views
1

Donc, un peu de contexte. J'utilise Dagger2, Retrofit et RxAndroid et structurer mon application en utilisant une architecture MVP. Pour l'instant, tout ce que je fais est de faire une demande de réseau à l'API de récupérer des informations dès que mon activité principale commence. J'essaye de persister mes présentateurs à travers les changements de configuration pour éviter de faire une nouvelle requête http chaque fois que je fais pivoter mon écran.Dagger2 singleton annotation ne fonctionne pas

MainActivity.java

public class MainActivity extends AppCompatActivity implements ForecastView { 


@Inject 
Presenter forecastPresenter; 

private TextView text; 

@Override 
protected void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    setContentView(R.layout.activity_main); 
    text = (TextView) findViewById(R.id.weather); 
    Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); 
    setSupportActionBar(toolbar); 
    initializeDependencies(); 
    initializePresenter(); 
} 

private void initializeDependencies() { 
    DaggerWeatherApiComponent.builder() 
      .build().inject(this); 
} 

private void initializePresenter() { 
    forecastPresenter.attachView(this); 
    forecastPresenter.onCreate(); 

} 

WeatherApiComponent.java

@Component(modules = {EndpointsModule.class}) 
@Singleton 
public interface WeatherApiComponent { 
    void inject(MainActivity context); 
} 

EndpointsModule.java

@Module @Singleton 
public class EndpointsModule { 

    @Provides 
    @Singleton 
    WeatherEndpoints provideEndpoints() { 
     Retrofit retrofit = new Retrofit.Builder() 
       .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) 
       .addConverterFactory(GsonConverterFactory.create()) 
       .client(new OkHttpClient()) 
       .baseUrl("http://api.openweathermap.org/data/2.5/") 
       .build(); 
     return retrofit.create(WeatherEndpoints.class); 
    } 

    @Provides 
    @Singleton 
    Repository providesRepository(RestRepository repository) { 
     return repository; 
    } 

    @Provides 
    @Singleton 
    Presenter providesPresenter(ForecastPresenter presenter) { 
     return presenter; 
    } 
} 

RestRespository

public class RestRepository implements Repository { 
    private WeatherEndpoints endpoints; 
    static final String API_KEY = "xxxxxxxxxxxxxxxxxxxxx"; 

    @Inject 
    public RestRepository(WeatherEndpoints endpoints) { 
     this.endpoints = endpoints; 
    } 

    public Observable<Current> getCurrentWeather(String cityName) { 
     return endpoints.getCurrent(cityName, API_KEY); 
    } 

    public Observable<com.feresr.rxweather.models.List> getForecast(String cityName) { 
     return endpoints.getForecast(cityName, API_KEY).flatMap(new Func1<FiveDays, Observable<com.feresr.rxweather.models.List>>() { 
      @Override 
      public Observable<com.feresr.rxweather.models.List> call(FiveDays fiveDays) { 
       return Observable.from(fiveDays.getList()); 
      } 
     }); 
    } 

}

ForecastPresenter.java

public class ForecastPresenter implements Presenter { 
private GetForecastUseCase useCase; 
private Subscription forecastSubscription; 
private ArrayList<List> lists; 
private ForecastView forecastView; 

@Inject 
public ForecastPresenter(GetForecastUseCase forecastUseCase) { 
    this.useCase = forecastUseCase; 
    lists = new ArrayList<>(); 
} 

@Override 
public void onStop() { 
    if (forecastSubscription.isUnsubscribed()) { 
     forecastSubscription.unsubscribe(); 
    } 
} 

@Override 
public void attachView(View v) { 
    forecastView = (ForecastView) v; 
} 


@Override 
public void onCreate() { 
    if (lists.isEmpty()) { 
     forecastSubscription = useCase.execute().subscribe(new Action1<List>() { 
      @Override 
      public void call(List list) { 
       lists.add(list); 
       forecastView.addForecast(list.getWeather().get(0).getMain()); 
      } 
     }); 
    } else { 
     forecastView.addForecast(lists.get(0).toString()); 
    } 
} 

Le constructeur de cette classe (présentateur) garde qui se fait appeler comme je tourne mon acitivité. J'ai annoté avec @Singleton la plupart de mes cours. Je ne sais pas quoi faire d'autre.

EDIT: Notez que je ne suis pas encore entré dans les SCOPES dagger, pour l'instant je me moque de savoir si ce présentateur singleton vit aussi longtemps que mon application. Je vais régler ça plus tard.

Répondre

4

Il semble que vous recréez le composant Dagger chaque fois que MainActivity.onCreate(Bundle) est appelée et que l'activité est réactivée lorsque vous faites pivoter l'écran.

Comme d'autres champs d'application, @Singleton signifie qu'il y aura une instance de l'objet pour la durée de vie du composant, non pas pour la durée de vie de la machine virtuelle Java. Vous devez généralement vous assurer qu'il n'y a qu'une seule instance du composant @Singleton, généralement en le conservant dans un champ de votre Application.

+1

Complètement bien! –

+0

Oh! Alors, pourquoi dérange-t-on l'annotation des composants et des modules avec l'annotation @singleton? – feresr

+1

L'ajout d'une annotation de portée à une méthode '@ Provides' signifie que la méthode sera appelée au plus une fois dans une instance du composant dans lequel elle est installée.Sans cela, la méthode '@ Provides' serait appelée à chaque fois qu'une méthode' get() 'de' Provider' est appelée, même dans une instance de composant. Chaque classe qui '' @ Injects'' un 'RestRepository' obtiendrait une nouvelle instance. – netdpb

1

Vous créez un nouveau composant de poignard à chaque fois ici:

private void initializeDependencies() { 
    DaggerWeatherApiComponent.builder() 
      .build().inject(this); 
} 

Une dépendance dans le scope existe comme une instance par composant.

Si vous créez un nouveau composant, il aura sa propre portée et créera sa propre instance.

Vous devez soit investir dans des étendues Mortar pour préserver votre composant, soit vous devriez avoir une sorte de "cache" dans votre instance Application.