ViewModel中傳入Context的方法 1.通過kotlin的拓展函數 2.通過自定義ViewModelProvider.Factory

ViewModel使用的越來越多了,嚴格來說,官方並不建議你在ViewModel中添加Context的引用。同時,ViewModel的構造方法是沒有任何參數的,有的時候會很不靈活。以下記錄兩種方法。

1.通過kotlin的拓展函數


fun <T : ViewModelProvider, V : ViewModel> T.get(
    key: String,
    modelClass: Class<V>,
    context: FragmentActivity
): V {
    val model = get(key, modelClass)
    if (model is TestViewModel) {
        model.addContext(context)
    }
    return model
}

fun <T : ViewModelProvider, V : ViewModel> T.get(
    key: String,
    modelClass: Class<V>,
    context: Context
): V {
    val model = get(key, modelClass)
    if (model is TestViewModel) {
        model.addContext(context)
    }
    return model
}

fun <T : ViewModelProvider, V : ViewModel> T.get(
    modelClass: Class<V>,
    context: FragmentActivity
): V {
    val model = get(modelClass)
    if (model is TestViewModel) {
        model.addContext(context)
    }
    return model
}

fun <T : ViewModelProvider, V : ViewModel> T.get(
    modelClass: Class<V>,
    context: Context
): V {
    val model = get(modelClass)
    if (model is TestViewModel) {
        model.addContext(context)
    }
    return model
}

TestViewModel中添加如下的方法

class TestViewModel : ViewModel() {
    protected lateinit var context: Context
    open fun addContext(context: FragmentActivity) {
        this.context = context
    }

    open fun addContext(context: Context) {
        this.context = context
    }
}

使用方法

val viewModel = ViewModelProvider(this).get(TestViewModel::class.java, this)

2.通過自定義ViewModelProvider.Factory

class CoreViewModelFactory(private val context: Context) : ViewModelProvider.Factory {
    override fun <T : ViewModel?> create(modelClass: Class<T>): T {
        try {
            for (constructor in modelClass.constructors) {
                if (arrayOf(Context::class.java).contentEquals(constructor.parameterTypes)) {
                    return (constructor as Constructor<T>).newInstance(context)
                }
            }
            return modelClass.newInstance()
        } catch (e: InstantiationException) {
            throw RuntimeException("Cannot create an instance of $modelClass", e)
        } catch (e: IllegalAccessException) {
            throw RuntimeException("Cannot create an instance of $modelClass", e)
        }
    }
}

關於這一塊,仔細閱讀ViewModelProvider的代碼,會發現,裏面同樣提供了兩三種的Factory。針對可以直接擁有contextAndroidViewModel,提供了ViewModelProvider.AndroidViewModelFactory,只是在引用的時候,不要再自己添加一遍了。

以下是你的TestViewModel

class TestViewModel(private val context: Context) : ViewModel() {
    init {
        L.i(" context $context ")
    }
}

使用方法

val viewModel = ViewModelProvider(this, CoreViewModelFactory(this)).get(TestViewModel::class.java)

以上兩種方法也可以用來幫助你自定義一些你要傳入的參數。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章