Android Jetpack架构组件Lifecycle+ViewModel+ LiveData

什么是Android Jetpack?

Android Jetpack是谷歌在2018年I/O开发者大会上推出的新一代组件、工具和架构指导,旨在加快开发者的 Android 应用开发速度。 ——官方介绍网站

Android Jetpack 组件是库的集合,这些库是为协同工作而构建的,不过也可以单独采用,同时利用 Kotlin 语言功能帮助您提高工作效率。可全部使用,也可混合搭配!

Android Jetpack组件的优势:

Jetpack推出的主要目的是为了能够让开发者更加快速、方便以及高质量的完成产品开发

  • 轻松管理应用程序的生命周期,后台任务的管理,导航的处理等等
  • 利用Jetpack组件进行开发可以有效减少内存溢出、崩溃的概率,提升应用开发的质量

Jetpack组件主要分为四个方向:基础,架构,行为和UI。详情见下

Android Jetpack组件推荐的使用项目架构

上面架构组件的功能如下:

  • Activity和Fragment负责产品与用户的交互
  • ViewModel作为数据的存储和驱动
  • Resposity负责调度数据的获取(Room储存本地序列化的数据,Retrofit获取远程数据的数据)

ViewModel+ LiveData

ViewModel的优点:
  • 解决了运行中断和界面重建时的数据保存问题 (横竖屏切换,导致Activity销毁并重新创建时,ViewMode仍然可以保留之前读取到的数据不会因为Activity的销毁而丢失,这样我们无需额外再浪费资源去再次请求数据)
  • 配合LiveData实时获取最新数据
  • 实现Activity中Fragment之间的数据交互(数据共享)
  • 数据和界面的分离,使数据驱动界面 (ViewModel类被设计为通过lifecycle感知的方式存储和管理UI相关数据)
ViewModel的生命周期:
  • ViewModel对象的范围是在获取ViewModel时传递给ViewModelProvider的Lifecycle生命周期
  • ViewModel在内存中直到Activity销毁或Fragment被移除
  • 系统首次调用活动对象的onCreate()方法时,通常会请求ViewModel
  • 系统可能会在整个活动的整个生命周期中多次调用onCreate(),例如当设备屏幕旋转时
  • ViewModel从第一次请求ViewModel直到活动完成并销毁时存在

ViewMode在其生命周期的范围内会一直保存在内存中,所以横竖屏切换 当切换手机横竖屏后,Activity会destroy并重新onCreate来重构当前界面,生命周期再次重新触发onCreate,但是ViewMode 并没有重新执行获取数据的操作。

由于 ViewModel 生命周期可能长与 activity 生命周期,所以为了避免内存泄漏 Google 禁止在 ViewModel 中持有 Context 或 activity 或 view 的引用。
如果有些请求数据的情况必须用到Context,在继承ViewMode的时候,可以改为继承AndroidViewMode,这个类会返回一个带有Context的构造函数。

ViewMode执行onCleared操作,这个是ViewMode的一个回调,表明当前Activity要彻底关闭,ViewMode需要做一些回收清理的操作


LiveData

优点:

  • 确保UI界面的数据状态
  • 没有内存泄漏,不会因为Activity的不可见导致Crash
  • 一个存放可被观察的数据持有类,但与一般的被观察者不同的是,它是有生命周期感知功能,解决了android开发者需要去手动处理生命周期的痛点。
  • 共享资源
 viewMode.getUserLiveData().observe(this, new Observer<String>() {
            @Override
            public void onChanged(String users) {
                fragment2.setText("fragment2==\n" + users);
            }
        });

LiveData是一个observable数据持有类,LiveData是生命周期感知的,这意味着它跟随其他应用程序组件(如activities, fragments, or services)的生命周期。这种感知能力确保LiveData只更新处于活跃生命周期状态的应用程序组件
LiveData与一个Observer关联,如果观察者的生命周期处于STARTED或RESUMED状态,则表示观察者处于活动状态。LiveData只通知活跃的观察者做更新。注册到LiveData对象中的不活跃的观察者则得不到数据更新的通知。

