Android組件-ViewModel 源碼分析

android viewModel源碼分析

VeiwModel 簡介

	ViewModel是google官方的MVVM架構組件,目前已經集成到了最新的支持庫中了,是MVVM架構的核心組件之一,ViewModel是把View和Model關聯起來的加工廠。
	ViewModel類是被設計用來以可感知生命週期的方式存儲和管理 UI 相關數據。ViewModel中數據會一直存活即使 Activity Configuration發生變化。

viewModel可以解決以下痛點:
1.數據持久化
  在系統銷燬和重建Activity時,涉及到數據保存問題,顯示重新請求或者加載數據是不友好的.使用 Activity 的onSaveInstanceState()機制保存和恢復數據缺點明顯,只適合保存少量可以被序列化,反序列化數據,對於列表型這種龐大的數據類型並不適合,利用VeiwModel的存活機制可以解決此痛點.
2.異步請求回調易引發內存泄露
app通常需要頻繁異步請求數據,在activity或者fargment中接收數據回調,就要在銷燬時對其進行清理,避免內存泄露,隨着項目擴大,維護成本增加.但利用ViewModel處理數據,可以解決.
3.分擔UI負擔,職責分明
UI Controller 比如 Activity 、Fragment 是設計用來渲染展示數據、響應用戶行爲、處理系統的某些交互,不應處理數據邏輯,我們可以分離出數據操作的職責給 ViewModel
4.Fragment 間數據共享
比如在一個 Activity 裏有多個 Fragment,這 Fragment 之間需要做某些交互。我之前的做法是接口回調,需要統一在 Activity 裏管理,並且不可避免的 Fragment 之間還得互相持有對方的引用.
我們可以利用ViewModel的作用域機制共享數據.

public class SharedViewModel extends ViewModel {
    private final MutableLiveData<Item> selected = new MutableLiveData<Item>();

    public void select(Item item) {
        selected.setValue(item);
    }

    public LiveData<Item> getSelected() {
        return selected;
    }
}

public class MasterFragment extends Fragment {
    private SharedViewModel model;
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        model = ViewModelProviders.of(getActivity()).get(SharedViewModel.class);
        itemSelector.setOnClickListener(item -> {
            model.select(item);
        });
    }
}

public class DetailFragment extends Fragment {
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        SharedViewModel model = ViewModelProviders.of(getActivity()).get(SharedViewModel.class);
        model.getSelected().observe(this, { item ->
           // Update the UI.
        });
    }
}

下面對ViewModel相關源碼進行分析

1. ViewModel的創建

ViewModel vm = ViewModelProviders.of(getActivity()).get(getModelClass())

對上面代碼拆分:

ViewModelProvider provider = ViewModelProviders.of(getActivity());
ViewModel vm = provider.get(getModelClass());

進入ViewModelProvider.of(getActivity());

 public static ViewModelProvider of(@NonNull FragmentActivity activity) {
 		// 傳入 activity 和 null Factory
        return of(activity, null);
    }
 public static ViewModelProvider of(@NonNull FragmentActivity activity,
            @Nullable Factory factory) {
            // 獲取 application
        Application application = checkApplication(activity);
        // factory爲null , 創建默認的 AndroidViewModelFactory
        if (factory == null) {
            factory = ViewModelProvider.AndroidViewModelFactory.getInstance(application);
        }
        // 創建 ViewModelProvider(ViewModelStore , factory)
        return new ViewModelProvider(ViewModelStores.of(activity), factory);
    }

進入ViewModelProvider 的 get(class);方法

 public <T extends ViewModel> T get(@NonNull Class<T> modelClass) {
 		// 包含路徑的類名
        String canonicalName = modelClass.getCanonicalName();
        if (canonicalName == null) {
            throw new IllegalArgumentException("Local and anonymous classes can not be ViewModels");
        }
        // 根據canonicalName生成 key
        return get(DEFAULT_KEY + ":" + canonicalName, modelClass);
    }
 public <T extends ViewModel> T get(@NonNull String key, @NonNull Class<T> modelClass) {
 		// 根據 key 從mViewModelStore中獲取 ViewModel
        ViewModel viewModel = mViewModelStore.get(key);
        // viewModle不爲空,並且是modelClass類型,則返回viewModel
        if (modelClass.isInstance(viewModel)) {
            return (T) viewModel;
        } else {
            if (viewModel != null) {
            }
        }
        // 根據傳入的工廠類創建ViewModel(這裏就是viewModel的最終創建)
        viewModel = mFactory.create(modelClass);
        // 將viewModel緩存到VeiwModelStore中
        mViewModelStore.put(key, viewModel);
        return (T) viewModel;
    }

