JetPack架构组件介绍

MVP & MVVM

MVP结构

image.png

MVP存在的问题:

  • View ,Model之间的通信都要经过presenter为中介通信,实现方式是接口注入,接口众多的现象

  • 维护成本高,常见的 View点击-》Model更新数据-》更新View,每次至少来回调用两次接口

  • 主要将逻辑分在View和Model中实现,复杂业务中这两个类容易膨胀

MVVM & LiveData

MVVM中的View和Model之间通过ViewModel通信,AndroidX中的LiveData采用观察者模式,Model的更新,可直接被View监听到,不需要用户手动定义接口更新数据,而是自动同步给View实现UI更新

gN16bqjm98KHgahmF5UWDFvhZDmjDoZPrHPl7L9Ni9w1q7Slvi.png

JetpPack总体介绍

2017年的Google I/O大会上,Google推出了一系列譬如 Lifecycle、ViewModel、LiveData等一系列 更适合用于MVVM模式开发 的架构组件。

cV2Pi6nGTwnctvC2lyhC0n84Ae8zuHjmP5cBhRh970hrtmC3sX.png

ViewModel

https://developer.android.com/reference/android/arch/lifecycle/ViewModel.html

如何使用:

public class UserActivity extends Activity {

     @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() {

            @Override

             public void onChanged(@Nullable User data) {

                 // update ui.

             }

         });

         findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {

             @Override

             public void onClick(View v) {

                  viewModel.doAction();

             }

         });

     }

 }
public class UserModel extends ViewModel {

     public final LiveData userLiveData = new LiveData<>();

     public UserModel() {

         // trigger user load.

     }

     void doAction() {

         // depending on the action, do necessary business logic calls and update the

         // userLiveData.

     }

 }

创建逻辑:

通过Activity中的fieldViewModelStore 去管理,以ViewModel的类名为key存储在map中,如果之前map中已经有这个key的数据,那么直接返回,如果没有创建过,则重新创建

/**

 * Returns an existing ViewModel or creates a new one in the scope (usually, a fragment or

 * an activity), associated with this {@code ViewModelProvider}.

 * 

* The created ViewModel is associated with the given scope and will be retained * as long as the scope is alive (e.g. if it is an activity, until it is * finished or process is killed). * * @param key The key to use to identify the ViewModel. * @param modelClass The class of the ViewModel to create an instance of it if it is not * present. * @param The type parameter for the ViewModel. * @return A ViewModel that is an instance of the given type {@code T}. */ @NonNull @MainThread public T get(@NonNull String key, @NonNull Class 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. } } if (mFactory instanceof KeyedFactory) { viewModel = ((KeyedFactory) (mFactory)).create(key, modelClass); } else { viewModel = (mFactory).create(modelClass); } mViewModelStore.put(key, viewModel); //noinspection unchecked return (T) viewModel; }

销毁逻辑

/**

 * Destroy all fragments.

 */

@Override

protected void onDestroy() {

    super.onDestroy();

    if (mViewModelStore != null && !isChangingConfigurations()) {

        mViewModelStore.clear();

    }

    mFragments.dispatchDestroy();

}

如果ViewModel中有使用到一些生命周期较长的数据,应在onClear回调中手动销毁

nVatL2mqR0YlqGBH85gjukPle4omO8zcHto44Tc6lRz3YQe6Ly.png

生命周期:

用户在使用产品的过程中,可能随时会被中断或界面发生重建,如果数据的丢失会造成很差的用户体验,当然现在都知道在onSaveInstanceState()中保存数据,在界面重建时恢复数据,这种虽然可以解决问题,但会造成每个界面都要编写板寸和恢复的代码,而且数据量过大时会影响执行性能,VIewModel的出现就是解决这个问题,它会在活动重建时仍然保存数据,在活动创建完成后从中获取数据。

androidx中Activity的ondestroy方法:

/**

 * Destroy all fragments.

 */

@Override

protected void onDestroy() {

    super.onDestroy();

    if (mViewModelStore != null && !isChangingConfigurations()) {

        mViewModelStore.clear();

    }

    mFragments.dispatchDestroy();

}
FJDJejVwTr1WbwEt7R2sTjZqUqdID4V6LndyG5KTtb4ECO7k4F.png

总结:

数据和界面的分离,使数据驱动界面

解决了运行中断和界面重建时的数据保存问题

实现Activity中Fragment之间的数据交互

配合LiveData实时获取最新数据

LifeCycle

https://developer.android.com/reference/android/arch/lifecycle/Lifecycle

如何使用:

java8:

If you use Java 8 Language, then observe events with DefaultLifecycleObserver. To include it you should add "android.arch.lifecycle:common-java8:" to your build.gradle file.

 class TestObserver implements DefaultLifecycleObserver {

     @Override

     public void onCreate(LifecycleOwner owner) {

         // your code

     }

 }

