How to inject dependencies in ViewModels using Dag

2019-07-14 00:25发布

问题:

I am trying to implement new architecture (MVVM + RxJava2 + Dagger2 + Retrofit) in my existing project. I have set up whole above architecture and tested on HomeActivity. Dependencies injected in HomeViewModel. So Now I was trying to inject dependencies same as HomeViewModel in a FollowingViewModel of FollowingFragment which is a container Fragment of HomeActivity.But injected dependencies always return null(Not Initiziling). I am following this project riggaroo/android-arch-components-date-countdown to Inject dependencies but in this sample, only activities are used no fragment. So I don't know what is happening and who to inject deps in multiple ViewModels.

Here is code for some Important classes to understand:

AppApplication.class

 public class AppApplication extends MultiDexApplication implements HasActivityInjector {
@Inject
    DispatchingAndroidInjector<Activity> dispatchingAndroidInjector;
@Override
    public void onCreate() {
        ...........................
        AppInjector.init(this)
        ..........................
    }
    @Override
    public AndroidInjector<Activity> activityInjector() {
        return dispatchingAndroidInjector;
    }
}

AppInjector.class

public class AppInjector {
private AppInjector() {
}

public static void init(AppApplication appApplication) {
    DaggerAppComponent.builder()
            .application(appApplication)
            .build()
            .inject(appApplication);
            appApplication
            .registerActivityLifecycleCallbacks(new Application.ActivityLifecycleCallbacks() {
                @Override
                public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
                    handleActivity(activity);
                }

            });
}

private static void handleActivity(Activity activity) {
    if (activity instanceof HasSupportFragmentInjector) {
        AndroidInjection.inject(activity);
    }
    if (activity instanceof FragmentActivity) {
        ((FragmentActivity) activity).getSupportFragmentManager()
                .registerFragmentLifecycleCallbacks(
                        new FragmentManager.FragmentLifecycleCallbacks() {
                            @Override
                            public void onFragmentCreated(FragmentManager fm, Fragment f,
                                                          Bundle savedInstanceState) {
                                if (f instanceof Injectable) {
                                    AndroidSupportInjection.inject(f);
                                }
                            }
                        }, true);
    }
}

}

AppComponent.class

@Singleton
@Component(modules = {AndroidSupportInjectionModule.class,ActivityBuilderModule.class, AppModule.class, NetworkModule.class})
public interface AppComponent {
@Component.Builder
interface Builder {
    @BindsInstance
    Builder application(AppApplication application);

    AppComponent build();

}
void inject(AppApplication app);

AppModule.class

@Module(includes = { ViewModelModule.class})
public class AppModule {
    @Provides
    Context provideContext(AppApplication application) {
        return application.getApplicationContext();
    }
}

ActivityBuilderModule.class

@Module
public abstract class ActivityBuilderModule {
@ContributesAndroidInjector(modules = FragmentBuildersModule.class)
abstract HomeActivity bindHomeActivity();
}

FragmentBuildersModule.class

@Module
public abstract class FragmentBuildersModule {
@ContributesAndroidInjector
abstract FollowingListFragment contributeFollowingListFragment();
}

ViewModule.class

@Module
public abstract class ViewModelModule {
    @Binds
    @IntoMap
    @ViewModelKey(FollowingViewModel.class)
    abstract ViewModel bindFollowingViewModel(FollowingViewModel followingViewModel);

    @Binds
    @IntoMap
    @ViewModelKey(HomeViewModel.class)
    abstract ViewModel bindHomeViewModel(HomeViewModel homeViewModel);

    @Binds
    abstract ViewModelProvider.Factory bindViewModelFactory(MyViewModelFactory factory);

}

NetworkModule.class

