[英]Dagger 2.11: Local Singleton when using @ContributesAndroidInjector
我使用@ContributesAndroidInjector注釋( https://google.github.io/dagger/android.html )進行了有效的Dagger設置。
Component Application
/ \
Subcomponent DrawerActivity Subcomponent SubActivity
|
Subcomponent DrawerFragment
在SubActivity和DrawerActivity中,我使用標記為@Singleton的相同存儲庫實例。
@Singleton
@Component(modules = {
AndroidInjectionModule.class,
AppModule.class,
ActivityBuilderModule.class
})
public interface AppComponent {
@Component.Builder
interface Builder{
@BindsInstance Builder application(Application application);
AppComponent build();
}
void inject(App app);
}
@Module
public abstract class ActivityBuilderModule {
@PerActivity
@ContributesAndroidInjector(modules = {DrawerActivityModule.class,
FragmentBuilderModule.class})
abstract DrawerActivity bindDrawerActivity();
@PerActivity
@ContributesAndroidInjector(modules = {DrawerActivityModule.class})
abstract SubActivity bindSubActivity();
}
@Module
public abstract class FragmentBuilderModule {
@PerFragment
@ContributesAndroidInjector(modules = DrawerFragmentModule.class)
abstract DrawerFragment provideDrawerFragment();
}
@Singleton
public class Repository{
private SomeClass mSomeClass;
@Inject
public VehicleRepositoryImpl(SomeClass someClass) {
mSomeClass = someClass;
}
}
public class App extends Application implements HasActivityInjector{
@Inject
DispatchingAndroidInjector<Activity> dispatchingAndroidInjector;
@Override
public void onCreate() {
super.onCreate();
if (BuildConfig.DEBUG) {
Timber.plant(new Timber.DebugTree());
}
AppComponent component = DaggerAppComponent.builder().application(this)
.build();
component.inject(this);
}
@Override
public AndroidInjector<Activity> activityInjector() {
return dispatchingAndroidInjector;
}
}
public class DrawerActivity extends AppCompatActivity implements HasSupportFragmentInjector{
@Inject
DispatchingAndroidInjector<Fragment> fragmentDispatchingAndroidInjector;
@Override
public AndroidInjector<Fragment> supportFragmentInjector() {
return fragmentDispatchingAndroidInjector;
}
@Override
protected void onCreate(Bundle savedInstanceState) {
AndroidInjection.inject(this);
super.onCreate(savedInstanceState);
}
}
public class DrawerFragment extends Fragment {
@Inject
ViewModelFactory mViewModelFactory; //repository gets injected into factory
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
AndroidSupportInjection.inject(this);
super.onCreate(savedInstanceState);
}
}
public class SubActivity extends AppCompatActivity{
@Inject
Repository mRepository;
@Override
protected void onCreate(Bundle savedInstanceState) {
AndroidInjection.inject(this);
super.onCreate(savedInstanceState);
}
}
我現在需要添加用戶管理。 這需要LoginActivity。 我不希望存儲庫在LoginActivity中可用。 所以我想為DrawerActivity / Subactivity / DrawerFragement創建一個本地單例范圍“UserScope”
Component Application
/ \
@UserScope @LoginScope
Subcomponent DrawerActivity SubComponent LoginActivity
| \
Subcomponent DrawerFragment Subcomponent SubActivity
如何使用新的@ContributesAndroidInjector注釋實現此目的?
我希望它像在這篇博文中一樣工作: http : //frogermcs.github.io/building-userscope-with-dagger2/
我在這個回購中解決了我的問題:
https://github.com/ragdroid/Dahaka
非常感謝它的貢獻者!
更新1 :添加了代碼示例。
該圖提供了代碼示例的粗略概念。
Component Application
/ \
@UserScope @LoginScope
Subcomponent UserComponent SubComponent LoginActivity
| \
Subcomponent DrawerActivity Subcomponent SubActivity
|
SubComponent DrawerFragment
代碼示例 (如果缺少某些內容請在評論中告訴我):
1.匕首設置
AppComponent是Dagger圖的根:
@Singleton
@Component(modules = {
AndroidSupportInjectionModule.class,
AppModule.class,
AppBindingModule.class
})
public interface AppComponent extends AndroidInjector<DaggerApplication> {
@Component.Builder
interface Builder{
@BindsInstance Builder application(Application application);
AppComponent build();
}
void inject(MyApp app);
UserComponent.Builder userBuilder();
UserManager getUserManager();
}
綁定其子組件的模塊:
@Module(subcomponents = UserComponent.class)
public abstract class AppBindingModule {
@ContributesAndroidInjector(modules = LoginModule.class)
@LoginScope
abstract LoginActivity loginActivity();
}
UserComponent保存僅在用戶登錄時使用的類的實例.UserModule.class中提供的所有類在其他子組件(如活動和片段組件)中可用作“LocalSingletons” 。
@UserScope
@Subcomponent(modules = {
UserBindingModule.class,
UserModule.class,
AndroidSupportInjectionModule.class
})
public interface UserComponent extends AndroidInjector<DaggerApplication> {
void inject(UserManager userManager);
@Subcomponent.Builder
interface Builder{
UserComponent build();
}
}
UserBindingModule定義哪些活動子組件屬於UserComponent。
@Module
public abstract class UserBindingModule {
@ContributesAndroidInjector(modules = {DrawerBindingModule.class, AndroidSupportInjectionModule.class})
abstract DrawerActivity bindDrawerActivity();
@ContributesAndroidInjector
abstract SubActivity bindSubActivity();
}
DrawerBindingModule定義哪些片段子組件屬於DrawerActivityComponent。
@Module
public abstract class DrawerBindingModule {
@DrawerFragmentScope
@ContributesAndroidInjector(modules = DrawerFragmentModule.class)
abstract DrawerFragment provideDrawerFragment();
}
UserManager處理用戶登錄/注銷以及所有進一步的活動注入。
@Singleton
public class UserManager implements HasActivityInjector {
private final UserComponent.Builder userComponentBuilder;
@Inject
DispatchingAndroidInjector<Activity> activityInjector;
private UserComponent userComponent;
@Inject
public UserManager(UserComponent.Builder builder) {
this.userComponentBuilder = builder;
}
public void logIn(){
createUserSession();
}
private void createUserSession() {
userComponent = userComponentBuilder.build();
userComponent.inject(this);
}
public boolean isLoggedIn() {
return userComponent != null;
}
public void logOut() {
userComponent = null;
}
@Override
public AndroidInjector<Activity> activityInjector() {
return activityInjector;
}
}
2. App + Activity + Fragment類
public class MyApp extends Application implements HasActivityInjector{
@Inject
DispatchingAndroidInjector<Activity> dispatchingAndroidInjector;
@Inject
UserManager mUserManager;
@Override
public void onCreate() {
super.onCreate();
if (BuildConfig.DEBUG) {
Timber.plant(new Timber.DebugTree());
}
AppComponent component = DaggerAppComponent.builder().application(this)
.build();
component.inject(this);
}
@Override
public AndroidInjector<Activity> activityInjector() {
return mUserManager.activityInjector();
}
}
public class LoginActivity extends AppCompatActivity {
Intent mOpenDrawerActivity;
private ActivityLoginBinding binding;
@Inject
UserManager mUserManager;
@Override
protected void onCreate(Bundle savedInstanceState) {
AndroidInjection.inject(this);
super.onCreate(savedInstanceState);
...
}
void openDrawerActivity(){
mUserManager.logIn();
mOpenDrawerActivity = new Intent(this, DrawerActivity.class);
startActivity(mOpenDrawerActivity);
finish();
}
}
public class DrawerActivity extends BaseUserActivity implements HasSupportFragmentInjector{
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
...
}
private void onLogout(){
logoutUser();
}
}
public abstract class BaseUserActivity extends BaseActivity {
@Inject
UserManager userManager;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (!userManager.isLoggedIn()) {
finishView();
}
}
@Override
protected void androidInject() {
AndroidInjection.inject(this);
}
protected void logoutUser() {
userManager.logOut();
finishView();
}
}
public abstract class BaseActivity extends AppCompatActivity implements HasSupportFragmentInjector {
@Inject
DispatchingAndroidInjector<Fragment> injector;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
androidInject();
super.onCreate(savedInstanceState);
}
protected void androidInject() {
AndroidInjection.inject(this);
}
public void finishView() {
startActivity(new Intent(this, LoginActivity.class));
finish();
}
@Override
public AndroidInjector<Fragment> supportFragmentInjector() {
return injector;
}
}
Application
(默認范圍內注釋@Singleton
已經可用), Activity
, BroadcastReceiver
, Fragment
, Service
, ContentProvider
(我從DaggerApplication
這個列表)。 因此,取決於它將基於什么對象,您將在此對象的生命周期內獲得可重用的依賴項(它將是本地單例,例如對於activity / fragment) @ContributesAndroidInjector
來生成@Subcomponent
。 這個子組件應該是作用域的,這就是為什么我們把@FragmentScope
(我們自己創建了注釋)放在它上面。 兩個子片段將屬於此子組件,這就是我們為子片段創建獨立模塊並將其添加到生成的子組件中的原因,方法是將參數modules
添加到父片段子組件的@ContributesAndroidInjector
中。 @Module(includes = [AndroidInjectionModule::class])
abstract class AppBindingModule {
//there are a lot of other android stuff binding here
//activities, fragments, etc.
@FragmentScope
@ContributesAndroidInjector(modules = [ParentFragmentModule::class])
abstract fun bindParentFragment(): ParentFragment
}
@Module
abstract class ParentFragmentModule {
//we should not annotate this by any scope annotation
@ContributesAndroidInjector
abstract fun bindFirstChildFragment(): FirstChildFragment
@ContributesAndroidInjector
abstract fun bindSecondChildFragment(): SecondChildFragment
}
@FragmentScope
class CommonInteractor @Inject constructor() {
//we can inject this interactor into presenters of those two child fragments
//it will be the same instance for both presenters
}
class FirstChildPresenter @Inject constructor(
private val commonInteractor: CommonInteractor
) : Presenter<FirstView>()
class SecondChildPresenter @Inject constructor(
private val commonInteractor: CommonInteractor
) : Presenter<SecondView>()
class FirstChildFragment: Fragment(), FirstView {
@Inject
lateinit var firstChildPresenter: FirstChildPresenter
}
class SecondChildFragment: Fragment(), SecondView {
@Inject
lateinit var secondChildPresenter: SecondChildPresenter
}
我省略了一些細節,比如描述AppComponent並將AppBindingModule添加到其中,並展示如何使用AndroidSupportInjection.inject(this)注入它,因為它不在主題中。 但如果需要澄清,請隨意在評論中提問。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.