架构模板篇介绍了mvp,mvi,mvvm(databinding),今天介绍的这款安卓架构框架是Google在今天5月17号推出的:Architecture Components. 它的第一版本解决如下问题:
1)自动管理activity和fragment的生命周期,从而避免资源和内存溢出问题
2)持续化java对象到sqlite数据库
主要包括组成部分:
1)Lifecycle Components
2)LiveData
3)ViewModel
4)Rom (Database, entity, DAO)
它的两个主要设计原则:
1)单一原则,不要把所有代码都写在Activity/Fragment, 隔离独立的模块
2)model(数据)驱动UI
完整的架构图:
1.添加到项目工程
allprojects {
repositories {
jcenter()
maven { url 'https://maven.google.com' }
}
}
Lifecycles,LiveData, ViewModel,添加依赖:
compile "android.arch.lifecycle:runtime:1.0.0-alpha3"
compile "android.arch.lifecycle:extensions:1.0.0-alpha3"
annotationProcessor "android.arch.lifecycle:compiler:1.0.0-alpha3"
Room,添加依赖
compile "android.arch.persistence.room:runtime:1.0.0-alpha3"
annotationProcessor "android.arch.persistence.room:compiler:1.0.0-alpha3"
添加Room的test依赖:
testCompile "android.arch.persistence.room:testing:1.0.0-alpha3"
添加room的rxjava支持依赖:
compile "android.arch.persistence.room:rxjava2:1.0.0-alpha3"
2.处理Lifecycles
Lifecycle持有Activity/Fragment的lifecycle状态,允许其他对象观察这些状态变化。使用下面两种枚举类跟踪关联组件的lifecycle状态:
1)Event
2)State
其对应的活动图:
在代码中,使用@Annotation的方式标识对应的关联组件的生命周期
class MyLocationListener implements LifecycleObserver {
private boolean enabled = false;
public MyLocationListener(Context context, Lifecycle lifecycle, Callback callback) {
...
}
@OnLifecycleEvent(Lifecycle.Event.ON_START)
void start() {
if (enabled) {
// connect
}
}
public void enable() {
enabled = true;
if (lifecycle.getState().isAtLeast(STARTED)) {
// connect if not connected
}
}
@OnLifecycleEvent(Lifecycle.Event.ON_STOP)
void stop() {
// disconnect if connected
}
}
3.LiveData
LiveData是一个保存value和观察value变化的对象。不像其他的observable,它可以关联lifecycle.如果Observer的生命周期处于STARTED或RESUMED状态,则LiveData会将Observer视为活动状态。看下对面的代码片段:
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);
}
}
LiveData有三个方法:
1)onActive() 当LiveData有一个激活的observer时调用;
2)onInactive() 当LiveData没有任何激活的observer时调用;
3)setValue() 调用该方法更新LiveData的value,并通知相关的observer
在Fragment中使用LiveData:
public class MyFragment extends LifecycleFragment {
public void onActivityCreated (Bundle savedInstanceState) {
LiveData<Location> myLocationListener = ...;
Util.checkUserStatus(result -> {
if (result) {
myLocationListener.addObserver(this, location -> {
// update UI
});
}
});
}
}
它具有如下优势:
1)没有内存泄漏:因为它的observers绑定到对应的Lifecycle对象,所以当Lifecycle销毁了,对应的LiveData也会被清除
2)不会导致Crash而停止activities,同样因为Lifecycle影响observer,当observer处于inactive状态,不会去接收event
3)总是更新到最新数据,这个很方便
4)正确处理configuration change(比如屏幕旋转),当屏幕旋转后,他仍然可以获取最新的可用数据
5)共享资源,可以把LiveData弄成单例模式
6)因为它绑定了Lifecycle,所以不需要手动管理Activity/Fragment对应的生命周期了。
4.ViewModel
它的设计就是为了保存和管理UI关联的数据,这样使得configuration change(比如屏幕旋转)发生时,数据可以恢复。
回顾下Activity恢复数据,如果Activity被重新创建或者发生屏幕旋转,保存和恢复周期
onCreate()
onSaveInstanceState()
onRestoreInstanceState()
但是它有缺点:只允许保存少量的数量,对于需要保存大量的数据:比如界面上所有的用户列表信息,无能为力。
Lifecycle提供了ViewModel,它负责为UI提供数据,ViewModel会自动保留当发生屏幕旋转时。这样就实现了代码分离: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
}
}
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被重新创建后,它会使用同样的ViewModel实例(上一个Activity创建的),当对应的activity被销毁了,框架会 调用ViewModel的onCleared方法来销毁资源。
注意:由于ViewModel超出了具体的Activity和Fragment实例生命周期,所以它不应该引用View或任何可能持有对活动上下文的引用的类。 如果ViewModel需要应用程序上下文(例如,找到系统服务),则可以扩展AndroidViewModel类,并在构造函数中接收应用程序的构造函数(因为Application类扩展了Context)
4.1实现fragment之间数据共享
很常见,一个Activity有多个Fragment, 而实现fragment之间的数据共享或者叫数据传递比较麻烦
fragment.setArgs(Bundle)
Bundle bundle = fragment.getArgs()
而ViewModel帮我们简化了,看下下面的代码示例
public class SharedViewModel extends ViewModel {
private final MutableLiveData<Item> selected = new MutableLiveData<Item>();
public void select(Item item) {
selected.setValue(item);
}
public LiveData<Item> getSelected() {
return selected;
}
}
public class MasterFragment extends Fragment {
private SharedViewModel model;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
model = ViewModelProviders.of(getActivity()).get(SharedViewModel.class);
itemSelector.setOnClickListener(item -> {
model.select(item);
});
}
}
public class DetailFragment extends LifecycleFragment {
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
SharedViewModel model = ViewModelProviders.of(getActivity()).get(SharedViewModel.class);
model.getSelected().observe(this, { item ->
// update UI
});
}
}
这种机制的优势:
1)对activity来说,它是完全隔离,不知道任何fragment之间的细节
2)fragment之间不需要互相关注,除了ViewModel的细节
3)fragment实现互相独立。
5.Room
Room是一个持续library,Room在SQLite上提供了一个抽象层,以便在利用SQLite的全部功能的同时使流畅的数据库访问。它包括了三个主要组件:
1)Database
2)Entity
3)DAO
Room的架构设计图如下:
从左到右的顺序:database, DAO, entity
下面几个代码判断,展示了怎么编写这几个组件,以及怎么使用
1)Entity
@Entity
public class User {
@PrimaryKey
private int uid;
@ColumnInfo(name = "first_name")
private String firstName;
@ColumnInfo(name = "last_name")
private String lastName;
// Getters and setters are ignored for brevity,
// but they're required for Room to work.
}
2)DAO
@Dao
public interface UserDao {
@Query("SELECT * FROM user")
List<User> getAll();
@Query("SELECT * FROM user WHERE uid IN (:userIds)")
List<User> loadAllByIds(int[] userIds);
@Query("SELECT * FROM user WHERE first_name LIKE :first AND "
+ "last_name LIKE :last LIMIT 1")
User findByName(String first, String last);
@Insert
void insertAll(User... users);
@Delete
void delete(User user);
}
3)Database
@Database(entities = {User.class}, version = 1)
public abstract class AppDatabase extends RoomDatabase {
public abstract UserDao userDao();
}
4)使用
AppDatabase db = Room.databaseBuilder(getApplicationContext(),
AppDatabase.class, "database-name").build();
5.总结
Lifecycle, LiveData,ViewModel,Room看起来是独立的,确实它们各自负责各自的功能,但是它们一旦串联起来,你会发现很多头疼的问题,比如:代码分离,数据持续化,异步加载结束确保Activity/Fragment没有被销毁后刷新UI,这些问题都透过架构的方式帮我们处理好了,既然它有这么多的优势还是值得一用的。
但是需要注意的是:它怎么样也只是一个架构模板,如果你有比它更好用的架构模板,可以比较之后再做出选择。
官方例子:
https://github.com/googlesamples/android-architecture-components
我的fork:https://github.com/Sherchen/android-architecture-components
来自developer上的blog:
https://android-developers.googleblog.com/2017/05/android-and-architecture.html
来自youtube上的官方video介绍:
https://www.youtube.com/watch?v=vOJCrbr144o