天天看點

網易一面之ViewModel存儲原理面試總結

作者:搬磚小碼龍

#頭條創作挑戰賽#

本文通過在網易面試遇到的問題總結而出,如有不對的地方,請及時批評指正。篇幅較長,請耐心閱讀。如果您想了解其他架構源碼,歡迎評論區留言!

簡介

ViewModel作為谷歌Jetpack重要元件之一,它可以目前頁面緩存狀态并可在配置更改後持久保留相應狀态。

網易一面之ViewModel存儲原理面試總結

使用步驟

ViewModel

1.定義MainViewModel類繼承ViewModel()

class MainViewModel:ViewModel() {
   val mainLiveData = MutableLiveData<String>() 
}           

2.在activity中通過ViewModelProvider擷取MainViewModel執行個體對象。

class MainActivity : AppCompatActivity() {
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        val viewModel = ViewModelProvider(this, ViewModelProvider.NewInstanceFactory()).
        get(MainViewModel::class.java)
        viewModel.mainLiveData.observe(this){
            
        }
    }           

通過定義一個MainViewModel類繼承自ViewModel抽象類,然後再Activity中初始化MainViewModel。

AndroidViewModel

  1. 如果需要在ManViewModel中使用context,MainViewModel需要繼承AndroidViewModel。
class MainViewModel(application: Application):AndroidViewModel(application) {
   val mainLiveData = MutableLiveData<String>()

}           

2 .使用ViewModelProvider擷取MainViewModel執行個體對象

val viewModel = ViewModelProvider(this, ViewModelProvider.AndroidViewModelFactory(application)).get(MainViewModel::class.java)
        viewModel.mainLiveData.observe(this){

        }           

源碼分析

網易一面之ViewModel存儲原理面試總結

Activity綁定

1 .Activity的父類ComponentActivity實作了ViewModelStoreOwner接口,

public class ComponentActivity extends androidx.core.app.ComponentActivity implements
        ContextAware,
        LifecycleOwner,
        ViewModelStoreOwner,
}
           

2 .ViewModelStoreOwner中定義了getViewModelStore方法用來提供ViewModelStore。

public interface ViewModelStoreOwner {
     //傳回一個ViewModelStore
    @NonNull
    ViewModelStore getViewModelStore();
}
           

3 .ViewModelStore中定義HashMap用來儲存ViewModel執行個體。

public class ViewModelStore {
    //定義HashMap集合存儲ViewModel
    private final HashMap<String, ViewModel> mMap = new HashMap<>();
    //存儲ViewModel
    final void put(String key, ViewModel viewModel) {
        ViewModel oldViewModel = mMap.put(key, viewModel);
        if (oldViewModel != null) {
            oldViewModel.onCleared();
        }
    }
   //根據key值擷取對應的ViewModel
    final ViewModel get(String key) {
        return mMap.get(key);
    }

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

    /**
     *  回收所有ViewModel并清空HashMap.
     */
    public final void clear() {
        for (ViewModel vm : mMap.values()) {
            vm.clear();
        }
        mMap.clear();
    }
}           

4 .由于ComponentActivity實作了ViewModelStoreOwner接口,在ComponentActivity中調用getViewModelStore可以擷取ViewModel的存儲類ViewModelStore,ViewModelStore中使用HashMap存儲ViewModel,如果存儲的ViewModel的key值相同,則删除oldViewModel舊的ViewModel,替換成最新的ViewModel。

5 . ComponentActivity中使用Lifecycle對目前activity生命周期進行監聽,并在on Destroy生命周期中對儲存在ViewModelStore中的ViewModel進行清空釋放。