** java7:**

 class TestObserver implements LifecycleObserver {

   @OnLifecycleEvent(ON_CREATE)

   void onCreated(LifecycleOwner source) {}

   @OnLifecycleEvent(ON_ANY)

   void onAny(LifecycleOwner source, Event event) {}

 }

State & Event:

public abstract class Lifecycle {

        //注册LifecycleObserver (比如Presenter)

        public abstract void addObserver(@NonNull LifecycleObserver observer);

        //移除LifecycleObserver 

        public abstract void removeObserver(@NonNull LifecycleObserver observer);

        //获取当前状态

        public abstract State getCurrentState();

        public enum Event {

            ON_CREATE,

            ON_START,

            ON_RESUME,

            ON_PAUSE,

            ON_STOP,

            ON_DESTROY,

            ON_ANY

        }
       public enum State {

            DESTROYED,

            INITIALIZED,

            CREATED,

            STARTED,

            RESUMED;

            public boolean isAtLeast(@NonNull State state) {

                return compareTo(state) >= 0;

            }

       }

}

Event发送时序:

4CnsQLLTHmmpaO4arXyVUnz52dtdwLIrO0kOqYig1UqBiko55D.png

总结:

  • 实现能够感知 Activity/Fragment 生命周期信息的组件,便于页面逻辑的拆解,代码解耦可代码的可读性和可维护性

  • LiveData的生命周期基于LifeCycle实现

LiveData

https://developer.android.com/reference/androidx/lifecycle/LiveData.html

如何使用:

(1)定义LiveData 变量,对外开放LiveData和修改value的方法:主线程调用setValue,后台线程调用postValue

class ProfileLiveDataViewModel : ViewModel() {

    private val _xytestData = MutableLiveData(XyTestData())

    val xyTestData: LiveData = _xytestData

    fun changeHomeTown() {

        _xytestData.value?.apply {

            innerData.homeTown = innerData.homeTown + "——湖南"

        }

        _xytestData.value = _xytestData.value

    }

}

(2)触发修改

binding.likeButton.setOnClickListener(new View.OnClickListener() {

    @Override

    public void onClick(View v) {

        viewModel.onLike();

        viewModel.changeHomeTown();

    }

});

(3)observer监听LiveData 的回调,onChanged一定 发生在主线程

viewModel.getXyTestData().observe(activity, new Observer() {

    @Override

    public void onChanged(XyTestData xyTestData) {

        Log.d("xiaoyu_activity home : ",xyTestData.innerData.homeTown);

        binding.lastname.setText(xyTestData.innerData.homeTown);

    }
});

具有生命周期的观察者模式

  • LiveData 认为观察者的生命周期处于STARTED状态或RESUMED状态下,表示观察者处于活动状态,LiveData只通知活跃的观察者去更新数据

  • LiveData会在活动处于Destroy时释放观察者,所以开发者无需特别处理

(1)添加监听:

@MainThread

public void observe(@NonNull LifecycleOwner owner, @NonNull Observer 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);

}

class LifecycleBoundObserver extends ObserverWrapper implements LifecycleEventObserver {

    @NonNull

    final LifecycleOwner mOwner;

    LifecycleBoundObserver(@NonNull LifecycleOwner owner, Observer observer) {

        super(observer);

        mOwner = owner;

    }

    @Override

    boolean shouldBeActive() {

        return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);

    }

    @Override

    public void onStateChanged(LifecycleOwner source, Lifecycle.Event event) {

        if (mOwner.getLifecycle().getCurrentState() == DESTROYED) {

            removeObserver(mObserver);

            return;

        }

        activeStateChanged(shouldBeActive());

    }

    @Override

    boolean isAttachedTo(LifecycleOwner owner) {

        return mOwner == owner;

    }

    @Override

    void detachObserver() {

        mOwner.getLifecycle().removeObserver(this);

    }

}

(2)setValue时去通知observers:

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;

    }

    if (observer.mLastVersion >= mVersion) {

        return;

    }

    observer.mLastVersion = mVersion;

    //noinspection unchecked

    observer.mObserver.onChanged((T) mData);

}

永久生效的观察者模式:

@MainThread

public void observeForever(@NonNull Observer observer) {

    assertMainThread("observeForever");

    AlwaysActiveObserver wrapper = new AlwaysActiveObserver(observer);

    ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);

    if (existing instanceof LiveData.LifecycleBoundObserver) {

        throw new IllegalArgumentException("Cannot add the same observer"

                + " with different lifecycles");

    }

    if (existing != null) {

        return;

    }

    wrapper.activeStateChanged(true);

}

这种情况下LiveData不会自动释放observer,需要我们手动调用removeObserver释放,避免内存泄漏。

Transformation:

map

 val popularity: LiveData = Transformations.map(_likes) {

    when {

        it > 9 -> Popularity.STAR

        it > 4 -> Popularity.POPULAR

        else -> Popularity.NORMAL

    }

}

