151

AndroidViewModelアプリケーション コンテキスト以外のカスタム コンストラクターに追加の引数を渡す方法はありますか。例:

public class MyViewModel extends AndroidViewModel {
    private final LiveData<List<MyObject>> myObjectList;
    private AppDatabase appDatabase;

    public MyViewModel(Application application, String param) {
        super(application);
        appDatabase = AppDatabase.getDatabase(this.getApplication());

        myObjectList = appDatabase.myOjectModel().getMyObjectByParam(param);
    }
}

カスタムViewModelクラスを使用する場合は、フラグメントで次のコードを使用します。

MyViewModel myViewModel = ViewModelProvider.of(this).get(MyViewModel.class)

String paramしたがって、追加の引数を customに渡す方法がわかりませんViewModel。アプリケーション コンテキストのみを渡すことができますが、追加の引数は渡すことができません。助けていただければ幸いです。ありがとうございました。

編集:いくつかのコードを追加しました。今は良くなっていることを願っています。

4

9 に答える 9

43

依存性注入で実装する

これはより高度で、プロダクション コードに適しています。

Dagger2、Square のAssistedInjectは、ネットワークやデータベースの要求を処理するリポジトリなどの必要なコンポーネントを注入できる、ViewModel の本番対応の実装を提供します。また、アクティビティ/フラグメントに引数/パラメーターを手動で挿入することもできます。これは、Gabor Varadi の詳細な投稿Dagger Tipsに基づいて、コード Gists で実装する手順の簡潔な概要です。

Dagger Hiltは次世代ソリューションであり、2020 年 7 月 12 日の時点でアルファ版であり、ライブラリがリリース ステータスになると、同じユース ケースをより簡単なセットアップで提供します。

KotlinでLifecycle 2.2.0を実装する

引数/パラメータの受け渡し

// Override ViewModelProvider.NewInstanceFactory to create the ViewModel (VM).
class SomeViewModelFactory(private val someString: String): ViewModelProvider.NewInstanceFactory() {
    override fun <T : ViewModel?> create(modelClass: Class<T>): T = SomeViewModel(someString) as T
} 

class SomeViewModel(private val someString: String) : ViewModel() {
    init {
        //TODO: Use 'someString' to init process when VM is created. i.e. Get data request.
    }
}

class Fragment: Fragment() {
    // Create VM in activity/fragment with VM factory.
    val someViewModel: SomeViewModel by viewModels { SomeViewModelFactory("someString") } 
}

引数/パラメータで SavedState を有効にする

class SomeViewModelFactory(
    private val owner: SavedStateRegistryOwner,
    private val someString: String) : AbstractSavedStateViewModelFactory(owner, null) {
    override fun <T : ViewModel?> create(key: String, modelClass: Class<T>, state: SavedStateHandle) =
            SomeViewModel(state, someString) as T
}

class SomeViewModel(private val state: SavedStateHandle, private val someString: String) : ViewModel() {
    val feedPosition = state.get<Int>(FEED_POSITION_KEY).let { position ->
        if (position == null) 0 else position
    }
        
    init {
        //TODO: Use 'someString' to init process when VM is created. i.e. Get data request.
    }
        
     fun saveFeedPosition(position: Int) {
        state.set(FEED_POSITION_KEY, position)
    }
}

class Fragment: Fragment() {
    // Create VM in activity/fragment with VM factory.
    val someViewModel: SomeViewModel by viewModels { SomeViewModelFactory(this, "someString") } 
    private var feedPosition: Int = 0
     
    override fun onSaveInstanceState(outState: Bundle) {
        super.onSaveInstanceState(outState)
        someViewModel.saveFeedPosition((contentRecyclerView.layoutManager as LinearLayoutManager)
                .findFirstVisibleItemPosition())
    }    
        
    override fun onViewStateRestored(savedInstanceState: Bundle?) {
        super.onViewStateRestored(savedInstanceState)
        feedPosition = someViewModel.feedPosition
    }
}
于 2020-02-08T19:56:04.700 に答える