Android はグローバルに呼び出し可能な ViewModel オブジェクトをどのように設計しているのでしょうか?

多くの場合、グローバルに利用可能な ViewModel を維持する必要があります。これは、同じグローバル データ ソースを維持でき、アプリのライフ サイクルをバインドするためにコルーチンを使用すると便利だからです。では、グローバルに利用可能な ViewModel オブジェクトを設計するにはどうすればよいでしょうか?

1. アイデア

viewModelオブジェクトは に保存されているViewModelStoreため、グローバルを作成しViewModelStoreviewModelオブジェクトを取得するときにそこから取得します。

viewModel通常は というメソッドViewModelProviderを通じて取得されますgetViewModelProvider(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 カードを直接スキャンして無料で入手してください↓↓↓

おすすめ

転載: blog.csdn.net/weixin_43440181/article/details/130712833