Android官方应用程序架构设置指南--Architecture Components

Handling Lifecycles

使用 android.arch.lifecycle 包提供的接口和类可以创建感知生命周期组件,这类组件可以根据当前Activity和Fragment的生命周期自动的调整行为。LiveData就是一种感知生命周期的组件。

Android框架中的大部分系统组件都是有生命周期限制的。生命周期由操作系统或者运行在用户进程中的框架代码来进行管理。这是Android系统的核心应用程序必须遵守。如果不这样就会引起内存泄露或者应用崩溃。

Lifecycle


Lifecycle类持有组件(Activity或者Fragment)的生命状态信息,并且可以通过LifecycleObserver来监听这些状态。
Lifecycle通过两个方面来追踪关联应用程序组件的状态。

Event
生命周期事件由系统和Lifec类分发。该事件一一对应Activity和Fragment的回调函数。
State
Lifecycle对象追踪的系统组件当前处于的状态。

这里写图片描述

Lifecycles 最佳实践

  • UI Controller(Activity/Fragment)越轻越好。使用ViewModel来查询数据,而不是在UI Controller中查询数据,然后通过监听LiveData来改变View的状态。

  • UI界面应该是由数据驱动的,UI Controller的职责是当数据变化时更新界面,或者将用户的操作通知到ViewModel。

  • 将业务逻辑放在ViewModel类中。ViewModel是UI Controller和非UI逻辑的桥梁。但是请注意,ViewModel不应该直接获取数据(比如发起网络请求)。正确的方式是ViewModel通过调用合适的组件去获取数据,然后提供结果给UI Controller。

  • 使用Data Binding可以更清晰的隔离UI界面和UI Controller。这样你就不需要在Activity和Fragment中编写太多的代码了。

  • 如果你的界面太复杂,考虑创建一个Presenter类去处理UI的更改。通常不需要这样做,但是这样可能有利于UI的测试。

  • 不要在ViewModel中持有View或者Activity的引用。如果ViewModel不依赖于Activity的生命周期,那么就会引起内存的泄露。

LiveData

LiveData持有数据并且允许被监听。和常见的被观察者(Observable)不同,LiveData关心应用程序组件的生命周期,所以可以为观察者可以指定为一个Lifecycle,LiveData就可以根据指定的Lifecycle来决定何时添加该观察者何时移除该观察者。

LiveData认为观察者处理活跃状态,当观察者的Lifecycle处理STARTED或者RESUMED状态。

public class LocationLiveData extends LiveData<Location> {
    private LocationManager locationManager;

    private SimpleLocationListener listener = new SimpleLocationListener() {
        @Override
        public void onLocationChanged(Location location) {
            setValue(location);
        }
    };

    public LocationLiveData(Context context) {
        locationManager = (LocationManager) context.getSystemService(
                Context.LOCATION_SERVICE);
    }

    @Override
    protected void onActive() {
        locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, listener);
    }

    @Override
    protected void onInactive() {
        locationManager.removeUpdates(listener);
    }
}

有三个重要的部分
onActive()
当LiveData有一个活跃的观察者,该方法被调用。此时需要启动监听设备位置的变化
onInactive()
当所有活跃的观察者都不存在了,该方法被调用。
setValue()
更新LiveData的值,并且通知活跃的观察者。

接下来看看怎么使用LocationLiveData

public class MyFragment extends LifecycleFragment {
    public void onActivityCreated (Bundle savedInstanceState) {
        LiveData<Location> myLocationListener = ...;
        Util.checkUserStatus(result -> {
            if (result) {
                myLocationListener.addObserver(this, location -> {
                    // update UI
                });
            }
        });
    }
}

注意addObserver()方法的第一个参数是LifecycleOwner类,将该观察者和这个Lifecycle绑定。

  • 如果Lifecycle不处于激活状态(STARTED或者RESUMED),数据的变化不会调用Observer。
  • Lifecycle被销毁,Observer自动被移除。

LiveData可以感知lifecycle的变化,这样的好处就是:它可以在多个Activity,Fragment中被共享。如下例所示,我们将LocationLiveData改成了单例模式:

public class LocationLiveData extends LiveData<Location> {
    private static LocationLiveData sInstance;
    private LocationManager locationManager;

    @MainThread
    public static LocationLiveData get(Context context) {
        if (sInstance == null) {
            sInstance = new LocationLiveData(context.getApplicationContext());
        }
        return sInstance;
    }

    private SimpleLocationListener listener = new SimpleLocationListener() {
        @Override
        public void onLocationChanged(Location location) {
            setValue(location);
        }
    };

    private LocationLiveData(Context context) {
        locationManager = (LocationManager) context.getSystemService(
                Context.LOCATION_SERVICE);
    }

    @Override
    protected void onActive() {
        locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, listener);
    }

    @Override
    protected void onInactive() {
        locationManager.removeUpdates(listener);
    }
}

现在Fragment也可以使用了:

public class MyFragment extends LifecycleFragment {
    public void onActivityCreated (Bundle savedInstanceState) {
        Util.checkUserStatus(result -> {
            if (result) {
                LocationLiveData.get(getActivity()).observe(this, location -> {
                   // update UI
                });
            }
        });
  }
}

现在可能有多个fragment和activity监听MyLocationListener 实例,LiveData会优雅的管理他们,当任意一个界面可见(即被激活),它就会连接到系统服务。

