多くの場合、グローバルに利用可能な ViewModel を維持する必要があります。これは、同じグローバル データ ソースを維持でき、アプリのライフ サイクルをバインドするためにコルーチンを使用すると便利だからです。では、グローバルに利用可能な ViewModel オブジェクトを設計するにはどうすればよいでしょうか?
1. アイデア
viewModel
オブジェクトは に保存されているViewModelStore
ため、グローバルを作成しViewModelStore
、viewModel
オブジェクトを取得するときにそこから取得します。
viewModel
通常は というメソッドViewModelProvider
を通じて取得されます。get
ViewModelProvider(owner: ViewModelStoreOwner, factory: Factory).get(ViewModel::class.java)
どのようにViewModelProvider
関連付けViewModelStore
ますか? リンクは、ViewModelStoreOwner
それがメソッドをViewModelStoreOwner
実装する必要があるインターフェイスでありgetViewModelStore()
、メソッドが返すものは次のとおりであるということですViewModelStore
。
public interface ViewModelStoreOwner {
/**
* Returns owned {@link ViewModelStore}
*
* @return a {@code ViewModelStore}
*/
@NonNull
ViewModelStore getViewModelStore(); //返回一个ViewModelStore
}
特定のクラスにこのインターフェイスを実装させ、定義した内容を返すようにメソッドを書き換えますViewModelStore
。
上記の構築方法ViewModelProvider
の 2 番目のパラメータはFactory
?
ソース コードには 2 つのタイプが提供されていますFactory
。1 つはNewInstanceFactory
、もう 1 つは ですAndroidViewModelFactory
。主な違いは次のとおりです。
-
NewInstanceFactory が ViewModel を作成するとき、アクティビティまたはフラグメントごとに新しい ViewModel インスタンスが作成されます。これにより、ViewModel がアプリケーションのさまざまな部分でデータを共有できなくなります。(ComponentActivity ソースコードの getDefaultViewModelProviderFactory メソッド)
-
AndroidViewModelFactory はアプリケーションのグローバル状態にアクセスでき、ViewModel インスタンスはアプリケーション全体で共有できます。
必要に応じて、AndroidViewModelFactory を使用する必要があります。
2. 実現
1. 方法 1: 任意の値を追加および取得できます。ViewModel
アプリケーション、Ktx.kt
ファイルの定義
import android.app.Application
lateinit var appContext: Application
fun setApplicationContext(context: Application) {
appContext = context
}
グローバルに利用可能なViewModelOwner
実装クラスを定義する
object ApplicationScopeViewModelProvider : ViewModelStoreOwner {
private val eventViewModelStore: ViewModelStore = ViewModelStore()
override fun getViewModelStore(): ViewModelStore {
return eventViewModelStore
}
private val mApplicationProvider: ViewModelProvider by lazy {
ViewModelProvider(
ApplicationScopeViewModelProvider,
ViewModelProvider.AndroidViewModelFactory.getInstance(appContext)
)
}
fun <T : ViewModel> getApplicationScopeViewModel(modelClass: Class<T>): T {
return mApplicationProvider.get(modelClass)
}
}
ViewModel
を定義して、StateFlow
イベントの送信およびサブスクライブのメソッドを定義します。
class EventViewModel : ViewModel() {
private val mutableStateFlow = MutableStateFlow(0)
fun postEvent(state: Int) {
mutableStateFlow.value = state
}
fun observeEvent(scope: CoroutineScope? = null, method: (Int) -> Unit = {
_ -> }) {
val eventScope = scope ?: viewModelScope
eventScope.launch {
mutableStateFlow.collect {
method.invoke(it)
}
}
}
}
というクラスを定義します
object FlowEvent {
//发送事件
fun postEvent(state: Int) {
ApplicationScopeViewModelProvider.getApplicationScopeViewModel(EventViewModel::class.java)
.postEvent(state)
}
//订阅事件
fun observeEvent(scope: CoroutineScope? = null, method: (Int) -> Unit = {
_ -> }) {
ApplicationScopeViewModelProvider.getApplicationScopeViewModel(EventViewModel::class.java)
.observeEvent(scope, method)
}
}
テストコードは次のとおりです。
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
//打印协程名称
System.setProperty("kotlinx.coroutines.debug", "on")
FlowEvent.observeEvent {
printMsg("MainActivity observeEvent before :$it")
}
//修改值
FlowEvent.postEvent(1)
FlowEvent.observeEvent {
printMsg("MainActivity observeEvent after :$it")
}
}
}
//日志
内容:MainActivity observeEvent before :0 线程:main @coroutine#1
内容:MainActivity observeEvent before :1 线程:main @coroutine#1
内容:MainActivity observeEvent after :1 线程:main @coroutine#2
2. 方法 2: Activity と Fragment を呼び出す方が便利です
アプリケーションを定義してBaseApplication
実現しようViewModelStoreOwner
//BaseApplication实现ViewModelStoreOwner接口
class BaseApplication : Application(), ViewModelStoreOwner {
private lateinit var mAppViewModelStore: ViewModelStore
private var mFactory: ViewModelProvider.Factory? = null
override fun onCreate() {
super.onCreate()
//设置全局的上下文
setApplicationContext(this)
//创建ViewModelStore
mAppViewModelStore = ViewModelStore()
}
override fun getViewModelStore(): ViewModelStore = mAppViewModelStore
/**
* 获取一个全局的ViewModel
*/
fun getAppViewModelProvider(): ViewModelProvider {
return ViewModelProvider(this, this.getAppFactory())
}
private fun getAppFactory(): ViewModelProvider.Factory {
if (mFactory == null) {
mFactory = ViewModelProvider.AndroidViewModelFactory.getInstance(this)
}
return mFactory as ViewModelProvider.Factory
}
}
Ktx.kt
ファイルも次のように変更されました
lateinit var appContext: Application
fun setApplicationContext(context: Application) {
appContext = context
}
//定义扩展方法
inline fun <reified VM : ViewModel> Fragment.getAppViewModel(): VM {
(this.requireActivity().application as? BaseApplication).let {
if (it == null) {
throw NullPointerException("Application does not inherit from BaseApplication")
} else {
return it.getAppViewModelProvider().get(VM::class.java)
}
}
}
//定义扩展方法
inline fun <reified VM : ViewModel> AppCompatActivity.getAppViewModel(): VM {
(this.application as? BaseApplication).let {
if (it == null) {
throw NullPointerException("Application does not inherit from BaseApplication")
} else {
return it.getAppViewModelProvider().get(VM::class.java)
}
}
}
上記の拡張メソッドをBaseActivity
とで呼び出します。BaseFragment
abstract class BaseActivity: AppCompatActivity() {
//创建ViewModel对象
val eventViewModel: EventViewModel by lazy {
getAppViewModel() }
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
}
}
abstract class BaseFragment: Fragment() {
//创建ViewModel对象
val eventViewModel: EventViewModel by lazy {
getAppViewModel() }
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
}
}
テストコード
class MainActivity : BaseActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
//打印协程名称
System.setProperty("kotlinx.coroutines.debug", "on")
eventViewModel.observeEvent {
printMsg("MainActivity observeEvent :$it")
}
findViewById<AppCompatButton>(R.id.bt).setOnClickListener {
//点击按钮修改值
eventViewModel.postEvent(1)
//跳转到其他Activity
Intent(this, TwoActivity::class.java).also {
startActivity(it) }
}
}
}
class TwoActivity : BaseActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_two)
eventViewModel.observeEvent {
printMsg("TwoActivity observeEvent :$it")
}
}
}
ログ
内容:MainActivity observeEvent :0 线程:main @coroutine#1
内容:MainActivity observeEvent :1 线程:main @coroutine#1
内容:TwoActivity observeEvent :1 线程:main @coroutine#2
やっと
アーキテクトになりたい場合、または 20,000 ~ 30,000 の給与範囲を突破したい場合は、コーディングとビジネスに限定されず、モデルを選択し、拡張し、プログラミング的思考を向上させることができなければなりません。また、しっかりとしたキャリアプランも大切で、学ぶ習慣も大切ですが、一番大切なのは継続力であり、継続的に実行できないプランは絵にかいたもちです。
方向性がわからない場合は、Ali の上級アーキテクトによって書かれた一連の「Android の 8 つの主要モジュールに関する上級ノート」をここで共有したいと思います。これは、乱雑で散在し断片化した知識を体系的かつ効率的に整理するのに役立ちます。 . Android開発のさまざまな知識をマスターします。
私たちが普段読んでいる断片的な内容と比べて、このノートの知識ポイントはより体系的で理解しやすく、覚えやすく、知識体系に従って厳密に配置されています。
ビデオ素材のフルセット:
1. インタビュー集
2. ソースコード解析集
3. オープン ソース フレームワークのコレクションは、
ワン クリックと 3 つのリンクで誰でもサポートできるようになっています。記事内の情報が必要な場合は、記事の最後にある CSDN 公式認定 WeChat カードを直接スキャンして無料で入手してください↓↓↓