LiveData+ViewModel+Lifecycle

1.LiveData+ViewModel+Lifecycle关系

在这里插入图片描述

2.Lifecycle

Lifecycle是一个抽象类,一个有Android 生命周期的对象附在它上面, 并且它持该对象的当前生命周期所处状态,所以其他对象可以观察到这种状态并做出相应的反应。为了跟踪这种状态,Lifecycle类包含两个枚举类Event和State。

2.1 Event
一个Event代表当Android 生命周期的对象的生命周期发生改变时候,会触发的一个生命周期事件(例如一个activity正在被恢复)。在LifecycleObserver类中,可以为每个事件实现回调,这样在生命周期的对象的生命周期改变的时候我们能进行相关的处理。arch.lifecycle包提供了Annotation,这意味着可以在类中注释应该在某些生命周期事件中触发的方法。比如像下面这样:


@OnLifecycleEvent(ON_STOP)
void doSometing(){
}

还可以在同一个带注释的方法中处理多个生命周期事件:

@OnLifecycleEvent({ON_STOP,ON_START})
void doSometing(){
}

下面是各种事件的情况:

① ON_ANY:在任何生命周期事件时触发。

② ON_CREATE:创建LifecycleOwner(下面会讲这个类)时将触发此事件。

③ ON_DESTROY:LifecycleOwner被销毁时将触发此事件。

④ ON_PAUSE:LifecycleOwner暂停时将触发此事件。

⑤ ON_RESUME:在LifecycleOwner恢复时触发此事件。

⑥ ON_START:启动LifecycleOwner时触发此事件。

⑦ ON_STOP:LifecycleOwner停止时触发此事件。

ON_CREATE,ON_START,ON_RESUME的方法会在LifeCycleOwner对应方法(onCreate()、onStart()、onResume())返回后被调用。生命周期事件ON_DESTROY, ON_STOP, ON_PAUSE的方法会在LifeCycleOwner对应方法(onDestory()、onStop()、onPause()被调用之前调用。

2.2 State
生命周期的State本质上是介于两个生命周期事件之间的一种情况。触发事件后,生命周期将进入一个状态,然后在触发另一个事件时离开该状态并进入另一个状态。如下图所示:
在这里插入图片描述
状态转换
从上图可以看到,Lifecycle实例在任意时间段里肯定是下面五个状态的其中一种:

① INITIALISED:初始起点的生命周期状态。
② CREATED:ON_CREATE事件之后,ON_START事件之前的状态。或者是ON_STOP事件之后,ON_DESTROY事件之前的状态。
③ STARTED:ON_START事件之后,ON_RESUME事件之前的状态。或者是事件之ON_PAUSE后,ON_STOP事件之前的状态。
④ RESUMED:ON_RESUME事件之后的状态。
⑤ DESTROYED:ON_DESTROY事件之后的状态。

如果想获取Lifecycle实例的当前状态,那么可以调用**getCurrentState()**方法,该方法允许开发者在任何时间检索其当前状态。这有助于在执行某种形式的操作之前检查Lifecycle组件的状态。State对象还可以调用isAtLeast()方法来判断当前状态是否大于等于给定状态。

2.3 Lifecycle相关方法
了解了Lifecycle所包含的State和Event枚举类,现在看看Lifecycle和其它类进行交互的一些方法。

Lifecycle方法
在这里插入图片描述
上图中看到可以Lifecycle的核心方法主要用来管理观察者

① addObserver():该方法用来添加一个Observer实例,只要LifecycleOwner改变状态就会通知它。当添加一个Observer时,它将接收导致当前状态的所有事件。举例来说,如果Lifecycle目前在RESUMED状态,则观察员将收到ON_CREATE,ON_START和ON_RESUME事件。
② removeObserver():可以调用此方法从Lifecycle的观察者列表中删除给定的观察者。从生命周期中删除观察者将不再接收任何触发事件。
③ getCurrentState():返回生命周期所在的当前状态。

前面提到了一个和Lifecycle息息相关的类LifecycleOwner,接下来看一下这个类是干什么的。

2.4 LifecycleOwner
这个其实是一个接口类,里面只有一个方法getLifecycle()

public interface LifecycleOwner {

    @NonNull
    Lifecycle getLifecycle();
}

里面的唯一方法getLifecycle()就是用来返回Lifecycle的。而这个方法的所代表的意思很简单,**告诉要使用Lifecycle的组件,我是一个生命周期感知组件,我存在生命周期的概念。**我们现在看v4组件下的Activity,会继承自SupportActivity,和Fragment,这两个类都实现了LifecycleOwner这个接口。同时这两个类有一个LifecycleRegistry属性,这个属性就是继承自Lifecycle而LifecycleOwner的getLifecycle()返回的就是这个LifecycleRegistry。这样就可以通过这个方法获取该Activity的Lifecycle,再通过对Lifecycle的观察对Activity的生命周期进行观察,如下:

class MainActivity extends AppCompatActivity() {
   protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState)
        getLifecycle().addObserver(new SomeObserver())
    }
}

