Android8.1 推荐设计模式

Android应用不同于一般的应用,组件的概念非常重要,甚至开发这不用去理会进程的概念。我们需要的是界面的无缝跳转与返回。而界面本身及其不稳定,旋转屏幕等操作Activity就会被销毁并且重新创建,所以在Activity中不能存储数据,所有存在的数据只有一个目的->显示。另外,为了保持良好的工程结构,数据最好由统一的模块管理,界面有统一的另外一个模块管理(防止界面元素太多,MVP模式中的Present,先不考虑)。  数据管理模块期望有以下几个功能。
  • 可以获取需要的数据。
  • 具有缓存功能,不用每次都去持久化方式(数据库、文件、网络)存取。
  • 可以监听数据的变化。
  • 与Activity或者Fragment的生命周期分离,同时也可以关注其生命周期。

为什么需要以上的功能?主要有两点1.数据的获取以显示数据  2.生命周期匹配以防止内存泄漏。

为了完成以上三点的功能,我们需要什么?

Loaders,在非主线程完成需要的数据加载工作之后将数据更新到界面,并时刻监听数据。同时在onDestroy中释放资源。

public class Loader extends AsyncTask{
    T startLoading(){
       T = loadData();
       T.observe();
       return T;  
    }
    stopLoading(){
        T.unobserve();
        T = null;
    }
}

这是我们最先想到的,也是传统的方式,但是这种方式,也就是LoaderManager在8.1中被弃用。我们可以通过这种方式完成很多功能,其缺点我现在感觉到的只有开发上面的问题,与Activity Fragment都耦合比较密切。 为了完成所需要的功能,需要重写许多方法。

在8.1或者更高的版本中,google官方推荐了ViewModel模块用来存储数据。独立于Activity的生命周期又可以感知其生命周期。先来看一下ViewModel是什么样子:

public abstract class ViewModel {
    /**
     * This method will be called when this ViewModel is no longer used and will be destroyed.
     * 

* 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() { } }

ViewModel只有一个接口,生命周期如下:  那么,ViewModel会不会在Activity被销毁时重建,或者还是会保留数据。

Android8.1 推荐设计模式_第1张图片

正如官方所说,是保留数据:

Android8.1 推荐设计模式_第2张图片

在Activity被销毁后,还是会重新恢复自己的对象。那么这是如何做到的呢? 我们从创建过程开始看起:

ViewModelProviders.of(this).get(UserProfileViewModel.class);

ViewModelProviders.of()  返回ViewModelProvider,两种情况:

return new ViewModelProvider(ViewModelStores.of(activity), factory);
return new ViewModelProvider(ViewModelStores.of(fragment), factory);

factory相同,都使用默认的Factory类。接下来看一下ViewModelStores,对于activity和fragment又有什么处理。

 public static ViewModelStore of(Fragment fragment) {
        return holderFragmentFor(fragment).getViewModelStore();
 }

public static ViewModelStore of(FragmentActivity activity) { return holderFragmentFor(activity).getViewModelStore(); }

在这里需要在ViewModelStores中获取ViewModelStore。

HolderFragment.holderFragmentFor,根据传入的activity或者fragment返回了一个Fragment的子类,HolderFragment。

    /**
     * @hide
     */
    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
    public static HolderFragment holderFragmentFor(FragmentActivity activity) {
        return sHolderFragmentManager.holderFragmentFor(activity);
    }

    /**
     * @hide
     */
    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
    public static HolderFragment holderFragmentFor(Fragment fragment) {
        return sHolderFragmentManager.holderFragmentFor(fragment);
    }

HolderFragment里面重点就是一个HolderFragmentManager,在这里还维护了一个静态的manager。这个manager里面有什么?

    static class HolderFragmentManager {
        private Map mNotCommittedActivityHolders = new HashMap<>();
        private Map mNotCommittedFragmentHolders = new HashMap<>();

        private ActivityLifecycleCallbacks mActivityCallbacks =
                new EmptyActivityLifecycleCallbacks() {
                    @Override
                    public void onActivityDestroyed(Activity activity) {
                        HolderFragment fragment = mNotCommittedActivityHolders.remove(activity);
                        if (fragment != null) {
                            Log.e(LOG_TAG, "Failed to save a ViewModel for " + activity);
                        }
                    }
                };

        private boolean mActivityCallbacksIsAdded = false;

        private FragmentLifecycleCallbacks mParentDestroyedCallback =
                new FragmentLifecycleCallbacks() {
                    @Override
                    public void onFragmentDestroyed(FragmentManager fm, Fragment parentFragment) {
                        super.onFragmentDestroyed(fm, parentFragment);
                        HolderFragment fragment = mNotCommittedFragmentHolders.remove(
                                parentFragment);
                        if (fragment != null) {
                            Log.e(LOG_TAG, "Failed to save a ViewModel for " + parentFragment);
                        }
                    }
                };

两个map容器,两个回调,一个标志。然后看一下holderfragmentfor方法