public ComponentActivity() {
        Lifecycle lifecycle = getLifecycle();
        ......................
        .........................
        //使用lifecycle對activity生命周期進行監聽
        getLifecycle().addObserver(new LifecycleEventObserver() {
            @Override
            public void onStateChanged(@NonNull LifecycleOwner source,
                    @NonNull Lifecycle.Event event) {
                 //如果生命周期為onDestory
                if (event == Lifecycle.Event.ON_DESTROY) {
                    // 清除context
                    mContextAwareHelper.clearAvailableContext();
                    //如果應用配置沒有發生改變
                    if (!isChangingConfigurations()) {
                        //清除ViewModelStore中HashMap存儲的ViewModel
                        getViewModelStore().clear();
                    }
                }
            }
        });
     getLifecycle().addObserver(new LifecycleEventObserver() {
            @Override
            public void onStateChanged(@NonNull LifecycleOwner source,
                    @NonNull Lifecycle.Event event) {
                //初始化ViewModelStore
                ensureViewModelStore();
                getLifecycle().removeObserver(this);
            }
        });
           

當ComponentActivity退出銷毀時,會調用getViewModelStore().clear(),清除ViewModelStore中HashMap存儲的ViewModel,釋放資源。

6 .調用ensureViewModelStore進行ViewModelStore進行初始化。

void ensureViewModelStore() {
        //如果存儲類為null
        if (mViewModelStore == null) {
            //擷取上一個儲存的NonConfigurationInstances執行個體對象
            NonConfigurationInstances nc =
                    (NonConfigurationInstances) getLastNonConfigurationInstance();
            if (nc != null) {
                // 從 NonConfigurationInstances 恢複 ViewModelStore
                mViewModelStore = nc.viewModelStore;
            }
            //否則建立新的ViewModelStore
            if (mViewModelStore == null) {
                mViewModelStore = new ViewModelStore();
            }
        }
    }

  static final class NonConfigurationInstances {
        Object custom;
        //成員變量用來儲存ViewModelStore
        ViewModelStore viewModelStore;
    }           

NonConfigurationInstances是一個靜态類,它有兩個成員變量Object 和ViewModelStore ;如果ViewModelstore如果不存在,則将NonConfigurationInstances的成員變量儲存的ViewModelstore指派給ViewModelStore 。

//擷取上一次儲存的資料
    @Nullable
    public Object getLastNonConfigurationInstance() {
        return mLastNonConfigurationInstances != null
                ? mLastNonConfigurationInstances.activity : null;
    }
           

mLastNonConfigurationInstances 是上一次儲存的資料執行個體,當Activity被建立的時候,調用attach方法,mLastNonConfigurationInstances = lastNonConfigurationInstances;當應用配置發生改變時,如螢幕旋轉,會導緻Activity重建,這個時候會擷取上一次儲存的mLastNonConfigurationInstances ,并取出其中存儲的viewModeStore,最後得到ViewModel,直接從ViewModel中得到資料恢複界面清單。

ViewModel儲存

1 .使用ViewModelProvider建立ViewModel。

public static ViewModelProvider of(@NonNull FragmentActivity activity) {
     //建立ViewModelProvider對象
    return new ViewModelProvider(activity);
    }

           

2 .由于目前activity實作ViewModelStoreOwner接口,是以可以通過getViewModelStore方法擷取ViewModelStore對象。

public ViewModelProvider(@NonNull ViewModelStoreOwner owner) {
      //由于目前activity實作ViewModelStoreOwner接口,
      //是以可以通過getViewModelStore方法擷取ViewModelStore對象。
     
     this(owner.getViewModelStore(), owner instanceof HasDefaultViewModelProviderFactory
                ? ((HasDefaultViewModelProviderFactory) owner).getDefaultViewModelProviderFactory()
                : NewInstanceFactory.getInstance());
    }
public ViewModelProvider(@NonNull ViewModelStore store, @NonNull Factory factory) {
        mFactory = factory;
        mViewModelStore = store;
    }
           

3 . 使用工廠模式建立ViewModel同時儲存到ViewModelStore中。

public <T extends ViewModel> T get(@NonNull String key, @NonNull Class<T> modelClass) {
   //擷取activity中的ViewModel
    ViewModel viewModel = mViewModelStore.get(key);
    
    ..........
    //使用工廠模式建立viewModel執行個體
    if (mFactory instanceof KeyedFactory) {
        viewModel = ((KeyedFactory) (mFactory)).create(key, modelClass);
    } else {
        viewModel = (mFactory).create(modelClass);
    }
    //将viewModel存入ViewModelStore中
    mViewModelStore.put(key, viewModel);
    return (T) viewModel;
}           

ViewModel銷毀

當activity退出銷毀時,通過lifecycle對activity的生命周期監聽,如果配置沒有發生改變,正常退出,則直接情況ViewModelStore。

//使用lifecycle對activity生命周期進行監聽
        getLifecycle().addObserver(new LifecycleEventObserver() {
            @Override
            public void onStateChanged(@NonNull LifecycleOwner source,
                    @NonNull Lifecycle.Event event) {
                 //如果生命周期為onDestory
                if (event == Lifecycle.Event.ON_DESTROY) {
                    // 清除context
                    mContextAwareHelper.clearAvailableContext();
                    //如果應用配置沒有發生改變
                    if (!isChangingConfigurations()) {
                        //清除ViewModelStore中HashMap存儲的ViewModel
                        getViewModelStore().clear();
                    }
                }
            }
        });           

總結如下:

Activity通過實作ViewModelStoreOwner接口,得到ViewModelStore,将ViewModel儲存到ViewModelStore中的HashMap中。同時使用LifeCycle監聽Activity生命周期,在onDestroy中進行ViewModel的主動釋放。

以上就是網易面試後總結的幾個要點,還不會的同學趕緊學起來吧,感謝您的閱讀,創造不易,如果您覺得本篇文章對您有幫助,請點選關注小編,您的支援就是小編創作的最大動力!

繼續閱讀