SomeObserver类继承自LifecycleObserver,如下所示

class SomeObserver implements LifecycleObserver {
        @OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
        void MyResume() {
        }
        @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
        void MyPause() {
        }
    }

这样的话,当MainActivity 触发相应的事件,SomeObserver 就会回调相应的方法。
Lifecycle、LifecycleOwner、LifecycleObserver 三者关系
在这里插入图片描述
到此Lifecycle相关部分介绍的差不多了,但是还不够,官方还提供了其他已经封装好的能感知Lifecycle组件生命周期的配套组件LiveData和ViewModels。

3. LiveData

**LiveData的作用是持有一份给定的数据,并且能够在生命周期变化中观察它。**该类为开发者提供了一系列方法,方便对这个类持有数据的观察者的管理。LiveData会根据观察者绑定的LifecycleOwner的生命周期情况,来决定是否将数据改变的情况通知给观察者。这么做的好处就是,比如在一个Activity里面请求了网络更新这个Activity A界面下的数据,但是如果数据还没有请求回来这时候用户跳转到了另一个Activity B,这时候如果这个数据是被LiveData所持有的,那么这个被网络请求更新的数据就不会通知给Activity A。

LiveData的处理逻辑如下图所示:
在这里插入图片描述
3.1 setValue()
当调用LiveData的setValue(T value)方法时,将设置LiveData持有的数据。判断是否有活跃的观察者,这里的活跃观察者指观察者绑定的LifecycleOwner中的Lifecycle处于STARTED和RESUMED状态的观察者,如果有的话,将更新的数据发送给这些处于活跃状态的观察者。

3.2 observe()
当调用的LiveData的observe(LifecycleOwner owner, Observer observer)方法时,根据情况会有不同的处理。如果LifecycleOwner处于DESTROYED状态,那么这个调用将被完全忽略。如果它不是DESTROYED,那么此时观察者Observer将被添加到LiveData的观察者列表中,同时该观察者会LifecycleOwner绑定,如果LifecycleOwner的生命周期状态变成DESTROYED,那么和这个LifecycleOwner绑定的观察者会自动被移除,这么做的好处就是可以避免很多可能会出现的内存泄漏。同时如果之前LiveData已经被设置过数据了,那么观察者会立刻接收到最新的数据。

如果之前LiveData没有观察者观察它,那第一次接受观察者会回调LiveData的onActive()方法。这个方法里面可以执行一些数据拉取操作,使数据处于处于最新状态,回调这个方法意味着该LiveData正在被使用中。

3.3 removeObserver()
这个方法有两个重载方法 removeObserver(Observer observer)和 removeObservers(LifecycleOwner owner) 一个是移除观察者,一个是移除和该LifecycleOwner所绑定的所有观察者。

如果LiveData的观察者列表中不存在活跃观察者了,也就是说没有一个观察者绑定的LifecycleOwner的Lifecycle处于 STARTED 或者RESUMED状态。这时候LiveData会回调onInactive()。这时候就算其持有的数据更新了,也不会发起通知。

3.4 其他方法
① hasActiveObservers():检查LiveData中是否有活跃的观察者。
② hasObservers():检查LiveData中是否有观察者。
③ observeForever(Observer observer):用于将一个Observer添加到一个活跃列表中,该列表将始终保持ACTIVE状态,因此永远不会自动从Observer实例列表中移除它。要移除此Observer时必须手动调用removeObserver()。
④ postValue(T value):在主线程中给LiveData设置值。

Tips:LiveData中的setValue(T value)、postValue(T value)都是protected,也就是说只能自己或者它的继承类进行调用。如果想在外面调用这些方法可以使用它的继承类MutableLiveData。

