Dagger 2, BottomNavigation и Injecting - PullRequest
       34

Dagger 2, BottomNavigation и Injecting

1 голос
/ 29 октября 2019

Я делаю небольшое приложение для Android в MVVM и Dagger 2. Но я не знаю, как правильно использовать Dagger 2 в случае, когда у меня есть одно действие и два фрагмента. Оба фрагмента являются владельцами моделей ViewModels. Я вставил ViewModelProvider в Fragment, но я все еще не уверен в этом решении. Может, кто-нибудь улучшит мой код?

Активность :

public class MainActivity extends DaggerAppCompatActivity {

private static final String TAG = "MainActivity";

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    BottomNavigationView navView = findViewById(R.id.nav_view);

    NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment);
    NavigationUI.setupWithNavController(navView, navController);
}

}

Первый фрагмент :

public class EventsFragment extends DaggerFragment {

private static final String TAG = "EventsFragment";
private EventsViewModel eventsViewModel;
private final EventsAdapter adapter = new EventsAdapter();
private List<Event> events = new ArrayList<>();

@Inject
ViewModelProviderFactory viewModelProviderFactory;

public View onCreateView(@NonNull LayoutInflater inflater,
                         ViewGroup container, Bundle savedInstanceState) {
    eventsViewModel = ViewModelProviders.of(this, viewModelProviderFactory).get(EventsViewModel.class);
    View root = inflater.inflate(R.layout.fragment_events, container, false);

    RecyclerView recyclerView = root.findViewById(R.id.events_recycler_view);
    recyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
    recyclerView.setHasFixedSize(true);
    recyclerView.setAdapter(adapter);

    getEvents();

    return root;
}

Второй фрагмент:

public class ScheduleFragment extends DaggerFragment {

private ScheduleViewModel scheduleViewModel;

public View onCreateView(@NonNull LayoutInflater inflater,
                         ViewGroup container, Bundle savedInstanceState) {
    scheduleViewModel = ViewModelProviders.of(this).get(ScheduleViewModel.class);
    View root = inflater.inflate(R.layout.fragment_schedule, container, false);

    return root;
}

@Override
public void onAttach(Context context) {
    AndroidSupportInjection.inject(this);
    super.onAttach(context);
}
}

В этом случае оба фрагмента работают, но я могу внедрить ViewModelFactory только в один. Если я добавлю это ко второму: error: не могу найти класс символов DaggerAppComponent

ActivityBuildersModule:

@Module
public abstract class ActivityBuildersModule {

@ContributesAndroidInjector(modules = FragmentBuildersModule.class)
abstract MainActivity contributeMainActivity();
}

AppComponent:

   @Singleton
   @Component(
    modules = {
            AndroidSupportInjectionModule.class,
            ActivityBuildersModule.class,
            AppModule.class,
            ViewModelFactoryModule.class
    }
    )
    public interface AppComponent extends AndroidInjector<BaseApplication> {

@Component.Builder
interface Builder {

    @BindsInstance
    Builder application(Application application);

    AppComponent build();
}

}

FragmentBuildersModule:

 @Module
 public abstract class FragmentBuildersModule {

@ContributesAndroidInjector(
        modules = {ViewModelModule.class, EventsModule.class}
)
abstract EventsFragment contributeEventsFragment();

@ContributesAndroidInjector(
        modules = {ViewModelModule.class}
)
abstract ScheduleFragment contributeScheduleFragment();
}

ViewModelFactory:

@Module
public abstract class ViewModelFactoryModule {

@Binds
public abstract ViewModelProvider.Factory bindViewModelFactory(ViewModelProviderFactory modelProviderFactory);
}

ViewModelKey:

@Documented
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@MapKey
public @interface ViewModelKey {
Class<? extends ViewModel> value();
}

ViewModelModule:

@Module

открытый абстрактный класс ViewModelModule {

@Binds
@IntoMap
@ViewModelKey(EventsViewModel.class)
public abstract ViewModel bindEventsViewModel(EventsViewModel eventsViewModel);

@Binds
@IntoMap
@ViewModelKey(ScheduleViewModel.class)
public abstract ViewModel bindScheduleViewmodel(ScheduleViewModel scheduleViewModel);

BaseApplication:

public class BaseApplication extends DaggerApplication {


@Override
protected AndroidInjector<? extends DaggerApplication> applicationInjector() {
    return DaggerAppComponent.builder().application(this).build();
}

1 Ответ

1 голос
/ 29 октября 2019

Просто сделайте это, как в первом фрагменте. Попробуйте это



public class ScheduleFragment extends DaggerFragment {

private ScheduleViewModel scheduleViewModel;

@Inject
ViewModelProviderFactory viewModelProviderFactory;

public View onCreateView(@NonNull LayoutInflater inflater,
                         ViewGroup container, Bundle savedInstanceState) {
    scheduleViewModel = ViewModelProviders.of(this, viewModelProviderFactory).get(ScheduleViewModel.class);
    View root = inflater.inflate(R.layout.fragment_schedule, container, false);

    return root;
}
}

Также способ предоставить Api, добавив этот метод, подобный этому, в AppModule

@Singleton
    @Provides
    public RemoteApi provideRemoteApi(){
        return Retrofit.Builder()
            .addConverterFactory(GsonConverterFactory.create())
            .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
            .baseUrl(Constants.API_BASE_URL)
            .build()
            .create(RemoteApi::class.java)
    }

, где вы должны заменить RemoteApi своим классом Api.

...