switchmap

 MutableLiveData userIdLiveData = ...;

 LiveData userLiveData = Transformations.switchMap(userIdLiveData, id ->

     repository.getUserById(id));

 void setUserId(String userId) {

      this.userIdLiveData.setValue(userId);

 }

类似于rxjava中的map和flatMap

LiveData/ MutableLiveData /MediatorLiveData

LiveData只可读,不可修改

MutableLiveData,开放了setValue和PostValue

MediatorLiveData,支持LiveData组合

* MediatorLiveData liveDataMerger = new MediatorLiveData<>();

* liveDataMerger.addSource(liveData1, value -> liveDataMerger.setValue(value));

* liveDataMerger.addSource(liveData2, value -> liveDataMerger.setValue(value));

* 
*

* Let's consider that we only want 10 values emitted by {@code liveData1}, to be * merged in the {@code liveDataMerger}. Then, after 10 values, we can stop listening to {@code * liveData1} and remove it as a source. *


* liveDataMerger.addSource(liveData1, new Observer() {

*      private int count = 1;

*

*      {@literal @}Override public void onChanged(@Nullable Integer s) {

*          count++;

*          liveDataMerger.setValue(s);

*          if (count > 10) {

*              liveDataMerger.removeSource(liveData1);

*          }

*      }

* });

总结:

  • 确保UI与数据状态相匹配

​LiveData​遵循观察者模式,当生命周期状态发送改变时,​LiveData​会通知观察者对象,您可以合并代码以更新这些观察者对象中的UI。您的观察者可以在任意变化的情况下更新UI,而不是每次数据发生变更时更新UI。

  • 没有内存泄露

观察者被绑定到生命周期对象上,并在其关联的生命周期被销毁后会进行清理。所以不会有内存泄露。

不会因为Activity停止而崩溃

如果观察者的生命周期处于不活动状态下,例如Activity在后台栈中,那不会接收到任意的​LiveData​事件。

  • 不在需要手动管理生命周期

UI组件只需要观察相关的数据,不需要停止和恢复观察。​LiveData​自动管理这些,因为他知道相关的生命周期的变化。

  • 始终保持最新数据

如果一个生命周期变得不活动,它将在再次激活时接收最新的数据。例如,后台的某个Activity在返回到前台后会接收最新的数据。

  • 适当的配置更改

如果一个Activity或者Fragment由于配置改变而重新创建,例如设备旋转,它会立即接收到最新的可用数据。

  • 共享资源

您可以使用单例模式扩展LiveData对象,以包装系统服务,以便它们可以在您的应用程序中共享。LiveData对象一旦连接到系统服务,然后任何需要资源的观察者都可以看到LiveData对象。

提供了一个数据更新UI,实现通信的非常轻量的方式

DataBinding

如何使用:

(1)gradle配置:

android {...

    dataBinding {

       enabled true

    }}

(2)在xml中直接将UI与ViewModel绑定,监听ViewModel中数据的变化,将变化直接体现在view上



        

            

        

         

    

(3)编译后直接根据layout文件生成Binding类

(4)通过binding对象直接获取到各个id的view:

val binding: ObservableFieldProfileBinding =

        DataBindingUtil.setContentView(this, R.layout.observable_field_profile)

binding.user = observableFieldProfile

好处:

  • 数据直接展示,没有复杂处理逻辑的,这样的方式可以用,只需要关心更新viewModel中的数据,而不需要关心数据与Ui的绑定了

  • 生成Binding类后,通过binding对象可以直接拿到xml中定义的view对象,比butterKnife和findViewById方便

存在的问题:

  • 编译时期出错,没有生成Binding类

  • 数据在xml中绑定,不方便调试

  • 逻辑维护比较分散

Android 业务层架构思考

Snip20191117_9.png

说明:

  • ViewModel中的数据根据数据逻辑拆分成不同的LiveData

  • UI逻辑根据业务拆分成不同的Observer

  • layout使用include方式拆分


  • UI与 数据逻辑之间通过ViewModel为中介通信

  • 各个Observer通过LifeCycle感知Fragment/Activity的生命周期,并能够拿到context和viewmodel

  • 各个Observer之间的非通用数据可通过自定义LiveData进行通信

好处:

  • 每个controller都有足够的context,包括Activity或者fragment的lifecycle,ViewModel数据交互;因此能够很容易地完成自己的逻辑

  • 逻辑分离,扩展性和可维护性更好

参考:

https://developer.android.com/jetpack
https://blog.csdn.net/Alexwll/article/details/83302173
https://medium.com/@MinaSamy/android-architecture-components-lifecycle-433ace1ec05d
https://medium.com/exploring-android/exploring-the-new-android-architecture-components-c33b15d89c23
http://timmy6.github.io/2018/08/13/android-lifecycle/
https://proandroiddev.com/5-common-mistakes-when-using-architecture-components-403e9899f4cb
https://codelabs.developers.google.com/codelabs/android-databinding/#0
https://developer.android.com/reference/android/arch/lifecycle/Transformations

你可能感兴趣的:(JetPack架构组件介绍)