從上面源碼中可以看出,ViewModel的創建是由傳入的ViewModelFactory創建的
在這裏ViewModelFactory 是默認的

 // factory爲null , 創建默認的 AndroidViewModelFactory
  if (factory == null) {
     factory = ViewModelProvider.AndroidViewModelFactory.getInstance(application);
  }

 public static class AndroidViewModelFactory extends ViewModelProvider.NewInstanceFactory {
        private static AndroidViewModelFactory sInstance;
        // 單例
        public static AndroidViewModelFactory getInstance(@NonNull Application application) {
            if (sInstance == null) {
                sInstance = new AndroidViewModelFactory(application);
            }
            return sInstance;
        }
        private Application mApplication;
        public AndroidViewModelFactory(@NonNull Application application) {
            mApplication = application;
        }

        public <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
      		// modelClass 屬於AndroidViewModel則傳入mApplication創建AndroidViewModel
      		// 否則默認創建ViewModel
            if (AndroidViewModel.class.isAssignableFrom(modelClass)) {
                try {
                    return modelClass.getConstructor(Application.class).newInstance(mApplication);
                } catch (NoSuchMethodException e) {
                    throw new RuntimeException("Cannot create an instance of " + modelClass, e);
                } catch (IllegalAccessException e) {
                    throw new RuntimeException("Cannot create an instance of " + modelClass, e);
                } catch (InstantiationException e) {
                    throw new RuntimeException("Cannot create an instance of " + modelClass, e);
                } catch (InvocationTargetException e) {
                    throw new RuntimeException("Cannot create an instance of " + modelClass, e);
                }
            }
            return super.create(modelClass);
        }
    }

小結:
  viewModel的最終獲取是在VeiwModelProvider的get(key,modleClass)方法中,
  key是根據modelClass的全類名構建的。
  第一步:從ViewModelStore中根據key獲取與modleClass同類型的veiwModel,成功則返回
  第二步:第一步失敗,再通過ViewModelFactory創建,並緩存到viewModelStore中
所以viewModel的創建是由傳入的ViewModleFactory創建的,然後緩存到ViewModelStore中

2.界面重建,ViewModel是如何保留的?
viewModel從ViewModelStore緩存獲取,或者通過ViewModelFactory創建,
當界面重建需要複用viewModel,這時viewModel只能從viewModelStore緩存中獲取,這樣才能拿到相同viewModel。
ViewModelStore究竟幹了啥東西?

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);
    }

    public final void clear() {
        for (ViewModel vm : mMap.values()) {
            vm.onCleared();
        }
        mMap.clear();
    }
}

ViewModelStore裏面維護了一個 map, key 就是modelClass全類型構建的字符串,value就是ViewModel。
viewModelStore是通過構造器傳入VeiwModeProvider的

new ViewModelProvider(ViewModelStores.of(activity), factory)

ViewModelStores.of(activity)獲取ViewModelStore對象

public class ViewModelStores {

    private ViewModelStores() {
    }

    public static ViewModelStore of(@NonNull FragmentActivity activity) {
     // 當前activity是ViewModelStoreOwner 則從activity中獲取ViewModelStore
     // 高版本的FragmentActivity已經實現 ViewModelStoreOwner,在這裏只分析FragmentActivity
        if (activity instanceof ViewModelStoreOwner) {
            return ((ViewModelStoreOwner) activity).getViewModelStore();
        }
        return holderFragmentFor(activity).getViewModelStore();
    }
 // 當fragment是ViewModelStoreOwner 則從fragment中獲取ViewModelStore
     // 高版本的fragment已經實現 ViewModelStoreOwner,在這裏只分析Fragment
    public static ViewModelStore of(@NonNull Fragment fragment) {
        if (fragment instanceof ViewModelStoreOwner) {
            return ((ViewModelStoreOwner) fragment).getViewModelStore();
        }
        return holderFragmentFor(fragment).getViewModelStore();
    }
}

