Jetpack學(xué)習(xí)之----ViewModel

一、介紹

官方學(xué)習(xí)文檔

ViewModel就是存儲頁面相關(guān)的數(shù)據(jù),并將這些數(shù)據(jù)和Activity、Fragment等有生命周期相關(guān)的組件相關(guān)聯(lián),賦予數(shù)據(jù)生命周期。

特點(diǎn):

  1. 將數(shù)據(jù)與界面控制器進(jìn)行分離(也就是將經(jīng)常在Actvity、Fragment中的保存的數(shù)據(jù)分離出來,這樣這樣界面控制器就主要負(fù)責(zé)與UI相關(guān)的事情即可)

  2. 加大保存數(shù)據(jù)的范圍(當(dāng)頁面發(fā)送無意關(guān)閉時(shí),我們一般是onSaveInstanceState()來保存數(shù)據(jù),但是這樣保存的數(shù)據(jù)大小有限制,而且是必須可序列化再反序列化的數(shù)據(jù),而viewmodel可以保存我們頁面所需的所有數(shù)據(jù))

  3. 分離界面控制器的工作(將一些與數(shù)據(jù)相關(guān)的業(yè)務(wù)處理分來出來,減少控制器對業(yè)務(wù)的處理工作)

  4. ViewModel 保存的數(shù)據(jù)會在activity完成時(shí),由框架調(diào)用onCleared方法清理資源

ViewModel的生命周期

在viewModel對象創(chuàng)建時(shí)開始,一直到他所關(guān)聯(lián)的界面控制器銷毀時(shí)才銷毀,這就說明了即使發(fā)生了橫豎屏切換,界面相關(guān)的數(shù)據(jù)也是一直存在并且不受橫豎屏切換的影響。

通常我們是在Actvity的onCreate()方法中來創(chuàng)建ViewModel對象,該ViewModel對象會一直在內(nèi)存中,直到這個(gè)Activity銷毀時(shí)才釋放資源。

二、使用

1、 添加依賴

// ViewModel
    implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.4.0-alpha03"
    // LiveData
    implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.4.0-alpha03"

2、 創(chuàng)建viewmodel

class MainViewModel:ViewModel() {
    var name:String="Leon"
    var position:MutableLiveData<String> = MutableLiveData()
}

3、 簡單使用

class MainActivity : AppCompatActivity() {

    val TAG=MainActivity::class.java.simpleName
    lateinit var viewModel:MainViewModel
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        viewModel= ViewModelProvider(this).get(MainViewModel::class.java)
        
        //下面是結(jié)合LiveData來使用ViewModel的數(shù)據(jù)的
        viewModel.position.observe(this,{
            Log.e(TAG, "onCreate: position value = ${it}")
        })
    }
}

三、工作原理

原理:

當(dāng)開始創(chuàng)建Activity的實(shí)例對象時(shí),會生成用來存儲ViewModel對象的ViewModelStore實(shí)例(使用Hashmap數(shù)據(jù)結(jié)構(gòu)存儲),并給當(dāng)前Activity的生命周期添加觀察者,用于觀察Activity的生命周期變化,當(dāng)Activity的生命周期是ON_DESTROY時(shí),就會清理掉ViewModelStore中存儲的ViewModel的所有對象,釋放資源。

創(chuàng)建ViewModelProvider對象實(shí)例時(shí),會在其構(gòu)造中調(diào)用生成一個(gè)AndroidViewModelFactory的全局工程對象,我們會使用這個(gè)工廠對象來反射自定義的ViewModel對象。

當(dāng)使用ViewModelProvider對象實(shí)例get自定義的ViewModel對象時(shí),會先從ViewModelStore的Hashmap去找,如果沒有找到,就用上一步的AndroidViewModelFactory實(shí)例來反射自定義的ViewModel對象,并將該ViewModel保存到Hashmap中,下次使用的時(shí)候就可以直接使用;如果找了ViewModel 就直接返回該ViewModel的對象。

從上面ViewModel的工作原理可以得知:

1、ViewModel 一旦創(chuàng)建好了,就會一直保存到當(dāng)前界面控制器(Activity 、Fragment等)銷毀時(shí)才會釋放資源;

2、不同的界面控制器,ViewModel 的對象時(shí)存在不同的Hashmap中的,他們也是不同的對象;局部單例;

3、要做到全局單例ViewModel對象,可以將ViewModel放到Application中去;

接下來從源碼角度來分析一下原理:

1、創(chuàng)建存儲ViewModel的容器ViewModelStore對象

