我尝试了解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();
}
}
但是我不明白两件事:
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);
}
}
如何在片段中获取此ViewModel?有了主持人,我可以做到:
presenter = MyApplication.get()。getAppComponent()。getUsersPresenter();
答案 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://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)
}
}