注册一个observer并与实现了LifecycleOwner接口的对象配对。这种关系允许当相应的Lifecycle对象的状态改变为DESTROYED时,观察者被移除

利用ViewMode(配合LiveData实时获取最新数据)进行Fragment之间的数据交互
public class OneFragment extends BaseFragment {
    @BindView(R2.id.fragment2)
    TextView fragment2;
    @Override
    protected int initLayout() {
        return R.layout.fragment_detail;

    }
    @Override
    protected void initView(View view) {
        //绑定ViewMode的selected的值,当有更新时通知DetailFragment
        SharedViewModel viewMode = ViewModelProviders.of(getActivity()).get(SharedViewModel.class);
        viewMode.getUserLiveData().observe(this, new Observer<String>() {
            @Override
            public void onChanged(String users) {
                fragment2.setText("fragment2==\n" + users);
            }
        });


    }

}


public class TwoFragment extends BaseFragment {
    @BindView(R2.id.fragment1)
    TextView fragment1;


    SharedViewModel viewMode;

    @Override
    protected void initView(View view) {
        //注意:这里ViewModelProviders.of(getActivity())这里的参数需要是Activity,而不能是Fragment,否则收不到监听
        viewMode = ViewModelProviders.of(getActivity()).get(SharedViewModel.class);

        fragment1.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //当点击某一个item的时候,更新viewmode中的selected的值
                viewMode.select("fragment1点击后,更新viewmode中的值,fragment2 里面的数据同步更新");
            }
        });
    }

    @Override
    protected void initData() {
        viewMode.getUserLiveData().observe(this, new Observer<String>() {
            @Override
            public void onChanged(String users) {
                Log.w("TAG", "====" + users);
            }
        });

    }

    @Override
    protected int initLayout() {
        return R.layout.fragment_master;
    }
}





public class SharedViewModel extends AndroidViewModel {
    //userLiveData保存的是被选中的item的状态或者数据
    private MutableLiveData<String> userLiveData;


    public MutableLiveData<String> getUserLiveData() {
        if (userLiveData == null) {
            Log.w("TAG", "SharedViewModel-getUserLiveData");
            userLiveData = new MutableLiveData<>();

        }
        return userLiveData;
    }

    //主要通过masterFragment进行调用交互,用来更新selected中的值
    public void select(String item) {
        userLiveData.setValue(item);
    }


    public SharedViewModel(@NonNull Application application) {
        super(application);
    }

    /**
     * 这里可以执行一些资源释放、数据清理的操作
     * ViewMode会执行onCleared操作,这个是ViewMode的一个回调,
     * 表明当前Activity要彻底关闭,ViewMode需要做一些回收清理的操作,如下代码:
     */
    @Override
    protected void onCleared() {
        super.onCleared();

    }
}


上述代码的逻辑很简单,OneFragment与TwoFragment并不直接进行交互,而是各自与ViewMode进行交互,OneFragment用来更新维护ViewMode中的数据,TwoFragment可以收到来自ViewMode中数据更新的通知。这样便达到了两个frangment之间的数据通信。

LifeCycles原理

Lifecycles是生命周期管理组件 另一组件的生命周期状态(随着Activity和Fragment)的变化而执行动作,support 26 以上的兼容包中的AppCompatActivity与Fragment中默认已实现了LifeCycleOwner接口,保证了LiveData及ViewModel具备了生命周期感知与内存缓存的能力。

场景使用:在平时的开发过程中,我们难免有些逻辑的执行是和UI的生命周期相结合的,需要在特定的生命周期中执行相应的方法,我们平时做的可能就是在View中的每个周期调用Present中获取数据的方法,然后在调用View的回调接口更新UI,但现在使用Lifecycles可以使用注解和观察的模式自动调用Observe中定义好的方法。

     //谁观察生命周期  就注册谁  两个角色定义好后,需要让他们之间建立联系
        //获取Lifecycle
        getLifecycle().addObserver(new LocationListener());


public class LocationListener implements LifecycleObserver {
    private static final String TAG = "TAG";