 @Module
public class NetworkModule {
    public NetworkModule(){}
    @Provides
    @Singleton
    CompositeDisposable getCompositeDisposable() {
        return new CompositeDisposable();
    }
    @Provides
    @Singleton
    Retrofit provideCall() {
        // OKHttps and Retrofit code...
    }
    @Provides
    @Singleton
    @SuppressWarnings("unused")
    public ApiCallInterface providesNetworkService(
            Retrofit retrofit) {
        return retrofit.create(ApiCallInterface.class);
    }
    @Provides
    @Singleton
    @SuppressWarnings("unused")
    public Repository providesService(
            ApiCallInterface networkService) {
        return new Repository(networkService);
    }
}

MyViewModelFactory.class

@Singleton
public class MyViewModelFactory extends ViewModelProvider.NewInstanceFactory {
private final Map<Class<? extends ViewModel>, Provider<ViewModel>> creators;

@Inject
public MyViewModelFactory(Map<Class<? extends ViewModel>, Provider<ViewModel>> creators) {
    this.creators = creators;
}

@SuppressWarnings("unchecked")
@Override
public <T extends ViewModel> T create(Class<T> modelClass) {
    Provider<? extends ViewModel> creator = creators.get(modelClass);
    if (creator == null) {
        for (Map.Entry<Class<? extends ViewModel>, Provider<ViewModel>> entry : creators.entrySet()) {
            if (modelClass.isAssignableFrom(entry.getKey())) {
                creator = entry.getValue();
                break;
            }
        }
    }
    if (creator == null) {
        throw new IllegalArgumentException("unknown model class " + modelClass);
    }
    try {
        return (T) creator.get();
    } catch (Exception e) {
        throw new RuntimeException(e);
    }
}
}

This class is used to create Instances of all viewModels. I have debugged and found only HomeViewModel instance is creating.

Now I have created HomeViewModel which is called from HomeActivity. Which is working fine. Now same implementaion is done in FollowingFragment but doesn't work. Let me show you how I have initialized FollowViewModel from FollowingListFragment.class

public class FollowingListFragment extends BaseFragment implementsInjectable {
    @Inject
    MyViewModelFactory myViewModelFactory;
    private FollowingViewModel followingViewModel;

@Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mContext = getActivity();
followingViewModel = ViewModelProviders.of(this, plownsViewModelFactory)
                .get(FollowingViewModel.class);
}

@Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        return inflater.inflate(R.layout.fragment_following_list, container, false);
    }

@Override
    public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        followingViewModel.getFollowings(id,curser);
 }
}

Here is FollowingViewModel.class

public class FollowingViewModel extends ViewModel {
@Inject
Repository service;
@Inject
CompositeDisposable subscriptions;

@Inject
public FollowingViewModel() {
}

/*void setService(Repository service){
    this.service = service;
}*/

void getFollowings(String id,String curser) {
    if(service!=null) { **//HERE SERVICE RETURNS NULL** 
        Disposable subscription = service.getFollowings(id, curser, new IResponseCallback<FollowingResponse.FollowingResult>() {
            @Override
            public void onSuccess(FollowingResponse.FollowingResult followingResult) {
            }
            @Override
            public void onError(Throwable throwable) {
            }
        });
        subscriptions.add(subscription);
    }else {
        Log.d("FollowViewModel", "Service is null " );
    }
}

Here is HomeActivity and HomeViewModel class code which is working fine. HomeActivity.class

public class HomeActivity extends BaseActivity implements HasSupportFragmentInjector, Injectable {

    @Inject
    DispatchingAndroidInjector<Fragment> supportFragmentInjector;
    @Inject
    MyViewModelFactory viewFactory;
    HomeViewModel homeViewModel;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    homeViewModel = ViewModelProviders.of(this,viewFactory).get(HomeViewModel.class);
        homeViewModel.getFollowings("xyx",null);
 }
 @Override
    public AndroidInjector<Fragment> supportFragmentInjector() {
        return supportFragmentInjector;
    }
}

HomeViewModel.class

public class HomeViewModel extends ViewModel {
    @Inject
    Repository service;
    @Inject
    CompositeDisposable subscriptions;
    @Inject
    public HomeViewModel() {

    }

    void getFollowings(String id,String curser) {
        if(service!=null) { **// Returing null service**
}
    }else {
            Log.d("FollowViewModel", "Service is null " );
        }
}
}

I am struggling for 2 days. Please help, suggest. Thanks. Please don't downvote if you are not willing to help.