4.ViewModel

4.1 ViewModel实现
ViewModel这个类设计出来的目的是为了解决configuration 改变时候,Activity会重建,这时候里面的数据不易保存的问题。有了它Activity或者Fragment就可以不需要承担保留数据的责任了,可以把这些事情交给ViewModel,做到很好的数据和视图的解耦。同时ViewModel会在configuration 更改时自动保留数据。
在这里插入图片描述
ViewModel生命周期
官方给的建议是将LiveData+ViewModel配合来使用。当不需要ViewModel时(比如Activity调用finish()方法),ViewModel会回调onCleared()方法,之后会销毁自己。这一好处也是避免了内存泄漏的情况发生。

Activity正常销毁时的ViewModel
gg
例子如下:

public class MyViewModel extends ViewModel {
    private MutableLiveDatam<Integer> mValue= new MutableLiveData<>(); 
    public LiveData getValue(){
        return  mValue;
    }
    
    public void setValue(Integer value ){
        mValue.setValue(value);
    }
}

Tips: ViewModel可能比它所涉及的一些Activity/Fragment实例存活时间更长。**因此不要保留 Activity的Context和View相关的任何引用,不然可能引起内存泄漏。**如果想引用Application的Context,可以使用AndroidViewModel,可以通过其getApplication()来获取。

4.2 ViewModel使用
ViewModel的创建不能通过简单的new对象来进行。需要通过activity / fragment 获取ViewModel实例。为此,需要访问一个名为ViewModelProviders的辅助类 ,通过这样获取的ViewModel对于一个activity 只有一份:

MyViewModel mMyViewModel  = ViewModelProviders.of(getActivity()).get(MyViewModel .class);

ViewModelProviders这个类,本质上其实是一个工厂类。这个类内部包含了一个ViewModelStore实例,它负责存储创建的ViewModels。同时可以使用ViewModelProvider.get()方法来获取作为参数传入的ViewModel类型的实例。该方法源码如下:

@NonNull@MainThreadpublicT get(@NonNull String key, @NonNull Class modelClass) {

    ViewModel viewModel = mViewModelStore.get(key);//是否有创建过
    if (modelClass.isInstance(viewModel)) {
        // 无需检查之间返回
        return (T) viewModel;
    } else {
        if (viewModel != null) {
            //  输出警告日志
        }
    }

    // 创建一个ViewModel 对象并存入ViewModelStore。
    viewModel = mFactory.create(modelClass);
    mViewModelStore.put(key, viewModel);
    return (T) viewModel;
}

如源码所示,当调用此get()方法时,ViewModelProvider将检查ViewModelStore是否已具有该类类型的现有ViewModel,如果是,则将返回它。但是,如果不存在将创建一个新的ViewModel并将其添加到ViewModelStore中。
获取到ViewModel 就可以使用里面的属性和方法来进行操作了。

4.3 ViewModel 意义
ViewModel 被设计出来,不仅为了解决上面所说的configuration改变时候能保留数据。其真正意义在于以下几个方面:

职责分离:使Activity/Fragment不用再负责从某些数据源获取数据,只需要负责展示数据就好,同时还消除了在配置更改时保留数据对象实例的引用的责任。这两个职责都转给了ViewModel。

简化对没用数据的清理:当Activity/Fragment负责清理数据的操作时,需要使用大量代码来清理这些请求。但是将这些清理操作放到**ViewModels. onCleared()**方法中,这些资源在Activity结束时会自动清除。

减少类的膨胀:由于职责的转移,Activity/Fragment删除了许多用于处理请求,状态持久性和注销数据的代码。这些代码通常会导致Activity/Fragment变得非常臃肿,这样的代码会难以扩展和维护。使用ViewModels可以帮助开发者缓解Activity/Fragment的膨胀,,代码解耦,使各个类的职责尽可能单一。