在構(gòu)建Activity的對象時(shí),在其父類ComponentActivity.java中實(shí)現(xiàn)了接口ViewModelStoreOwner,在其實(shí)現(xiàn)方法中生成ViewModelStore對象

//ComponentActivity.java
 public ViewModelStore getViewModelStore() {
        if (getApplication() == null) {
            throw new IllegalStateException("Your activity is not yet attached to the "
                    + "Application instance. You can't request ViewModel before onCreate call.");
        }
        if (mViewModelStore == null) {
            NonConfigurationInstances nc =
                    (NonConfigurationInstances) getLastNonConfigurationInstance();
            if (nc != null) {
                // Restore the ViewModelStore from NonConfigurationInstances
                mViewModelStore = nc.viewModelStore;
            }
            if (mViewModelStore == null) {
                mViewModelStore = new ViewModelStore();
            }
        }
        return mViewModelStore;
    }

2、ViewModelProvider(this)生成AndroidViewModelFactory工廠對象

//ViewModelProvider.kt
public constructor(
        owner: ViewModelStoreOwner
    ) : this(owner.viewModelStore, defaultFactory(owner))


//AndroidViewModelFactory的伴生對象
public open class AndroidViewModelFactory(
        private val application: Application
    ) : NewInstanceFactory() {
        @Suppress("DocumentExceptions")
        override fun <T : ViewModel> create(modelClass: Class<T>): T {
            return if (AndroidViewModel::class.java.isAssignableFrom(modelClass)) {
                try {
                    modelClass.getConstructor(Application::class.java).newInstance(application)
                } catch (e: NoSuchMethodException) {
                    throw RuntimeException("Cannot create an instance of $modelClass", e)
                } catch (e: IllegalAccessException) {
                    throw RuntimeException("Cannot create an instance of $modelClass", e)
                } catch (e: InstantiationException) {
                    throw RuntimeException("Cannot create an instance of $modelClass", e)
                } catch (e: InvocationTargetException) {
                    throw RuntimeException("Cannot create an instance of $modelClass", e)
                }
            } else super.create(modelClass)
        }

        public companion object {
            internal fun defaultFactory(owner: ViewModelStoreOwner): Factory =
                if (owner is HasDefaultViewModelProviderFactory)
                    owner.defaultViewModelProviderFactory else instance

            internal const val DEFAULT_KEY = "androidx.lifecycle.ViewModelProvider.DefaultKey"

            private var sInstance: AndroidViewModelFactory? = null

            /**
             * Retrieve a singleton instance of AndroidViewModelFactory.
             *
             * @param application an application to pass in [AndroidViewModel]
             * @return A valid [AndroidViewModelFactory]
             */
            @JvmStatic
            public fun getInstance(application: Application): AndroidViewModelFactory {
                if (sInstance == null) {
                  //**** 生成全局的ViewModelFactory對象
                    sInstance = AndroidViewModelFactory(application)
                }
                return sInstance!!
            }
        }
    }

3、生成自定義的ViewModel實(shí)例

//ViewModelProvider.kt
public open operator fun <T : ViewModel> get(key: String, modelClass: Class<T>): T {
        var viewModel = store[key]
        if (modelClass.isInstance(viewModel)) {
            (factory as? OnRequeryFactory)?.onRequery(viewModel)
            return viewModel as T
        } else {
            @Suppress("ControlFlowWithEmptyBody")
            if (viewModel != null) {
                // TODO: log a warning.
            }
        }
        viewModel = if (factory is KeyedFactory) {
            factory.create(key, modelClass)
        } else {
            //此處進(jìn)入上一步創(chuàng)建好的AndroidViewModelFactory的create()方法中去
            factory.create(modelClass)
        }
        store.put(key, viewModel)
        return viewModel
    }


//AndroidViewModelFactory 類
@Suppress("DocumentExceptions")
        override fun <T : ViewModel> create(modelClass: Class<T>): T {
            return if (AndroidViewModel::class.java.isAssignableFrom(modelClass)) {
                try {
                  //1.第一步獲取自定義ViewModel的構(gòu)造器,第二部構(gòu)造viewmodel的實(shí)例
                    modelClass.getConstructor(Application::class.java).newInstance(application)
                } catch (e: NoSuchMethodException) {
                    throw RuntimeException("Cannot create an instance of $modelClass", e)
                } catch (e: IllegalAccessException) {
                    throw RuntimeException("Cannot create an instance of $modelClass", e)
                } catch (e: InstantiationException) {
                    throw RuntimeException("Cannot create an instance of $modelClass", e)
                } catch (e: InvocationTargetException) {
                    throw RuntimeException("Cannot create an instance of $modelClass", e)
                }
            } else super.create(modelClass)
        }
    
    