以下是LiveData类的优点:

  • 避免内存泄露:因为观察者与Lifecycle绑定,所以当Lifecycle销毁时他们会被自动清理。
  • Activity的停止不会引起崩溃:如果观察者的Lifecycle未被激活(如果在回退栈中),他们不会收到变换事件。
  • 总是能获取最新的数据:Lifecycle重新启动(比如Activity从回退栈中重新显示)他会收到最新的数据。
  • 适配配置更新:当Activity或者Fragment因为配置的更新被重新创建(比如屏幕翻转),他们会立即收到最后的数据。
  • 资源可以共享:MyLocationListener使用了单例模式,只连接到系统服务一次,可以支持所有的Observer。
  • 不需要手动的处理生命周期:Fragment只需要监测他需要的数据,无需关心何时停止。Fragment只需要提供他的Lifecycle来监测,其余的LiveData都会自动管理。

LiveData的变换


有时你希望在LiveData分发数据给观察者之前改变他的值。或者你希望将一个LiveData转变为另一个LiveData然后返回。

ViewModel

ViewModel负责存储和管理UI有关的数据,当屏幕翻转等配置更改时数据就不会被销毁了。
应用程序组件比如Activity和Fragment,他们的生命周期由系统来管理。系统觉得何时销毁和重建,这些都不受应用程序的控制。所以在这些组件里保存数据就不明智了。
比如,一个展示用户列表的Activity,当用户旋转屏幕时,一个新的Activity就会被创建,当然所有的用户数据又要重新地获取。
对于简单的数据,可以通过Activity的onSaveInstanceState()方法保存,然后通过onCreate()的bundle来获取。但是这种方式只适应于少量数据量的情况。不适用上述这种可能有大量数据的情况。
另一个问题是,UI Controller(Activity,Fragment等)耗时的操作就需要异步调用,不然会阻塞UI线程。UI Controller就需要管理这些异步调用,比如当其被系统销毁时就需要停止异步调用并清理占用的资源不然就有可能会出现内存泄漏问题。这就要求你做很多的管理工作,当然如果用户旋转屏幕重建View时你又重新发起一个相同的请求,这也是一种资源的浪费。
最后,重要的一点,UI Controller的作用是响应用户操作,和操作系统通信。如果他还需要处理其他资源和类,那他就变成了一个上帝类了。也就是所有的操作都自己来,而不是把相关功能委托给其他类。退一步讲这样的类怎么来测试呢。
为了简单更有效的从UI Controller中分离出数据的所有权,Lifecycle提供了一个ViewModel类,他可以帮助UI Controller获取UI数据。当旋转屏幕等配置更改后ViewModel可以自动的维护UI数据,当新的Activity和Fragment创建好后这些数据就可以立即使用了。所以在上面的例子中,用户列表数据的获取和保存就由ViewModel来实现,而不是通过Activity和Fragment。

public class MyViewModel extends ViewModel {
    private MutableLiveData<List<User>> users;
    public LiveData<List<User>> getUsers() {
        if (users == null) {
            users = new MutableLiveData<List<Users>>();
            loadUsers();
        }
        return users;
    }

    private void loadUsers() {
        // do async operation to fetch users
    }
}

Activity怎么使用这些数据呢?如下

public class MyActivity extends AppCompatActivity {
    public void onCreate(Bundle savedInstanceState) {
        MyViewModel model = ViewModelProviders.of(this).get(MyViewModel.class);
        model.getUsers().observe(this, users -> {
            // update UI
        });
    }
}

如果Activity重新创建,他会获取到由之前Activity创建的同一个MyViewModel实例。当Activity finished时,系统会调用ViewModel的onCleared()方法,你可以在该方法中清理占用的资源。

注意:因为ViewModel的生命周期比Activity和Fragment要长,所以不要在该类中保存View或者其他引用Activity Context的对象。如果ViewModel需要Application Context(比如获取系统服务)可以通过继承AndroidViewModel类来实现。

Fragment间共享数据


使用Fragment很常见的一个场景是,一个Activity中包含两个或者更多的Fragment,而且这些Fragment之间还需要交互。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
本项目是一个基于SpringBoot开发的华府便利店信息管理系统,使用了Vue和MySQL作为前端框架和数据库。该系统主要针对计算机相关专业的正在做毕设的学生和需要项目实战练习的Java学习者,包含项目源码、数据库脚本、项目说明等,有论文参考,可以直接作为毕设使用。 后台框架采用SpringBoot,数据库使用MySQL,开发环境为JDK、IDEA、Tomcat。项目经过严格调试,确保可以运行。如果基础还行,可以在代码基础之上进行改动以实现更多功能。 该系统的功能主要包括商品管理、订单管理、用户管理等模块。在商品管理模块中,可以添加、修改、删除商品信息;在订单管理模块中,可以查看订单详情、处理订单状态;在用户管理模块中,可以注册、登录、修改个人信息等。此外,系统还提供了数据统计功能,可以对销售数据进行统计和分析。 技术实现方面,前端采用Vue框架进行开发,后端使用SpringBoot框架搭建服务端应用。数据库采用MySQL进行数据存储和管理。整个系统通过前后端分离的方式实现,提高了系统的可维护性和可扩展性。同时,系统还采用了一些流行的技术和工具,如MyBatis、JPA等进行数据访问和操作,以及Maven进行项目管理和构建。 总之,本系统是一个基于SpringBoot开发的华府便利店信息管理系统,使用了Vue和MySQL作为前端框架和数据库。系统经过严格调试,确保可以运行。如果基础还行,可以在代码基础之上进行改动以实现更多功能。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值