① 下面分析,FragmentActivity中ViewModelStore是如何在界面重建時保留下來的
FragmentActivity 中

public class FragmentActivity{
...
 protected void onCreate(@Nullable Bundle savedInstanceState) {
        this.mFragments.attachHost((Fragment)null);
        super.onCreate(savedInstanceState);
      // 當系統重建時,首先從NonConfigurationInstances中獲取ViewModelStore
        // NonConfigurationInstances數據是在系統因配置發生改變(屏幕旋轉),回調 onRetainNonConfigurationInstance()保存的
        // 所以界面銷燬和重建之後的viewModelStore是同一個
        FragmentActivity.NonConfigurationInstances nc = (FragmentActivity.NonConfigurationInstances)this.getLastNonConfigurationInstance();
        if (nc != null && nc.viewModelStore != null && this.mViewModelStore == null) {
            this.mViewModelStore = nc.viewModelStore;
        }
        ....
   }

 public ViewModelStore getViewModelStore() {
        if (this.getApplication() == null) {
            throw new IllegalStateException("Your activity is not yet attached to the Application instance. You can't request ViewModel before onCreate call.");
        } else {
            if (this.mViewModelStore == null) {
           		// 當系統重建時,首先從NonConfigurationInstances中獲取ViewModelStore
           		// NonConfigurationInstances數據是在系統因配置發生改變(屏幕旋轉),回調onRetainNonConfigurationInstance()保存的
           		// 所以界面銷燬和重建之後的viewModelStore是同一個
                FragmentActivity.NonConfigurationInstances nc = (FragmentActivity.NonConfigurationInstances)this.getLastNonConfigurationInstance();
                if (nc != null) {
                    this.mViewModelStore = nc.viewModelStore;
                }
                if (this.mViewModelStore == null) {
                    this.mViewModelStore = new ViewModelStore();
                }
            }

            return this.mViewModelStore;
        }
    }
// 系統因配置發生改變(屏幕旋轉),回調onRetainNonConfigurationInstance()
// 返回一個NonConfigurationInstances 對象
// 當界面再次重建時,通過getLastNonConfigurationInstance()可以獲取NonConfigurationInstances
 public final Object onRetainNonConfigurationInstance() {
        Object custom = this.onRetainCustomNonConfigurationInstance();
        // 獲取fragment 相關狀態
        FragmentManagerNonConfig fragments = this.mFragments.retainNestedNonConfig();
        if (fragments == null && this.mViewModelStore == null && custom == null) {
            return null;
        } else {
            FragmentActivity.NonConfigurationInstances nci = new FragmentActivity.NonConfigurationInstances();
            nci.custom = custom;
            // 保留viewModelStore
            nci.viewModelStore = this.mViewModelStore;
            // 保留 fragment相關狀態----->fragment 的ViewModelStore的保留就是這裏開始的
            nci.fragments = fragments;
            return nci;
        }
    }
   ...
    }

小結:
從FragmentActivity.getViewModelStore()方法中可以看出,
ViewModelStore有三個地方可以賦值:

第一個地方: 
界面重建場景使用:
在onCreate()中
通過 NonConfigurationInstances
this.mViewModelStore = FragmentActivity.getLastNonConfigurationInstance().viewModelStore;
當配置發生改變,系統銷燬界面會回調 FragmentActivity.onRetainNonConfigurationInstance(),
此時緩存了ViewModel的ViewModelStore就會記錄到NonConfigurationInstances中,
界面重建時,從NonConfigurationInstances取出ViewModelStore,所以界面銷燬前和重建後的ViewModelStore是同一個,根據傳入的modelClass構建key,就可以取出緩存的viewModel.
第二個地方:
在 getViewModelStore()中
也是 通過NonConfigurationInstances
this.mViewModelStore = FragmentActivity.getLastNonConfigurationInstance().viewModelStore;
第三個地方:
在getViewModelStore()中
第一次創建界面使用
this.mViewModelStore = new ViewModelStore();
直接創建全新的ViewModelStore對象

