web-dev-qa-db-ja.com

ダガー2を使用してViewModelを作成し、それにリポジトリを挿入するにはどうすればよいですか?

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つのことを理解していません:

  1. このUsersRepositoryVievModelを注入するにはどうすればよいですか?プレゼンターを使用すると、次のような短剣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();

7
ip696

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のサンプルからダガーに関する多くのことを学びました。それらもチェックできます。

11
Reza A. Ahmadi

私は、これをより簡単でよりクリーンにするライブラリを作成しました。マルチバインディングや工場の定型文は必要ありませんが、実行時に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
        })
    }
}
0
Radu Topor

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

0
veeyikpong