如何在AndroidX中实例化ViewModel?

Nur*_*lov 5 android viewmodel android-jetpack

我想使用androidx库在Activity中初始化ViewModel

我已经尝试了文档中说的内容,但是没有用。“ .of”未解析。

import androidx.appcompat.app.AppCompatActivity
Run Code Online (Sandbox Code Playgroud)

import android.os.Bundle import androidx.databinding.DataBindingUtil import androidx.lifecycle.ViewModelProvider import com.example.myapplication.databinding.ActivityMainBinding

MainActivity类:AppCompatActivity(){

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    val binding: ActivityMainBinding = DataBindingUtil.setContentView(
        this, R.layout.activity_main)
    binding.setLifecycleOwner(this)

    var model = ViewModelProvider.of(this).get(SheduleViewModel::class.java)

}
Run Code Online (Sandbox Code Playgroud)

}

的尚未解决,可能是在androidx中有其他方法

Ada*_*itz 14

将 ViewModel 更新到Lifecycle 版本 2.2.0及更高版本

所述的ViewModels(VM)的可理论上被初始化为使用科特林扩展库类水平的实例变量import androidx.fragment.app.viewModels的方法by viewmodels()。通过将 VM 初始化为类级别实例 var,可以在类中访问它。

问题:将 VM 初始化为类级别实例变量而不是 inside 是否有缺点onCreate

在创建具有扩展功能onCreate的 VM 时,VM 仅在其范围内,onCreate并且需要额外的代码来重新分配类级别的实例变量。

查看文档

将 VM 初始化为类实例 Val

class Fragment : Fragment() {
    private val viewModel: SomeViewModel by viewModels()

    private fun observeViewState() {
        viewModel.feedViewState.observe(viewLifecycleOwner) { viewState ->
            //viewState used here.
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

在 onCreate 中初始化 VM 并重新分配类实例变量

class Fragment : Fragment() {
    private lateinit var viewModel: SomeViewModel

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        val viewModel: ContentViewModel by viewModels()
        this.viewModel = viewModel
    }

    private fun observeViewState() {
        viewModel.feedViewState.observe(viewLifecycleOwner) { viewState ->
            //viewState used here.
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

传递参数/参数

// 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") } 
}
Run Code Online (Sandbox Code Playgroud)

使用参数/参数启用 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
    }
}
Run Code Online (Sandbox Code Playgroud)


DrG*_*ral 6

附注。这是针对那些使用 Java 并像我一样卡住了一段时间的人来说的,这个 SO 答案一直出现在谷歌中。

显然,截至该日期(2020 年 5 月 6 日),API 发生了变化,我必须这样做才能使其正常工作。

// 1. Create a ViewModel Class Let's call it AppStateViewModel

// 2. Put below code Inside Activity onCreate like this:
ViewModelProvider.Factory factory = new ViewModelProvider.NewInstanceFactory();
appStateManager = new ViewModelProvider(this, factory).get(AppStateViewModel.class);
Run Code Online (Sandbox Code Playgroud)


小智 6

对我来说,唯一有效的方法是:

implementation 'androidx.fragment:fragment:1.2.4'
Run Code Online (Sandbox Code Playgroud)


Ana*_*hah 6

在您的应用程序 gradle 文件中,确保您已添加以下依赖项:

对于活动用途:

implementation "androidx.activity:activity-ktx:1.4.1"
Run Code Online (Sandbox Code Playgroud)

对于片段使用:

implementation 'androidx.fragment:fragment:1.4.1'
Run Code Online (Sandbox Code Playgroud)


Ric*_*ira 5

更新的答案:

事情改变了一点点,因为以前需要依赖- ViewModelProviders- 得到了弃用(详见旧的答案)。您现在可以ViewModelProvider直接使用构造函数。

因此,在这种情况下,答案将是:

private val viewModel = ViewModelProvider(this).get(SheduleViewModel::class.java)
Run Code Online (Sandbox Code Playgroud)

需要注意的是,但是,如果你实例化一个ViewModelFragment,你可以添加androidx.fragment:fragment-ktx:$Version依赖关系,然后利用财产代表团:

private val viewModel: SheduleViewModel by viewModels()
Run Code Online (Sandbox Code Playgroud)

它在内部将使用ViewModelProvider和范围的ViewModel给你Fragment。这只是编写相同内容的一种更简洁的方式。

无论是ViewModelProvider构造和by viewModels()也接受工厂作为参数(注入您有用ViewModel):

private val viewModel = 
    ViewModelProvider(this, viewModelFactory).get(SheduleViewModel::class.java)
Run Code Online (Sandbox Code Playgroud)

private val viewModel: SheduleViewModel by viewModels { viewModelFactory }
Run Code Online (Sandbox Code Playgroud)

使用最适合您的一种。

旧答案:

添加androidx.lifecycle:lifecycle-extensions:$lifecycleExtensionsVersion依赖项以便导入ViewModelProviders


Amr*_*era 5

ViewModelProviders:此类已弃用。直接使用 ViewModelProvider 的构造函数。

Kotlin中的示例

这是直接使用ViewModelProvider 的方法:

如果您的视图模型仅使用一个参数(即应用程序)扩展AndroidViewModel ,那么您可以使用默认的AndroidViewModelFactory,而无需编写新的 Factory。例子:

// Activity / fragment class
private lateinit var viewModel: MyOwnAndroidViewModel

    // onCreate
    viewModel = ViewModelProvider(
            this,
            ViewModelProvider.AndroidViewModelFactory(application)
        ).get(MyOwnAndroidViewModel::class.java)
Run Code Online (Sandbox Code Playgroud)

如果您的视图模型仅扩展ViewModel而没有额外的参数,则使用NewInstanceFactory()

// Activity / fragment class
private lateinit var viewModel: MyOwnViewModel

    // onCreate
    viewModel = ViewModelProvider(
            this,
            ViewModelProvider.NewInstanceFactory()
        ).get(MyOwnViewModel::class.java)
Run Code Online (Sandbox Code Playgroud)

亚当的上述回答也涵盖了其他变化。

免责声明:仍在学习基本的 Android 开发 - 如果代码有任何问题,请在评论中告诉我。