通過onRetainNonConfigurationInstance()和getLastNonConfigurationInstance()機制,
實現對ViewModelStore的複用,從而保留VeiwModel對象

②下面分析Fragment中,viewModelStore是如何在界面重建保留下來的

public class ViewModelStores {

    private ViewModelStores() {
    }
    ...
 	// 當fragment是ViewModelStoreOwner 則從fragment中獲取ViewModelStore
    // 高版本的fragment已經實現 ViewModelStoreOwner,在這裏只分析Fragment
    public static ViewModelStore of(@NonNull Fragment fragment) {
        if (fragment instanceof ViewModelStoreOwner) {
            return ((ViewModelStoreOwner) fragment).getViewModelStore();
        }
        return holderFragmentFor(fragment).getViewModelStore();
    }
}

Fragment中

public class Fragment {
...
 public ViewModelStore getViewModelStore() {
        if (this.getContext() == null) {
            throw new IllegalStateException("Can't access ViewModels from detached fragment");
        } else {
            if (this.mViewModelStore == null) {
                this.mViewModelStore = new ViewModelStore();
            }
            return this.mViewModelStore;
        }
    }
    ...
    }

在fragment中貌似只有getViewModelStore()方法對mViewModelStore賦值.
前面分析FragmentActivity時,我們知道onRetainNonConfigurationInstance()有對fargment相關狀態進行保留

public final Object onRetainNonConfigurationInstance() {
        Object custom = this.onRetainCustomNonConfigurationInstance();
        // 獲取fragment 相關狀態
        FragmentManagerNonConfig fragments = this.mFragments.retainNestedNonConfig();
        if (fragments == null && this.mViewModelStore == null && custom == null) {
            return null;
        } else {
            FragmentActivity.NonConfigurationInstances nci = new FragmentActivity.NonConfigurationInstances();
            nci.custom = custom;
            // 保留viewModelStore
            nci.viewModelStore = this.mViewModelStore;
            // 保留 fragment相關狀態----->fragment 的ViewModelStore的保留就是這裏開始的
            nci.fragments = fragments;
            return nci;
        }
    }

進入FragmentController.retainNestedNonConfig();

    public FragmentManagerNonConfig retainNestedNonConfig() {
    	// this.mHost.mFragmentManager是 FragmentManagerImpl
        return this.mHost.mFragmentManager.retainNonConfig();
    }
	final class FragmentManagerImpl extends FragmentManager implements Factory2 {
	...
		FragmentManagerNonConfig retainNonConfig() {
       	 	setRetaining(this.mSavedNonConfig);
       	 	// FragmentManagerNonConfig mSavedNonConfig;
       	 	// 返回 成員變量 mSavedNonConfig ---> 存放了mViewModelStores
        	return this.mSavedNonConfig;
    	}
    ...
    }
public class FragmentManagerNonConfig {
    private final List<Fragment> mFragments;
    private final List<FragmentManagerNonConfig> mChildNonConfigs;
    private final List<ViewModelStore> mViewModelStores;

    FragmentManagerNonConfig(List<Fragment> fragments, List<FragmentManagerNonConfig> childNonConfigs, List<ViewModelStore> viewModelStores) {
        this.mFragments = fragments;
        this.mChildNonConfigs = childNonConfigs;
        this.mViewModelStores = viewModelStores;
    }
    ...
}

