美文网首页
Android Architecture Componets -

Android Architecture Componets -

作者: 康迪437 | 来源:发表于2017-11-09 16:59 被阅读0次

    ViewModel

    /**
    ViewModel是一个负责准备和管理Activity或Fragment数据的类。
    它还处理Activity / Fragment与其他应用程序的通信 (例如调用业务逻辑类)
    ViewModel会在一个关联的范围内(activity 或者 fragment)创建,只要activity或fragment是活着的,它将被保留.
    换句话说,这意味着如果它的所有者由于配置改变被销毁了(例如旋转), ViewModel不会被销毁,所有者的新实例将重新连接到现有的ViewModel。
    ViewModel的目的是获取并保存Activity或Fragment所需的信息. Activity或Fragment应该能够观察ViewModel中的变化。ViewModel通常通过LiveData或Android DataBinding公开这些信息。 你也可以使用你喜欢的框架的任何可观察性构造。
    ViewModel唯一的职责就是管理用户界面的数据, 它不应该访问您的视图层次结构或持有引用回到Activity或Fragment.
    
    典型的用法:
     * public class UserActivity extends Activity {
     *
     *     {@literal @}Override
     *     protected void onCreate(Bundle savedInstanceState) {
     *         super.onCreate(savedInstanceState);
     *         setContentView(R.layout.user_activity_layout);
     *         final UserModel viewModel = ViewModelProviders.of(this).get(UserModel.class);
     *         viewModel.userLiveData.observer(this, new Observer<User>() {
     *            {@literal @}Override
     *             public void onChanged(@Nullable User data) {
     *                 // update ui.
     *             }
     *         });
     *         findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
     *             {@literal @}Override
     *             public void onClick(View v) {
     *                  viewModel.doAction();
     *             }
     *         });
     *     }
     * }
     
     ViewModel:
      * public class UserModel extends ViewModel {
     *     public final LiveData&lt;User&gt; userLiveData = new LiveData<>();
     *
     *     public UserModel() {
     *         // trigger user load.
     *     }
     *
     *     void doAction() {
     *         // depending on the action, do necessary business logic calls and update the
     *         // userLiveData.
     *     }
     * }
    ViewModels也可以用作Activity中的不同Fragment之间的通信层。 每个Fragment可以通过他们的Activity使用相同的密钥来获取ViewModel。这允许Fragment之间以分离的方式进行通信,使得它们不需要直接与另一个Fragment进行通信。
     * public class MyFragment extends Fragment {
     *     public void onStart() {
     *         UserModel userModel = ViewModelProviders.of(getActivity()).get(UserModel.class);
     *     }
     * }
    */
    public abstract class ViewModel {
        /**
         * 这个ViewModel被销毁时调用
         * <p>
         * It is useful when ViewModel observes some data and you need to clear this subscription to
         * prevent a leak of this ViewModel.
         */
        @SuppressWarnings("WeakerAccess")
        protected void onCleared() {
        }
    }
    
    ViewModelProviders.of(this).get(MyViewModel::class.java)
    
    // ViewModelProviders
    @MainThread
    public static ViewModelProvider of(@NonNull FragmentActivity activity) {
        // 确保单例对象 sDefaultFactory 实例存在
        initializeFactoryIfNeeded(checkApplication(activity));
        return new ViewModelProvider(ViewModelStores.of(activity), sDefaultFactory);
    }
    // ViewModelStores
    @MainThread
    public static ViewModelStore of(@NonNull FragmentActivity activity) {
        // 创建HolderFragment 并且添加到Activity当中, 返回ViewModelStore
        return HolderFragment.holderFragmentFor(activity).getViewModelStore();
    }
    // HolderFragment
    
    // getViewModelStore() 返回该实例
    private ViewModelStore mViewModelStore = new ViewModelStore();
    
    private static final HolderFragmentManager sHolderFragmentManager = new HolderFragmentManager();
    
    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
    public static HolderFragment holderFragmentFor(FragmentActivity activity) {
        return sHolderFragmentManager.holderFragmentFor(activity);
    }
    
    // HolderFragmentManager
    HolderFragment holderFragmentFor(FragmentActivity activity) {
        FragmentManager fm = activity.getSupportFragmentManager();
        // 根据 HOLDER_TAG 寻找 HolderFragment
        HolderFragment holder = findHolderFragment(fm);
        if (holder != null) {
            return holder;
        }
        // mNotCommittedActivityHolders 保存已经执行了add操作, 但是没有添加进去的 Fragment
        holder = mNotCommittedActivityHolders.get(activity);
        if (holder != null) {
            return holder;
        }
    
        if (!mActivityCallbacksIsAdded) {
            mActivityCallbacksIsAdded = true;
            // 在activity的 onDestroy()方法中 mNotCommittedActivityHolders释放引用
            activity.getApplication().registerActivityLifecycleCallbacks(mActivityCallbacks);
        }
        // 创建 HolderFragment 添加到当前 Activity 当中
        holder = createHolderFragment(fm);
        // 上面方法执行了 fragment 的 add以及commit 操作, 到HolderFragment 真正添加到activity之前记录
        mNotCommittedActivityHolders.put(activity, holder);
        return holder;
    }
    
    // HolderFragment
    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        sHolderFragmentManager.holderFragmentCreated(this);
    }
    // HolderFragmentManager
    void holderFragmentCreated(Fragment holderFragment) {
        // 如果是在Fragment中嵌套Fragment, 该返回不为空, 这里只讨论Activity的情况
        Fragment parentFragment = holderFragment.getParentFragment();
        if (parentFragment != null) {
            mNotCommittedFragmentHolders.remove(parentFragment);
            parentFragment.getFragmentManager().unregisterFragmentLifecycleCallbacks(
                    mParentDestroyedCallback);
        } else {
            // 执行 onCreate() 说明HolderFragment以及添加到Activity, 可以释放引用了
            mNotCommittedActivityHolders.remove(holderFragment.getActivity());
        }
    }
    
    @NonNull
    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");
        }
        return get(DEFAULT_KEY + ":" + canonicalName, modelClass);
    }
    @NonNull
    @MainThread
    public <T extends ViewModel> T get(@NonNull String key, @NonNull Class<T> modelClass) {
        ViewModel viewModel = mViewModelStore.get(key);
    
        if (modelClass.isInstance(viewModel)) {
            //noinspection unchecked
            return (T) viewModel;
        } else {
            //noinspection StatementWithEmptyBody
            if (viewModel != null) {
                // TODO: log a warning.
            }
        }
        // 根据反射创建实例
        viewModel = mFactory.create(modelClass);
        // 存入 viewModel实例
        mViewModelStore.put(key, viewModel);
        //noinspection unchecked
        return (T) viewModel;
    }
    

    到这里会发现只是将一个毫不起眼的HolderFragment添加到Activity,并且利用HolderFragment中的ViewModelStore中的Map保存了 自定义ViewModel实例.

    HolderFragment是如何在在Activity配置变更被销毁时继续持有viewModel的?

    // HolderFragment
    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // 这行代码上面已经分析过了
        sHolderFragmentManager.holderFragmentCreated(this);
    }
    @Override
    public void onDestroy() {
        super.onDestroy();
        // 调用ViewModel的
        mViewModelStore.clear();
    }
    
    // ViewModelStore
    public final void clear() {
        for (ViewModel vm : mMap.values()) {
            // 空方法, 继承给开发者用, 做释放等操作
            vm.onCleared();
        }
        // 清空map, 也就是 释放ViewModel数据
        mMap.clear();
    }
    

    上面也并没有什么特殊的操作, 并且在onDestroy() 中释放了 viewModel, 那么在 Activity例如旋转的时候会调用onDestroy(), 跟着 Fragment的 onDestroyView(), onDestroy(), onDetach() 会依次触发. HolderFragment为什么不会调用 onDestroy()?

    关键来了!!

    // 关键就在 HolderFragment的构造方法中
    public HolderFragment() {
        setRetainInstance(true);
    }
    // Fragment
    /**
     控制是否在重新创建Activity(例如配置更改)中保留Fragment实例。这只能用于不在back stack中的Fragment。 如果设置,则在 recreate Activity时,Fragment生命周期将略有不同:
     onDestroy() 将不会被调用 (但onDetach() 仍然会,因为片段正在从它当前的活动分离). onCreate(Bundle)将不会被调用,因为片段不被重新创建。onAttach(Activity) 和 onActivityCreated(Bundle)仍然被调用。
     */
    public void setRetainInstance(boolean retain) {
        mRetainInstance = retain;
    }
    

    所以在ViewModel类的注释中有一段

    ViewModel唯一的职责就是管理用户界面的数据, 它不应该访问您的视图层次结构或持有引用回到Activity或Fragment.

    一旦ViewModel持有了Activity, 并且在旋转时, 新的Activity需要创建, 而旧的Activity需要被释放. 但是被ViewModel持有而释放不了就有可能造成内存泄漏.

    相关文章

      网友评论

          本文标题:Android Architecture Componets -

          本文链接:https://www.haomeiwen.com/subject/utlmmxtx.html