Android ViewModel 附加参数

新手上路,请多包涵

有没有办法将附加参数传递给我的自定义 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 传递给我的自定义 ViewModel 。我只能传递应用程序上下文,但不能传递其他参数。我真的很感激任何帮助。谢谢你。

编辑:我添加了一些代码。我希望现在好多了。

原文由 Mario Rudman 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 2.1k
2 个回答

您需要为您的 ViewModel 提供一个工厂类。

 public class MyViewModelFactory implements ViewModelProvider.Factory {
    private Application mApplication;
    private String mParam;

    public MyViewModelFactory(Application application, String param) {
        mApplication = application;
        mParam = param;
    }

    @Override
    public <T extends ViewModel> T create(Class<T> modelClass) {
        return (T) new MyViewModel(mApplication, mParam);
    }
}

在实例化视图模型时,您可以这样做:

 MyViewModel myViewModel = ViewModelProvider(this, new MyViewModelFactory(this.getApplication(), "my awesome param")).get(MyViewModel.class);

对于 kotlin,您可以使用委托属性:

 val viewModel: MyViewModel by viewModels { MyViewModelFactory(getApplication(), "my awesome param") }

There’s also another new option - to implement HasDefaultViewModelProviderFactory and override getDefaultViewModelProviderFactory() with the instantiation of your factory and then you would call ViewModelProvider(this) or by viewModels() 没有工厂。

原文由 mlykotom 发布,翻译遵循 CC BY-SA 4.0 许可协议

正确的方法是使用依赖注入框架,例如 Dagger hilt 。如果不使用 DI 框架,请使用 ViewModelFactory。

使用匕首:

带参数的 ViewModel

 @HiltViewModel
class MyViewModel @Inject constructor(
    private val myRepository: MyRepository,
    private val savedStateHandle: SavedStateHandle
) : ViewModel() { ... }

存储库

class MyRepository @Inject constructor(
    private val myRemoteDataSource: MyDataSource,
    private val ioDispatcher: CoroutineDispatcher = Dispatchers.IO
) { ... }

用于提供依赖项/参数的模块,以便可以将它们注入到存储库和 ViewModel 中。

 @InstallIn(ViewModelComponent::class)
@Module
object MyProvideModule {
    @Provides
    fun provideMyDataSource(@ApplicationContext context: Context): MyDataSource {
        //code to create MyDataSource...
        return MyDataSource(context)
    }

    @Provides
    fun provideCoroutineDispatcher(): CoroutineDispatcher {
        return Dispatchers.IO
    }
}

用于绑定存储库的模块

@Module
@InstallIn(ViewModelComponent::class)
interface RepositoryModules {
    @Binds
    fun provideMyRepository(repository: MyRepository): MyRepository
}

使用带有 @HiltAndroidApp 注释的应用程序启动 Dagger 刀柄。

 @HiltAndroidApp
class MainApplication : Application() {

    override fun onCreate() {
        super.onCreate()
    }

}

在活动中获取 ViewModel

 @AndroidEntryPoint
class MainActivity : AppCompatActivity() {
  private val myViewModel: MyViewModel by viewModels()
  // Other code...
}

获取片段中的 ViewModel

 @AndroidEntryPoint
class MyFragment : Fragment() {
  private val myViewModel: MyViewModel by activityViewModels()
  // Other code...
}

使用 ViewModelFactory:

带有参数 messageDataStore 的 ViewModel,其中 MessageDataStore 是一个 DataStore 类,或者它可以是您想要传递给 ViewModel 的任何其他内容。

 class MyViewModel(
    private val messageDataStore: MessageDataStore,
): ViewModel() { ... }

用于创建 ViewModel 的 ViewModel 工厂类

/**
 * Factory for all ViewModels.
 */
@Suppress("UNCHECKED_CAST")
class ViewModelFactory constructor(
    private val messageDataStore: MessageDataStore,
    owner: SavedStateRegistryOwner,
    defaultArgs: Bundle? = null
) : AbstractSavedStateViewModelFactory(owner, defaultArgs) {
    override fun <T : ViewModel> create(
        key: String,
        modelClass: Class<T>,
        handle: SavedStateHandle
    ) = with(modelClass) {
        when {
            isAssignableFrom(MyViewModel::class.java) ->
                MyViewModel(messageDataStore)
            else ->
                throw IllegalArgumentException("Unknown ViewModel class: ${modelClass.name}")
        }
    } as T
}

用于创建依赖项/参数的应用程序类

class MyApp : Application() {
    val messageDataStore: MessageDataStore
        get() = MessageDataStore.getInstance(this)

}

用于在活动和片段中获取工厂类的扩展函数,MyExt.kt

 fun AppCompatActivity.getViewModelFactory(savedInstanceState: Bundle?): ViewModelFactory {
    val messageDataStore = (applicationContext as MyApp).messageDataStore
    return ViewModelFactory(messageDataStore, this, savedInstanceState)
}

fun Fragment.getViewModelFactory(savedInstanceState: Bundle?): ViewModelFactory {
    val messageDataStore = (requireContext().applicationContext as MyApp).messageDataStore
    return ViewModelFactory(messageDataStore, this.requireActivity(), savedInstanceState)
}

在活动中获取 ViewMode

 class MainActivity : AppCompatActivity() {

  private lateinit var myViewModel: MyViewModel
  // Other code...

  override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    val vm by viewModels<MyViewModel> { getViewModelFactory(savedInstanceState) }
    myViewModel = vm
    // Other code...
  }
}

在 Fragments 中获取 ViewModel。

 class MyFragment : Fragment() {
    private lateinit var myViewModel: MyViewModel
    //Other code...

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View {
      val vm by activityViewModels<MyViewModel> { getViewModelFactory(savedInstanceState) }
      myViewModel = vm
      //Other code...
  }
}

原文由 s-hunter 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题