可以看到FragmentManagerNonConfig mSavedNonConfig 裏面存放了fragment列表和對應的viewModelStore,還有childFragment 的 FragmentManagerNonConfig
mSavedNonConfig是在FragmentActivity. onSaveInstanceState(Bundle outState)進行賦值的

 protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        this.markFragmentsCreated();
        //final FragmentController mFragments = FragmentController.createController(new FragmentActivity.HostCallbacks());
        Parcelable p = this.mFragments.saveAllState();
        if (p != null) {
            outState.putParcelable("android:support:fragments", p);
        }
        ...
    }

  public class FragmentController{
 		public Parcelable saveAllState() {
        	return this.mHost.mFragmentManager.saveAllState();
   	 	}
   }
   final class FragmentManagerImpl extends FragmentManager implements Factory2 {
		Parcelable saveAllState() {
        ...
        if (this.mActive != null && this.mActive.size() > 0) {
           ...
            if (!haveFragments) {
                if (DEBUG) {
                    Log.v("FragmentManager", "saveAllState: no fragments!");
                }
                return null;
            } else {
        		...
        		// 這裏 對mSavedNonConfig 進行賦值
        		// mSavedNonConfig會在 FragmentActivity.onRetainNonConfigurationInstance()保留
                this.saveNonConfig();
                return fms;
            }
        } else {
            return null;
        }
    }
// mSavedNonConfig賦值
 void saveNonConfig() {
        ArrayList<Fragment> fragments = null;
        ArrayList<FragmentManagerNonConfig> childFragments = null;
        ArrayList<ViewModelStore> viewModelStores = null;
        if (this.mActive != null) {
        // 遍歷活躍的fragment
            for(int i = 0; i < this.mActive.size(); ++i) {
                Fragment f = (Fragment)this.mActive.valueAt(i);
                if (f != null) {
                // 當前fragment 是否保留實例
                    if (f.mRetainInstance) {
                        if (fragments == null) {
                            fragments = new ArrayList();
                        }
                        // 添加保留實例的fragment
                        fragments.add(f);
              			...
                    }
                    // childFragmen的相關狀態
                    FragmentManagerNonConfig child;
                    if (f.mChildFragmentManager != null) {
                  		// 保存childFragment 的狀態
                        f.mChildFragmentManager.saveNonConfig();
                        child = f.mChildFragmentManager.mSavedNonConfig;
                    } else {
                        child = f.mChildNonConfig;
                    }

                    int j;
                    if (childFragments == null && child != null) {
                        childFragments = new ArrayList(this.mActive.size());
						// 這裏是爲了 child在childFragments位置與當前f位置對應
                        for(j = 0; j < i; ++j) {
                            childFragments.add((Object)null);
                        }
                    }

                    if (childFragments != null) {
                        childFragments.add(child);
                    }

                    if (viewModelStores == null && f.mViewModelStore != null) {
                        viewModelStores = new ArrayList(this.mActive.size());
						// 這裏是爲了 f.mViewModelStore在viewModelStores位置與當前f位置對應
                        for(j = 0; j < i; ++j) {
                            viewModelStores.add((Object)null);
                        }
                    }
                    // 添加mViewModelStore
                    if (viewModelStores != null) {
                        viewModelStores.add(f.mViewModelStore);
                    }
                }
            }
        }

        if (fragments == null && childFragments == null && viewModelStores == null) {
            this.mSavedNonConfig = null;
        } else {
        	// mSavedNonConfig 賦值
            this.mSavedNonConfig = new FragmentManagerNonConfig(fragments, childFragments, viewModelStores);
        }

    }

}

現在我們已經知道FragmentActivity銷燬時,在onRetainNonConfigurationInstance()中會保留fragmnet的相關狀態,包括ViewModelStore。
接下來分析界面重建時,是如何將fragment 的ViewModelStore取出的.

 protected void onCreate(@Nullable Bundle savedInstanceState) {
        this.mFragments.attachHost((Fragment)null);
        super.onCreate(savedInstanceState);
        // 界面重建時,取出保留的狀態
        FragmentActivity.NonConfigurationInstances nc = (FragmentActivity.NonConfigurationInstances)this.getLastNonConfigurationInstance();
        if (nc != null && nc.viewModelStore != null && this.mViewModelStore == null) {
        // 取出viewModelStore
            this.mViewModelStore = nc.viewModelStore;
        }

        if (savedInstanceState != null) {
            Parcelable p = savedInstanceState.getParcelable("android:support:fragments");
            // 恢復fragment的狀態
            this.mFragments.restoreAllState(p, nc != null ? nc.fragments : null);
           	....
            }
        }
}

