一、运用架构
1.1、规划意图
运用或许规划某个运用架构的意图是什么?
简略的概括来说,是为了满足开闭准则,在不修正原有代码的状况下给程序扩展功能,而不是直接修正原有代码。
终究的意图是为了 提高开发测试效率,降低程序保护本钱(降本增效)
1.2、架构挑选
依据上面的认知,咱们挑选运用一些其他的规划来完成开闭准则的意图。包括但不限于:单一责任,笼统接口,承继多态、解耦等等办法。
Android官方引荐的MVVM运用架构(现在现已不是官方最引荐架构了),主要是经过拆分View层(Activity/Fragmet)责任,简化View层的逻辑,分离View层和Model层之间的耦合的办法来完成开闭准则的意图
MVVM架构模型如下(每个组件仅依靠下一级组件):
这儿需求强调的是:
-
虽然该架构本身是完成程序开闭准则的比较好实践之一,但是并不是一切的运用界面代码规划有必要运用该架构。
-
运用架构的挑选应该依据实际状况挑选,没有最好的架构,只是只要当时场景的最优挑选
下面主要剖析下该架构下最重要的两个架构组件ViewModel和LiveData的运用和原理
二、组件运用
ViewModel教程
LiveData教程
简略运用示例(具体教程可查看如上官方教程):
ViewModel和LiveData一般组合运用(也能够独自运用,依据实际场景挑选):
界面由MainActivity和对应的布局activity_main.xml组成。
首页需求恳求页面数据,咱们运用HomeViewModel恳求和存储这些数据,界说了以下文件:
MainActivity
activity_main.xml
HomeViewModel
以下代码段显现了这些文件的起始内容(为简略起见,省掉了布局文件)
MainActivity:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// Use the 'by viewModels()' Kotlin property delegate from the activity-ktx artifact
// or use ' ViewModelProvider(this).get(HomeViewModel::class.java)'
val viewModel: HomeViewModel by viewModels()
viewModel.pageData.observe(this, { data ->
Log.d("mumu","data: $data")
})
}
HomeViewModel:
class HomeViewModel : ViewModel() {
val pageData: MutableLiveData<String> by lazy {
MutableLiveData<String>()
}
init {
// 恳求回来字符串并保存
requestNetData(object : IHttpCallBack {
override fun onError(error: IHttpCallBack.HttpError?) {
pageData.value = null
}
override fun onEnd(data: String) {
pageData.value = data
}
})
阐明:
- 在ViewModel层调用网络数据层的办法恳求数据并保存到ViewModel的LiveData存储器中。
- 在View层(Activity)中注册调查者目标,调查LiveData的数据更新。无需在onStop中止调查,由于LiveData结构具有生命周期感知,检测调查者onStop了不会告诉调查者数据更新。
三、组件原理
3.1、LiveData
LiveData 是一种可调查的数据存储器。运用中的其他组件能够运用此存储器监控目标的更改,而无需在它们之间创立明确且严格的依靠路径。LiveData 组件还能感知运用组件(如 Activity、Fragment 和 Service)的生命周期状况,能够主动整理调查者以避免目标走漏和过多的内存消耗。
3.1.1、注册调查者
@MainThread
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
assertMainThread("observe");
//运用组件现已毁掉,疏忽
if (owner.getLifecycle().getCurrentState() == DESTROYED) {
// ignore
return;
}
//将调查者目标封装成一个LifecycleBoundObserver目标(详见3.1.2)
LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
//不为空阐明现已在SafeIterableMap调集中了,同一个运用组件(Activity/Fragment)不能重复增加相同的调查者
if (existing != null && !existing.isAttachedTo(owner)) {
throw new IllegalArgumentException("Cannot add the same observer"
+ " with different lifecycles");
}
if (existing != null) {
return;
}
//LifecycleBoundObserver完成LifecycleEventObserver接口,绑定Lifecycle的生命周期
owner.getLifecycle().addObserver(wrapper);
}
阐明: 该步骤主要讲调查者目标observer封装成一个LifecycleBoundObserver目标,然后保存到调集中,并且经过LifeCycle绑定运用组件的生命周期
3.1.2、LifecycleBoundObserver调查者包装类
//内部类
class LifecycleBoundObserver extends ObserverWrapper implements LifecycleEventObserver {
@NonNull
final LifecycleOwner mOwner;
LifecycleBoundObserver(@NonNull LifecycleOwner owner, Observer<? super T> observer) {
super(observer);
mOwner = owner;
}
//判别调查者是否激活,运用组件生命周期处在onStart和onResume状况该办法才会回来true
@Override
boolean shouldBeActive() {
return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
}
//运用组件生命周期发生改动时回调该办法(Lifecycle组件的功能)
@Override
public void onStateChanged(@NonNull LifecycleOwner source,
@NonNull Lifecycle.Event event) {
Lifecycle.State currentState = mOwner.getLifecycle().getCurrentState();
//判别运用组件现已destroy了则主动解注册
if (currentState == DESTROYED) {
removeObserver(mObserver);
return;
}
Lifecycle.State prevState = null;
while (prevState != currentState) {
prevState = currentState;
//状况办法改动,调用该办法改动LiveData状况和分发数据(详见3.1.3)
activeStateChanged(shouldBeActive());
currentState = mOwner.getLifecycle().getCurrentState();
}
}
@Override
boolean isAttachedTo(LifecycleOwner owner) {
return mOwner == owner;
}
@Override
void detachObserver() {
mOwner.getLifecycle().removeObserver(this);
}
}
//LiveData的解注册办法(LiveData的办法)
@MainThread
public void removeObserver(@NonNull final Observer<? super T> observer) {
assertMainThread("removeObserver");
//从调集中移除调查者包装目标
ObserverWrapper removed = mObservers.remove(observer);
//为空阐明现已移除了
if (removed == null) {
return;
}
//Lifecycle解注册
removed.detachObserver();
//调用activeStateChanged办法同步状况改动
removed.activeStateChanged(false)
3.1.3、activeStateChanged状况改动同步办法
void activeStateChanged(boolean newActive) {
if (newActive == mActive) {
return;
}
// immediately set active state, so we'd never dispatch anything to inactive
// owner
mActive = newActive;
//该办法是经过加一减一来判别当时LiveData目标内是否有处在调集状况的调查者
//假如从无到有则调用onActive办法,从有到无则调用onInactive办法
//两个办法均为LiveData的空完成办法,咱们能够做一些初始化或许数据重置的操作
changeActiveCounter(mActive ? 1 : -1);
if (mActive) {
//真实开发分发数据的办法(只要调查者处于激活状况才会分发数据,详见3.1.4)
dispatchingValue(this);
}
}
3.1.4、dispatchingValue分发数据办法
void dispatchingValue(@Nullable ObserverWrapper initiator) {
if (mDispatchingValue) {
//mDispatchInvalidated符号数据是否失效,假如失效从头分发最新数据
mDispatchInvalidated = true;
return;
}
mDispatchingValue = true;
do {
mDispatchInvalidated = false;
if (initiator != null) {
//状况改动同步数据initiator不为空(首次注册状况下假如需求同步也是走到这儿)
considerNotify(initiator);
initiator = null;
} else {
//更新数据状况同步一切调查者数据改动
for (Iterator<Map.Entry<Observer<? super T>, ObserverWrapper>> iterator =
mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
//告诉调查者数据改动分发(详见3.1.5)
considerNotify(iterator.next().getValue());
if (mDispatchInvalidated) {
break;
}
}
}
} while (mDispatchInvalidated);
mDispatchingValue = false;
}
3.1.5、considerNotify告诉调查者数据改动办法
private void considerNotify(ObserverWrapper observer) {
//调查者没有激活不处理
if (!observer.mActive) {
return;
}
// Check latest state b4 dispatch. Maybe it changed state but we didn't get the event yet.
//
// we still first check observer.active to keep it as the entrance for events. So even if
// the observer moved to an active state, if we've not received that event, we better not
// notify for a more predictable notification order.
//再判别一次调查者状况,避免状况没有及时同步
if (!observer.shouldBeActive()) {
//假如状况办法改动就会调用上面的状况改动同步分发
observer.activeStateChanged(false);
return;
}
//判别数据是否现已告诉了该调查者目标,避免重复更新(LiveData数据每更新一次,mVersion就会加一)
if (observer.mLastVersion >= mVersion) {
return;
}
observer.mLastVersion = mVersion;
//没有告诉过则调用调查者的onChanged办法告诉数据更新
observer.mObserver.onChanged((T) mData);
}
阐明:
走到这儿,LiveData的一次完整数据调查和数据更新流程就完毕了。
经过上述流程可知,LiveData会经过Lifecycle主动观测运用组件生命周期改动,组件毁掉了主动解注册;组件激活了将调查者变为激活状况并及时同步数据给调查者。调查者只需求在数据更新办法中做相应的中心逻辑处理,而无需关心数据丢失或许数据重复回调,也无需担心内存走漏,LiveData会主动解注册调查者。
终究还有就是LiveData的数据更新办法(setValue和postValue办法),详见3.1.6阐明
3.1.6、更新数据办法
setValue或许postValue(区别是postValue支持异步调用,终究仍是会切换到主线程调用setValue办法)
@MainThread
protected void setValue(T value) {
assertMainThread("setValue");
//数据改动,version加一
mVersion++;
mData = value;
//调用3.1.4的分发数据办法,不过这儿的调查者包装类目标为null因而会循环调集中一切的调查者目标告诉数据更新
dispatchingValue(null);
}
3.2、ViewModel
ViewModel目标为特定的界面组件(如 Fragment 或 Activity)提供数据,并包含数据处理事务逻辑,以与模型进行通讯。例如,ViewModel能够调用其他组件来加载数据,还能够转发用户恳求来修正数据。ViewModel无法感知界面组件,因而不受装备更改(如在旋转设备时从头创立 Activity)的影响
ViewModel是怎么确保同一个Activity目标仅有一个ViewMode目标?
ViewModel目标创立是经过ViewModelProvider目标的get办法来进行创立的,经过ViewModelProvider目标来确保ViewModel的唯一
3.2.1、ViewModelProvider结构办法
ViewModelProvider共有三个结构办法,如下:
public ViewModelProvider(@NonNull ViewModelStoreOwner owner) {
this(owner.getViewModelStore(), owner instanceof HasDefaultViewModelProviderFactory
? ((HasDefaultViewModelProviderFactory) owner).getDefaultViewModelProviderFactory()
: NewInstanceFactory.getInstance());
}
//ViewModelStoreOwner是个接口只要一个办法getViewModelStore,由Activity/Fragment完成(详见3.2.2)
public ViewModelProvider(@NonNull ViewModelStoreOwner owner, @NonNull Factory factory) {
this(owner.getViewModelStore(), factory);
}
//终究会调用的该结构办法,ViewModelStore封装了HashMap调集保存ViewModel目标
//ViewModelStore详见3.2.3
public ViewModelProvider(@NonNull ViewModelStore store, @NonNull Factory factory) {
mFactory = factory;
mViewModelStore = store;
3.2.2、完成ViewModelStoreOwner接口
下列代码已Activity为例,Fragment相似
@NonNull
@Override
public ViewModelStore getViewModelStore() {
if (getApplication() == null) {
throw new IllegalStateException("Your activity is not yet attached to the "
+ "Application instance. You can't request ViewModel before onCreate call.");
}
ensureViewModelStore();
return mViewModelStore;
}
@SuppressWarnings("WeakerAccess") /* synthetic access */
void ensureViewModelStore() {
//mViewModelStore是ComponentActivity的成员变量,内部经过HashMap存储数据ViewModel
if (mViewModelStore == null) {
//假如为空,先尝试从mLastNonConfigurationInstances中取,
//mLastNonConfigurationInstances是activity的成员变量,这个值在Acivity attach 的时候赋值
NonConfigurationInstances nc =
(NonConfigurationInstances) getLastNonConfigurationInstance();
if (nc != null) {
// Restore the ViewModelStore from NonConfigurationInstances
mViewModelStore = nc.viewModelStore;
}
//假如取值为空则从头创立一个
if (mViewModelStore == null) {
mViewModelStore = new ViewModelStore();
}
}
}
3.2.3、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);
}
Set<String> keys() {
return new HashSet<>(mMap.keySet());
}
/**
* Clears internal storage and notifies ViewModels that they are no longer used.
*/
public final void clear() {
for (ViewModel vm : mMap.values()) {
vm.clear();
}
mMap.clear();
阐明: 其实就是个HashMap,用来保存ViewModel目标
3.2.4、ViewModelProvider.get(ViewModel.class)办法获取ViewModel实例
@NonNull
@MainThread
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);
//优先从ViewModelStore中获取,不为空则直接回来
if (modelClass.isInstance(viewModel)) {
if (mFactory instanceof OnRequeryFactory) {
((OnRequeryFactory) mFactory).onRequery(viewModel);
}
return (T) viewModel;
} else {
//noinspection StatementWithEmptyBody
if (viewModel != null) {
// TODO: log a warning.
}
}
//为空则经过mFactory创立,
//这儿的mFactory假如ViewModeStoreOwner没有完成HasDefaultViewModelProviderFactory
//则默许运用NewInstanceFactory经过反射构建ViewModel目标。
//Componentactivity默许是完成了HasDefaultViewModelProviderFactory接口的,回来 SavedStateViewModelFactory,
//假如是ViewModel是无参结构则终究仍是会经过NewInstanceFactory构建目标
if (mFactory instanceof KeyedFactory) {
viewModel = ((KeyedFactory) mFactory).create(key, modelClass);
} else {
viewModel = mFactory.create(modelClass);
}
mViewModelStore.put(key, viewModel);
return (T) viewModel;
}
3.2.5、NewInstanceFactory工厂类
NewInstanceFactory经过反射构建ViewModel目标,办法比较简略,其他工厂相似
public static class NewInstanceFactory implements Factory {
private static NewInstanceFactory sInstance;
@NonNull
static NewInstanceFactory getInstance() {
if (sInstance == null) {
sInstance = new NewInstanceFactory();
}
return sInstance;
}
@SuppressWarnings("ClassNewInstance")
@NonNull
@Override
public <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
//noinspection TryWithIdenticalCatches
try {
return modelClass.newInstance();
} catch (InstantiationException e) {
throw new RuntimeException("Cannot create an instance of " + modelClass, e);
} catch (IllegalAccessException e) {
throw new RuntimeException("Cannot create an instance of " + modelClass, e);
}
}
阐明: 上述5个步骤即确保了ViewModel目标在Activity/Fragment的唯一性
3.2.6、装备改动导致Activity重建状况保存
怎么确保装备状况改动导致Activity重建的状况下,ViewModel不变?
主要是靠NonConfigurationInstances目标,代码阐明如下
@Nullable
public final Object onRetainNonConfigurationInstance() {
Object custom = this.onRetainCustomNonConfigurationInstance();
ViewModelStore viewModelStore = this.mViewModelStore;
ComponentActivity.NonConfigurationInstances nci;
if (viewModelStore == null) {
nci = (ComponentActivity.NonConfigurationInstances)this.getLastNonConfigurationInstance();
if (nci != null) {
viewModelStore = nci.viewModelStore;
}
}
if (viewModelStore == null && custom == null) {
return null;
} else {
nci = new ComponentActivity.NonConfigurationInstances();
nci.custom = custom;
//保存viewModelStore
nci.viewModelStore = viewModelStore;
return nci;
}
四、实践总结
4.1、内存走漏
1、 ViewModel不能持有Activity/Fragment/View相关目标的引证,由于ViewModel生命周期和组件的生命周期不一致,这种状况下或许(少量状况,由于一般咱们不允许装备更新导致Activity重建,但是即使仅从规划模式的视点考虑咱们也应该这么做)会导致内存走漏。
2、 LiveData.observer办法注册调查者的时候,留意假如是Fragment和View的状况。Fragment建议传递Fragment本身作为LifecycleOwner(和Activity的LifecycleOwner不是同一个)由于Fragment或许会先于 activity毁掉。
3、组件真实毁掉时,会调用ViewModel的onCleared办法,留意毁掉必要的数据,比如说数据层的监听回调等等(或许在数据层运用弱运用,不是有必要,需求留意数据层生命周期很长的状况,例如数据层是个单例,一直持有ViewModel的引证会导致ViewModel无法回收)
4.2、数据保存
1、 Activity/Fragment 或许Fragment/Frament之间传递数据,留意传递的ViewModelStore需求时同一个,由于Fragment也会完成ViewModelStoreOwner接口,经过Fragment的getViewModelStore办法和Activity的getViewModelStrore办法获取的ViewModelStore并不是同一个,所以终究获取到的ViewModel目标并不是同一个。Fragment共享数据需求相同的Activity作为ViewModelStoreOwner,建议运用requireActivity办法获取Acitivity。
2、 ViewModel只能在装备更新导致的Activity重建的状况下保存,例如屏幕旋转。并不能在异常毁掉Activity的状况保存数据,例如操作系统由于内存紧张杀掉进程的状况,这种状况数据并不能经过ViewModel康复数据,能够考虑运用onSaveInstanceState办法或许其他办法保存数据。