    @OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
    public void onActivityCreate(LifecycleOwner owner) {
        Log.w(TAG, "onActivityCreate");
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
    public void onActivityDestroy(LifecycleOwner owner) {
        Log.w(TAG, "onActivityDestroy");
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
    public void onActivityPause(LifecycleOwner owner) {
        Log.w(TAG, "onActivityPause");
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
    public void onActivityResume(LifecycleOwner owner) {
        Log.w(TAG, "onActivityResume");
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_START)
    public void onActivityStart(LifecycleOwner owner) {
        Log.w(TAG, "onActivityStart");
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_STOP)
    public void onActivityStop(LifecycleOwner owner) {
        Log.w(TAG, "onActivityStop");
    }

}


Lifecycle 原理 如何感知 activity 或 fragment 生命周期

1、activity 和 fragment 已经实现了 LifecycleOwner
2、出现了一个LifecycleRegistry,是 Lifecycle 的一个实现类。通过markState方法在onSaveInstanceState把 Lifecycle 状态标记为Lifecycle.State.CREATED。
3、onCreate 方法里有个ReportFragment,
4、利用 fragment 的特性,绑定了一个 fragment 然后在其生命周期dispatch()方法中调用了LifecycleRegistry的handleLifecycleEvent,此方法便是通知观察者的地方。Lifecycle.Event,判断执行事件后下一个到达的状态,然后使用moveToState()中修改活动的生命周期
5、通知观察者addObserver 后,把observer维护到ObserverWithState然后装到 map 里。
然后通过handleLifecycleEvent方法最终遍历map 通知 observer。

伪代码
public class ComponentActivity extends androidx.core.app.ComponentActivity implements LifecycleOwner{

 private final LifecycleRegistry mLifecycleRegistry = new LifecycleRegistry(this);

 @CallSuper
    @Override
    protected void onSaveInstanceState(@NonNull Bundle outState) {
        mLifecycleRegistry.markState(Lifecycle.State.CREATED);
        super.onSaveInstanceState(outState);
    }

 @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mSavedStateRegistryController.performRestore(savedInstanceState);
        ReportFragment.injectIfNeededIn(this);
        if (mContentLayoutId != 0) {
            setContentView(mContentLayoutId);
        }
    }


  public void addObserver(@NonNull LifecycleObserver observer) {
        State initialState = mState == DESTROYED ? DESTROYED : INITIALIZED;
        ObserverWithState statefulObserver = new ObserverWithState(observer, initialState);
        ObserverWithState previous = mObserverMap.putIfAbsent(observer, statefulObserver);

}

ViewModel 原理

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


ViewModel 和 onSaveInstaceState方法区别在于:ViewModel只能保存因为配置更改导致重建的数据,但是它能保存大量和复杂的数据;onSaveInstaceState能保存配置更改导致重建和资源限制导致重建的数据,但是它只能保存少量简单的数据。ViewModel使用SavedStateHandle能够保存资源限制导致重建的数据。

根据传入的Activity获取、创建、添加并以键值对保存Fragment,从VIewStore的Map中或Factory的create()中获取ViewMode
1、获取ViewProvider:
2、获取ViewModelStore:由前面的源码可以知道创建ViewProvider时传入两个参数:ViewModelStore 和 Factory;显然从名字就可以看出他们的作用,Factory负责创建,ViewModelStore负责存储

ViewModelStore内部维护者一个Map集合保存者ViewModel对象的键值对

ViewModel的生命周期要比Activity长一点。因为在ComponentActivity 实现了的getViewModelStore ,ViewModelStore在Activity重建前后能保持同一个对象就是通过NonConfigurationInstances实现的。

ActivityThread 里面performLaunchActivity方法里面,启动Activity 调用了Activity的attach方法,在这个方法,将已有的NonConfigurationInstances赋值给了新的Activity对象。所以Activity 获取到的ViewMode是同一个,
这样NonConfigurationInstances能保证ViewModelStore在Activity重建前后是同一个对象,同时也知道为啥ViewModel的生命周期比Activity的生命周期要长一点

LiveData 原理,如何做到生命周期感知:

涉及到LifecycleOwner属于另一个架构组件 lifecycle,lifecycle原理上面已经讲述

伪代码
   //LiveData数据可以再通过observe方法进行数据回调的返回,如上代码中的onChanged回调。
    //  从Livedata添加观察者的方法 observe 开始:
        viewMode.getUsers().observe(this, new Observer<String>() {
            @Override
            public void onChanged(String users) {
                viewmode_text.setText("viewMode获取到的数据--" + users);
            }
        });

 public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
        assertMainThread("observe");
        if (owner.getLifecycle().getCurrentState() == DESTROYED) {
            // ignore
            return;
        }
        LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
        ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
        if (existing != null && !existing.isAttachedTo(owner)) {
            throw new IllegalArgumentException("Cannot add the same observer"
                    + " with different lifecycles");
        }
        if (existing != null) {
            return;
        }
        owner.getLifecycle().addObserver(wrapper);
    }


第一个参数为LifecycleOwner用于提供当前的生命周期状态,DESTROYED的时候不做任何操作。
第二个为观察者observer,首先把observer包装成了LifecycleBoundObserver,然后把LifecycleBoundObserver维护到mObservers里
private SafeIterableMap<Observer<? super T>, ObserverWrapper> mObservers = new SafeIterableMap<>();
mObservers是一个LinkedList结构的容器 通过putIfAbsent方法判断,容器中此观察者是不是已经存在,如果存在且LifecycleOwner不同的话则抛异常,LifecycleOwner相同则 return 不重复添加。
LifecycleBoundObserver实现了LifecycleObserver,为lifecycle 的观察者,通过上文的 observe方法添加到了lifecycle观察中,

接下来主要看LifecycleBoundObserver
通过此类持有 Livedata 的观察者observer,当 生命周期发生变化时 会回调onStateChanged方法,然后 Livedata 的观察者在onStateChanged中执行相应的逻辑。

  @Override
        public void onStateChanged(@NonNull LifecycleOwner source,
                @NonNull Lifecycle.Event event) {
            if (mOwner.getLifecycle().getCurrentState() == DESTROYED) {
                removeObserver(mObserver);
                return;
            }
            activeStateChanged(shouldBeActive());
        }
    //接着执行activeStateChanged
     void activeStateChanged(boolean newActive) {
            if (newActive == mActive) {
                return;
            }
            // immediately set active state, so we'd never dispatch anything to inactive
            // owner
            mActive = newActive;
            boolean wasInactive = LiveData.this.mActiveCount == 0;
            LiveData.this.mActiveCount += mActive ? 1 : -1;
            if (wasInactive && mActive) {
                onActive();
            }
            if (LiveData.this.mActiveCount == 0 && !mActive) {
                onInactive();
            }
            if (mActive) {
                dispatchingValue(this);
            }
        }

通过巧妙的设计实现了:
1、状态没有变化,什么也不做。
2、变为活(active)就是调用onActive(),非活(inactive)就调用onInactive().
3、另外,变为活的话就调用dispatchingValue方法,此方法为回调观察者的方法

事件的通知
LiveData通过 setValue 或 postValue 方法去改变持有的数据,并通知观察者,最终都是调用dispatchingValue()方法:

 void dispatchingValue(@Nullable ObserverWrapper initiator) {
   ........................................
//遍历之前注册的观察者
                for (Iterator<Map.Entry<Observer<? super T>, ObserverWrapper>> iterator =
                        mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
                    considerNotify(iterator.next().getValue());
                    if (mDispatchInvalidated) {
                        break;
                    }
                }
            }
        } while (mDispatchInvalidated);
        mDispatchingValue = false;
    }

 private void considerNotify(ObserverWrapper observer) {
   ................................
        if (observer.mLastVersion >= mVersion) {
            return;
        }
        observer.mLastVersion = mVersion;
     //开始通知了
        observer.mObserver.onChanged((T) mData);
    }
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,968评论 6 482
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,601评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 153,220评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,416评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,425评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,144评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,432评论 3 401
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,088评论 0 261
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,586评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,028评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,137评论 1 334
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,783评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,343评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,333评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,559评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,595评论 2 355
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,901评论 2 345

推荐阅读更多精彩内容