public class FragmentController {
	public void restoreAllState(Parcelable state, FragmentManagerNonConfig nonConfig) {
        this.mHost.mFragmentManager.restoreAllState(state, nonConfig);
    }final class FragmentManagerImpl extends FragmentManager implements Factory2 {
	void restoreAllState(Parcelable state, FragmentManagerNonConfig nonConfig) {
        if (state != null) {
            FragmentManagerState fms = (FragmentManagerState)state;
            if (fms.mActive != null) {
                List<FragmentManagerNonConfig> childNonConfigs = null;
                List<ViewModelStore> viewModelStores = null;
                List nonConfigFragments;
                int count;
                int i;
                Fragment f;
                if (nonConfig != null) {
                    nonConfigFragments = nonConfig.getFragments();
                    childNonConfigs = nonConfig.getChildNonConfigs();
                    viewModelStores = nonConfig.getViewModelStores();
                    count = nonConfigFragments != null ? nonConfigFragments.size() : 0;
                    // 遍歷可保留的fragment --->fragment.setRetainInstance(true)
                    for(i = 0; i < count; ++i) {
                    // 取出fragment
                        f = (Fragment)nonConfigFragments.get(i);
                        ...
                        int index;
                        // 計算當前f 對應fms.mActive位置
                        for(index = 0; index < fms.mActive.length && fms.mActive[index].mIndex != f.mIndex; ++index) {
                            ;
                        }
                        ...
                        // 取出當前fragment所保留的狀態
                        FragmentState fs = fms.mActive[index];
                        // 將當前fragment保存到狀態對象中,下面通過FragmentState獲取fragment時直接返回
                        fs.mInstance = f;
                        ...
                    }
                }
                // 初始化 mActive
                this.mActive = new SparseArray(fms.mActive.length);
                int i;
                for(i = 0; i < fms.mActive.length; ++i) {
                    FragmentState fs = fms.mActive[i];
                    if (fs != null) {
                    // 取出 childFragment 保留的狀態
                        FragmentManagerNonConfig childNonConfig = null;
                        if (childNonConfigs != null && i < childNonConfigs.size()) {
                            childNonConfig = (FragmentManagerNonConfig)childNonConfigs.get(i);
                        }
                        // 取出Fragment保留的ViewModelStore
                        ViewModelStore viewModelStore = null;
                        if (viewModelStores != null && i < viewModelStores.size()) {
                            viewModelStore = (ViewModelStore)viewModelStores.get(i);
                        }
                        // 構建fragment,fs存在fragment就返回,否則新建fragment實例
                        Fragment f = fs.instantiate(this.mHost, this.mContainer, this.mParent, childNonConfig, viewModelStore);
                        // 將fragment 保存到mActive中
                        this.mActive.put(f.mIndex, f);
                        fs.mInstance = null;
                    }
                }
                ...
            }
        }
    }

final class FragmentState implements Parcelable {
public Fragment instantiate(FragmentHostCallback host, FragmentContainer container, Fragment parent, FragmentManagerNonConfig childNonConfig, ViewModelStore viewModelStore) {
		// 當前Fragment mInstance是否爲空 
		// fragment.setRetainInstance(true)這種情況  mInstance不爲空,會複用銷燬前所保留的fragment
        if (this.mInstance == null) {
            Context context = host.getContext();
            ...
            // mInstance創建新實例
            if (container != null) {
                this.mInstance = container.instantiate(context, this.mClassName, this.mArguments);
            } else {
                this.mInstance = Fragment.instantiate(context, this.mClassName, this.mArguments);
            }
        }
       
        this.mInstance.mChildNonConfig = childNonConfig;
        // 複用viewModelStore
        this.mInstance.mViewModelStore = viewModelStore;
        return this.mInstance;
    }
}

到這裏 fragment的ViewModelStore複用就分析完了
小結:
fragment的viewModelstore複用也是通過FragmentActivity的onRetainNonConfigurationInstance()和getLastNonConfigurationInstance()機制實現的。
界面銷燬時:
在FragmentActivity.onSaveInstance()中對Fragment的相關狀態mSavedNonConfig(保留了ViewModelStore等狀態)進行保留,然後在onRetainNonConfigurationInstance()中取出mSavedNonConfig保存到 FragmentActivity.NonConfigurationInstances 中,
界面重建時:
在onCreat()中恢復

至此,viewModel源碼分析結束
寫博客的目的是爲了加深印象,梳理思路,也爲了方便後面複習。
文章未經仔細梳理,勉強能看…

發佈了38 篇原創文章 · 獲贊 8 · 訪問量 8620
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章