Method of passing in Context in ViewModel

ViewModelIt is used more and more. Strictly speaking, the official does not recommend that you ViewModeladd Contextreferences to it. At the same time, ViewModelthe construction method does not have any parameters, and sometimes it is very inflexible. Two methods are recorded below.

#1. Through kotlin's extension function


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
}

In the TestViewModelmethod, add the following

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

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

Instructions

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

#2. Through custom 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)
        }
    }
}

Regarding this one, if you read the code of ViewModelProvider carefully, you will find that there are also two or three kinds of Factory provided. For the contextones AndroidViewModelthat can be directly owned , they are provided ViewModelProvider.AndroidViewModelFactory, just don't add them again when you quote them.

Below is yoursTestViewModel

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

Instructions

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

The above two methods can also be used to help you customize some of the parameters you want to pass in.

Guess you like

Origin blog.csdn.net/Ser_Bad/article/details/111637963