4、ViewModel 觀察界面控制器的生命周期

在界面控制器的構(gòu)造函數(shù)中,就添加了對生命周期的觀察者,而當(dāng)觀察者收到當(dāng)前的界面控制器的生命周期是Lifecycle.Event.ON_DESTROY時(shí),就會將mViewModelStore對象map中所有保存的viewModel清理掉,這樣來達(dá)到釋放資源。

這里只處理了ON_DESTROY的生命周期狀態(tài),那么也就說明了在ViewModel對象實(shí)例創(chuàng)建成功后,不管界面控制器(如Activity)的生命周期(除ON_DESTROY外)如何發(fā)生變化,ViewModel都不會被清理掉。

//ComponentActivity.java
public ComponentActivity() {
        Lifecycle lifecycle = getLifecycle();
        //noinspection ConstantConditions
        if (lifecycle == null) {
            throw new IllegalStateException("getLifecycle() returned null in ComponentActivity's "
                    + "constructor. Please make sure you are lazily constructing your Lifecycle "
                    + "in the first call to getLifecycle() rather than relying on field "
                    + "initialization.");
        }
        if (Build.VERSION.SDK_INT >= 19) {
            getLifecycle().addObserver(new LifecycleEventObserver() {
                @Override
                public void onStateChanged(@NonNull LifecycleOwner source,
                        @NonNull Lifecycle.Event event) {
                    if (event == Lifecycle.Event.ON_STOP) {
                        Window window = getWindow();
                        final View decor = window != null ? window.peekDecorView() : null;
                        if (decor != null) {
                            decor.cancelPendingInputEvents();
                        }
                    }
                }
            });
        }
        getLifecycle().addObserver(new LifecycleEventObserver() {
            @Override
            public void onStateChanged(@NonNull LifecycleOwner source,
                    @NonNull Lifecycle.Event event) {
                if (event == Lifecycle.Event.ON_DESTROY) {
                    if (!isChangingConfigurations()) {
                        getViewModelStore().clear();
                    }
                }
            }
        });

        if (19 <= SDK_INT && SDK_INT <= 23) {
            getLifecycle().addObserver(new ImmLeaksCleaner(this));
        }
    }

5、存儲ViewModel的數(shù)據(jù)結(jié)構(gòu)

//ViewModelStore.java
public class ViewModelStore {

    private final HashMap<String, ViewModel> mMap = new HashMap<>();

    final void put(String key, ViewModel viewModel) {
        ViewModel oldViewModel = mMap.put(key, viewModel);
        if (oldViewModel != null) {
            oldViewModel.onCleared();
        }
    }

    final ViewModel get(String key) {
        return mMap.get(key);
    }

    Set<String> keys() {
        return new HashSet<>(mMap.keySet());
    }

    /**
     *  Clears internal storage and notifies ViewModels that they are no longer used.
     */
    public final void clear() {
        for (ViewModel vm : mMap.values()) {
            vm.clear();
        }
        mMap.clear();
    }
}


6、Hashmap存放ViewModel的key的生成規(guī)則

從這里看出來ViewModel對應(yīng)key的唯一性

//ViewModelProvider.kt

internal const val DEFAULT_KEY = "androidx.lifecycle.ViewModelProvider.DefaultKey"

public open operator fun <T : ViewModel> get(modelClass: Class<T>): T {
  
        //這里需要注意下這個(gè)canonicalName是個(gè)什么東西
        val canonicalName = modelClass.canonicalName
            ?: throw IllegalArgumentException("Local and anonymous classes can not be ViewModels")
        return get("$DEFAULT_KEY:$canonicalName", modelClass)
    }


//Class.java 
public String getCanonicalName() {
        if (isArray()) {
            String canonicalName = getComponentType().getCanonicalName();
            if (canonicalName != null)
                return canonicalName + "[]";
            else
                return null;
        }
        if (isLocalOrAnonymousClass())
            return null;
        Class<?> enclosingClass = getEnclosingClass();
        if (enclosingClass == null) { // top level class
            return getName();
        } else {
            String enclosingName = enclosingClass.getCanonicalName();
            if (enclosingName == null)
                return null;
            return enclosingName + "." + getSimpleName();
        }
    }

四、總結(jié)

ViewModel工作原理的核心技術(shù)點(diǎn):

觀察者模式、工程模式、反射、Hashmap數(shù)據(jù)結(jié)構(gòu)

ViewModel在MVVM架構(gòu)模型中,與DataBinding結(jié)合使用,會讓你有起飛的感覺。后續(xù)會進(jìn)一步加深使用。本篇僅以學(xué)會使用、了解原理為重點(diǎn)。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容