如何创建ViewModel并使用匕首2向其注入存储库?

时间:2018-07-08 12:47:21

标签: android viewmodel dagger-2

我尝试了解ViewModel。我创建了ViewModel:

public class UsersViewModel extends ViewModel {

    private final UsersRepository usersRepository;

    public UsersViewModel(UsersRepository usersRepository) {
        this.usersRepository = usersRepository;
    }

    public LiveData<List<User>> loadAll() {
        return usersRepository.getAll();
    }

}

但是我不明白两件事:

  1. 如何向此UsersRepository注入VievModel?当我使用演示者时,可以使用匕首2创建它,如下所示:
@Module
public class PresentersModule {

    @Singleton
    @Provides
    UsersPresenter provideUsersPresenter(UsersRepository usersRepository) {
        return new UsersPresenter(usersRepository);
    }
}

但是如何使用ViewModel呢?像这样?

@Module
public class ViewModelsModule {

    @Singleton
    @Provides
    UsersViewModel provideUsersViewModel(UsersRepository usersRepository) {
        return new UsersViewModel(usersRepository);
    }
}
  1. 如何在片段中获取此ViewModel?有了主持人,我可以做到:

    presenter = MyApplication.get()。getAppComponent()。getUsersPresenter();

4 个答案:

答案 0 :(得分:9)

ViewModel是通过ViewModelProvider创建的,该ViewModelFactory使用@Singleton public class DaggerViewModelFactory implements ViewModelProvider.Factory { private final Map<Class<? extends ViewModel>, Provider<ViewModel>> creators; @Inject public DaggerViewModelFactory(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); } } } 创建实例。您不能直接注入ViewModel,而应使用如下所示的自定义工厂

@Module
abstract class ViewModelModule {
@Binds
abstract ViewModelProvider.Factory bindViewModelFactory(DaggerViewModelFactory factory);

@Binds
@IntoMap
@ViewModelKey(VideoListViewModel.class)
abstract ViewModel provideVideoListViewModel(VideoListViewModel videoListViewModel);

@Binds
@IntoMap
@ViewModelKey(PlayerViewModel.class)
abstract ViewModel providePlayerViewModel(PlayerViewModel playerViewModel);

@Binds
@IntoMap
@ViewModelKey(PlaylistViewModel.class)
abstract ViewModel providePlaylistViewModel(PlaylistViewModel playlistViewModel);

@Binds
@IntoMap
@ViewModelKey(PlaylistDetailViewModel.class)
abstract ViewModel providePlaylistDetailViewModel(PlaylistDetailViewModel playlistDetailViewModel);
}

然后,您需要一个用于匕首的模块,用于创建视图模型工厂和视图模型本身。

ViewModelKey

@Target({ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @MapKey @interface ViewModelKey { Class<? extends ViewModel> value(); } 文件就是这样

public class PlayerActivity extends BaseActivity {
     @Inject DaggerViewModelFactory viewModelFactory;
     PlayerViewModel viewModel;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        AndroidInjection.inject(this);
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_player);
        viewModel = ViewModelProviders.of(this,viewModelFactory).get(PlayerViewModel.class);

}

现在要在活动或片段中获取视图模型,只需将视图模型工厂注入,然后使用该工厂创建视图模型实例

public class PlayerViewModel extends ViewModel {
    private VideoRepository videoRepository;
    private AudioManager audioManager;


    @Inject
    public PlayerViewModel(VideoRepository videoRepository, AudioManager audioManager) {
         this.videoRepository = videoRepository;
         this.audioManager = audioManager;

    }
}

要向存储库中的ViewModel注入任何内容,只需使用构造函数注入。

$result = []
while($row = $result->fetch_assoc()) {
    $result[] = $row["modello"];
}

从这里https://github.com/alzahm/VideoPlayer中查看完整的示例,我也从Google样本中学到了许多匕首的知识,您也可以将其检出。

答案 1 :(得分:0)

我编写了一个库,该库应使其更直接,更简洁,不需要多重绑定或工厂样板,同时还可以在运行时进一步对ViewModel进行参数化: https://github.com/radutopor/ViewModelFactory

@ViewModelFactory
class UserViewModel(@Provided repository: Repository, userId: Int) : ViewModel() {

    val greeting = MutableLiveData<String>()

    init {
        val user = repository.getUser(userId)
        greeting.value = "Hello, $user.name"
    }    
}

在视图中:

class UserActivity : AppCompatActivity() {
    @Inject
    lateinit var userViewModelFactory2: UserViewModelFactory2

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_user)
        appComponent.inject(this)

        val userId = intent.getIntExtra("USER_ID", -1)
        val viewModel = ViewModelProviders.of(this, userViewModelFactory2.create(userId))
            .get(UserViewModel::class.java)

        viewModel.greeting.observe(this, Observer { greetingText ->
            greetingTextView.text = greetingText
        })
    }
}

答案 2 :(得分:0)

Dagger2要求您创建ViewModelModule并绑定到您的ViewModels

我知道您在问有关Dagger2的问题,但是如果您要开始一个新项目,也许您可​​以签出Koin来提供轻量级注入。

我已经在一些生产应用程序中使用过它,并且在较少的代码行中也可以正常工作。

您可以像

一样在模块中声明
viewModel { MyViewModel(get()) }

然后在您的活动/片段/类中(您需要扩展KoinComponent),只需编写

val myViewModel : MyViewModel by viewModel()

它将处理创建本身。

有关更多信息,请参阅

https://insert-koin.io/

https://start.insert-koin.io/#/getting-started/koin-for-android?id=android-viewmodel

答案 3 :(得分:0)

此解决方案允许您在没有工厂的情况下将依赖项注入 ViewModel 和 Workers。相反,它使用静态方法。

将图注入类

这一行可以用在 init 块或 onCreate 方法中(底部的 ViewModel 示例)

    Injector.getComponent().inject(this)

基础应用

    class BaseApplication : Application() {
    
        lateinit var applicationComponent: ApplicationComponent
    
        override fun onCreate() {
            super.onCreate()

            INSTANCE = this

            applicationComponent = DaggerApplicationComponent
                .builder()
                //Add your modules
                .build()
        }
    
        companion object {
            private var INSTANCE: BaseApplication? = null
    
            @JvmStatic
            fun get(): BaseApplication= INSTANCE!!
        }
    }

注射器

    class Injector private constructor() {
        companion object {
            @JvmStatic
            fun getComponent(): ApplicationComponent = BaseApplication.get().applicationComponent
        }
    }

就是这样!

像往常一样在 ApplicationComponent 中请求注入

应用组件

Singleton
@Component(modules = [add your modules])
interface ApplicationComponent {
    fun inject(someViewModel: SomeViewModel)
}

视图模型

    class SomeViewModel : ViewModel(){

        @Inject
        lateinit var someClass: SomeClass //In your case, userRepository: UserRepository

        init{
            Injector.getComponent().inject(this)
        }
    }