        HolderFragment holderFragmentFor(FragmentActivity activity) {
            FragmentManager fm = activity.getSupportFragmentManager();
            HolderFragment holder = findHolderFragment(fm);
            if (holder != null) {
                return holder;
            }
            holder = mNotCommittedActivityHolders.get(activity);
            if (holder != null) {
                return holder;
            }

            if (!mActivityCallbacksIsAdded) {
                mActivityCallbacksIsAdded = true;
                activity.getApplication().registerActivityLifecycleCallbacks(mActivityCallbacks);
            }
            holder = createHolderFragment(fm);
            mNotCommittedActivityHolders.put(activity, holder);
            return holder;
        }

        HolderFragment holderFragmentFor(Fragment parentFragment) {
            FragmentManager fm = parentFragment.getChildFragmentManager();
            HolderFragment holder = findHolderFragment(fm);
            if (holder != null) {
                return holder;
            }
            holder = mNotCommittedFragmentHolders.get(parentFragment);
            if (holder != null) {
                return holder;
            }

            parentFragment.getFragmentManager()
                    .registerFragmentLifecycleCallbacks(mParentDestroyedCallback, false);
            holder = createHolderFragment(fm);
            mNotCommittedFragmentHolders.put(parentFragment, holder);
            return holder;
        }
完犊子,这个activity需要时fragmentactivity呀,也没有报错,结果也是对的,先假设这里对吧,标红一下。

这里看逻辑还得把另外两个方法也粘过来。

        private static HolderFragment findHolderFragment(FragmentManager manager) {
            if (manager.isDestroyed()) {
                throw new IllegalStateException("Can't access ViewModels from onDestroy");
            }

            Fragment fragmentByTag = manager.findFragmentByTag(HOLDER_TAG);
            if (fragmentByTag != null && !(fragmentByTag instanceof HolderFragment)) {
                throw new IllegalStateException("Unexpected "
                        + "fragment instance was returned by HOLDER_TAG");
            }
            return (HolderFragment) fragmentByTag;
        }

        private static HolderFragment createHolderFragment(FragmentManager fragmentManager) {
            HolderFragment holder = new HolderFragment();
            fragmentManager.beginTransaction().add(holder, HOLDER_TAG).commitAllowingStateLoss();
            return holder;
        }

先给个manager看看有没有用指定的这个tag创建的holderfragment。当然没有,第一次。然后继续看看map里边有没有,很显然,也没有。。。。继续。。先不管这个callback,我们去创建一个holderfragment,new一个实例,通过标签和manager加到栈里面去,然后也放到map里边。

这个holderfragment我理解就是提供这个viewModelStore,为了让别的组建都有这个东东,好方便去存咱们的viewModel  现在有了provider了,然后就factory实例化出来吧。这个store实际上是在一个已经加到栈中的holderfragment存储着,就经验来说这个是不会随activity销毁的,讲真。再向下就太多了,实验一下就结束。

我们在用fragment的时候需要用transcation去动态的控制,add replace remove 所以这个是独立于activity的,viewmodel也就存储下来了。

看了这么多,也就是为了知道为什么viewModel可以把数据存下来。而且现在也只是大概知道,还不可避免有一些理解上的误差。

继续。

接下来就是通知数据的变更,只需要在我们的数据外套一层,LiveData, 并且在初始化viewModel的时候注册监听:

viewModel.getUser().observe(this, user -> {
      // update UI
    });

这里有个重点,LiveData是可以自己处理生命周期变化的,具体就是lifeCycle这套机制和support中的activity结合起来实现的,虽然有一些小问题,但是不会妨碍我们使用,我暂时不想知道他们是如何去处理这些生命周期的问题的,我想知道,什么样子的数据变化会引起这个回调的调用。

要知道的是,我们的数据在viewModel中虽然可以保持很长时间,但依旧是暂时的,我们需要从数据库中查找,并且可能会在网络上更新,这些如何处理? google提供的这个结构中提供了一个Room的数据库封装,但是这还不是我想关注的重点。我想我需要先梳理一下我的关注点:

1. 我需要界面显示数据,这个数据来自数据库。

2.我需要可以交互触发网络更新,更新的数据存入数据库,并通知界面。

3.如果更新失败,界面也需要知道失败的信息。

4.后台会有一个jobservice在定期的更新,我不能让前台的更新和这个服务冲突。

如果我前台更新是调用jobservice一样的服务,那么我只能通过contentobserver去监听数据库或者服务发送本地的广播给我,如果更新失败,只能是使用广播,所以,更新的接口都是相同的,并且解决掉冲突不要同时调用,前台的时候就使用viewModel这一套。

LiveData是可以setData的,一设置数据肯定就变了呀,就直接回调了,这是个不错的方式。

单一职责,我们获取数据需要封装另外一个类。

接下来的任务就只需要熟悉这些借口,做一些实验然后和自己的需求挂钩。

实际上,我不想使用ViewModel,我只是想模仿这套机制,无所谓了,可以尝试一下。


你可能感兴趣的:(Android)