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();
}
}
しかし、私は2つのことを理解していません:
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();
ViewModel
は、ViewModelProvider
を使用してインスタンスを作成するViewModelFactory
によって作成されます。 ViewModelを直接注入することはできません。代わりに、以下のようなカスタムファクトリを使用する必要があります
@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);
}
}
}
次に、ビューモデルファクトリとビューモデル自体を作成する短剣用のモジュールが必要です。
@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;
}
}
ここから完全に機能する例をチェックしてください https://github.com/alzahm/VideoPlayer 、また、Googleのサンプルからダガーに関する多くのことを学びました。それらもチェックできます。
私は、これをより簡単でよりクリーンにするライブラリを作成しました。マルチバインディングや工場の定型文は必要ありませんが、実行時に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
})
}
}
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