容易测试:职责的分离会使测试这些职责更容易,而且还可以产生更细粒度的测试用例。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
代码实现: 定义一个观察者接口,用于接收消息通知: public interface Observer { void update(String message); } 定义一个主题接口,用于注册观察者和通知观察者: public interface Subject { void registerObserver(Observer observer); void removeObserver(Observer observer); void notifyObservers(String message); } 实现主题接口的订单类,表示用户下单成功: import java.util.ArrayList; import java.util.List; public class Order implements Subject { private String orderId; private String userName; private double amount; private String payType; private String status; private List<Observer> observers = new ArrayList<>(); public Order(String orderId, String userName, double amount, String payType, String status) { this.orderId = orderId; this.userName = userName; this.amount = amount; this.payType = payType; this.status = status; } public String getOrderId() { return orderId; } public String getUserName() { return userName; } public double getAmount() { return amount; } public String getPayType() { return payType; } public String getStatus() { return status; } public void setStatus(String status) { this.status = status; notifyObservers(status); } @Override public void registerObserver(Observer observer) { observers.add(observer); } @Override public void removeObserver(Observer observer) { observers.remove(observer); } @Override public void notifyObservers(String message) { for (Observer observer : observers) { observer.update(message); } } } 实现两个观察者,分别用于向用户发送短信和邮件: public class SmsNotify implements Observer { private String userName; public SmsNotify(String userName) { this.userName = userName; } @Override public void update(String message) { System.out.println(userName + ", 您的订单状态已更新为:" + message + ",请您注意查收。【电商平台】"); } } public class EmailNotify implements Observer { private String email; public EmailNotify(String email) { this.email = email; } @Override public void update(String message) { System.out.println(email + ", 您的订单状态已更新为:" + message + ",请您注意查收。【电商平台】"); } } 当用户下单成功时,在订单类中注册观察者: public class Main { public static void main(String[] args) { Order order = new Order("20220101001", "张三", 100.0, "支付宝", "待发货"); order.registerObserver(new SmsNotify("12345678901")); order.registerObserver(new EmailNotify("zhangsan@example.com")); order.setStatus("已发货"); } }要在myeclipse中成功运行,应该怎么做,补充代码或者写出实现步骤
05-26
要在MyEclipse中成功运行,可以按照以下步骤进行操作: 1. 创建一个Java项目,命名为ObserverDemo。 2. 在项目中新建Observer接口和Subject接口的Java文件,并按照题目中的代码进行定义。 3. 在项目中新建Order类的Java文件,并实现Subject接口的方法,同时在setStatus方法中调用notifyObservers方法通知观察者。 4. 在项目中新建SmsNotify和EmailNotify类的Java文件,并实现Observer接口的方法。 5. 在Main类中创建Order对象,然后向其注册两个观察者,最后调用setStatus方法更新订单状态。 完整代码如下: Observer.java ```java public interface Observer { void update(String message); } ``` Subject.java ```java public interface Subject { void registerObserver(Observer observer); void removeObserver(Observer observer); void notifyObservers(String message); } ``` Order.java ```java import java.util.ArrayList; import java.util.List; public class Order implements Subject { private String orderId; private String userName; private double amount; private String payType; private String status; private List<Observer> observers = new ArrayList<>(); public Order(String orderId, String userName, double amount, String payType, String status) { this.orderId = orderId; this.userName = userName; this.amount = amount; this.payType = payType; this.status = status; } public String getOrderId() { return orderId; } public String getUserName() { return userName; } public double getAmount() { return amount; } public String getPayType() { return payType; } public String getStatus() { return status; } public void setStatus(String status) { this.status = status; notifyObservers(status); } @Override public void registerObserver(Observer observer) { observers.add(observer); } @Override public void removeObserver(Observer observer) { observers.remove(observer); } @Override public void notifyObservers(String message) { for (Observer observer : observers) { observer.update(message); } } } ``` SmsNotify.java ```java public class SmsNotify implements Observer { private String userName; public SmsNotify(String userName) { this.userName = userName; } @Override public void update(String message) { System.out.println(userName + ", 您的订单状态已更新为:" + message + ",请您注意查收。【电商平台】"); } } ``` EmailNotify.java ```java public class EmailNotify implements Observer { private String email; public EmailNotify(String email) { this.email = email; } @Override public void update(String message) { System.out.println(email + ", 您的订单状态已更新为:" + message + ",请您注意查收。【电商平台】"); } } ``` Main.java ```java public class Main { public static void main(String[] args) { Order order = new Order("20220101001", "张三", 100.0, "支付宝", "待发货"); order.registerObserver(new SmsNotify("12345678901")); order.registerObserver(new EmailNotify("zhangsan@example.com")); order.setStatus("已发货"); } } ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值