Google Architecture Components应用框架初探

简介: Google Architecture Components应用框架初探

GoogleComponentsDemo


Google Architecture Components 演示程序


MVVM框架基础上简单使用了Room、LiveData、ViewModel框架组件。


微信截图_20220527210503.png


关于我


微信截图_20220527210536.png


演示效果(请star支持)



2018031518101311.gif


何为 Google Architecture Components


Google Architecture Components是Google在I/O大会上发布的一套应用框架库,它的使用基础是DataBinding和MVVM框架。详细介绍可参见:


http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2017/1107/8715.html


架构库的架构图


2018031518103119.png


架构库的基本组成


Lifecycle:Android声明周期的回调,帮助我们将原先需要在onStart()等生命周期回调的代码可以分离到Activity或者Fragment之外。


LiveData:一个数据持有类,持有数据并且这个数据可以被观察被监听,和其他Observer不同的是,它和Lifecycle是绑定的。


ViewModel:用于实现架构中的ViewModel,同时是与Lifecycle绑定的,使用者无需担心生命周期。方便在多个Fragment之前分享数据,比如旋转屏幕后Activity会重新create,这时候使用ViewModel可以方便使用之前的数据,不需要再次请求网络数


Room:谷歌推出的一个Sqlite ORM库,使用注解,极大简化数据库的操作。


框架的补充


框架补充:


如果不满足官方的库其实可以自己实现。比如LiveData在某些情况下可使用RxJava代替。


数据层官方推荐使用Room或者Realm或者其他Sqlite ORM等都可以。


网络请求推荐使用Retrofit。


各层之间的耦合推荐使用服务发现(Service Locator)或者依赖注入(DI),推荐Dagger。


如何使用Google Architecture Components


1.在Android Studio上使用,需要在module级别的build.gradle上添加对DataBinding的支持:


android {
    ....
    dataBinding {
        enabled = true
    }
}


2.配置Room schemaLocation


android {
    ....
    defaultConfig {
        ....
        //指定room.schemaLocation生成的文件路径
        javaCompileOptions {
            annotationProcessorOptions {
                arguments = ["room.schemaLocation": "$projectDir/schemas".toString()
                ]
            }
        }
    }
}


3.配置依赖dependencies


dependencies {
    ....
    // Architecture Components
    implementation "android.arch.persistence.room:runtime:1.0.0-alpha1"
    annotationProcessor "android.arch.persistence.room:compiler:1.0.0-alpha1"
    implementation "android.arch.lifecycle:runtime:1.0.0-alpha1"
    implementation "android.arch.lifecycle:extensions:1.0.0-alpha1"
    annotationProcessor "android.arch.lifecycle:compiler:1.0.0-alpha1"
}


4.配置使用Room


1.使用@Entity注解配置数据库的实体类


下面是用户信息数据库的实体配置:


@Entity(tableName = "_UserInfo")
public class UserInfoEntity {
    @PrimaryKey(autoGenerate = true)
    private int Id;
    /**
     * 登录名
     */
    @ColumnInfo(name = "name")
    private String LoginName;
    /**
     * 登录密码
     */
    @ColumnInfo(name = "password")
    private String LoginPassword;
    /**
     * 别名
     */
    private String Alias;
    /**
     * 年龄
     */
    private int Age;
    /**
     * 性别
     */
    private String Gender;
    /**
     * 出生日期
     */
    private Date BirthDay;
    /**
     * 签名
     */
    private String Signature = "这个家伙很懒,什么也没留下~~";
    ....
}


创建后生成的数据库表如下:


20180315181047245.png


2.构建数据库操作Dao


数据库操作Dao是一个加了@Dao注解修饰的接口,里面定义了数据库操作的方法,所有的数据库操作都是通过Sql语句实现的,查询出来的结果能够自动转化为实体对象或者LiveData对象。代码如下:


@Dao
public interface UserInfoDao {
    @Query("SELECT * FROM _UserInfo")
    LiveData<List<UserInfoEntity>> loadAllUserInfos();
    @Query("SELECT * FROM _UserInfo where name = :loginName and password = :loginPassword")
    LiveData<UserInfoEntity> queryUserInfo(String loginName, String loginPassword);
    /**
     * 同步操作
     *
     * @param loginName
     * @param loginPassword
     * @return
     */
    @Query("SELECT * FROM _UserInfo where name = :loginName and password = :loginPassword")
    List<UserInfoEntity> queryUserInfoSync(String loginName, String loginPassword);
    @Insert(onConflict = OnConflictStrategy.REPLACE)
    void insertAll(List<UserInfoEntity> userInfos);
}


需要注意的是,Room最好的特性之一是如果你在主线程中执行数据库操作,app将崩溃,显示下面的信息:


java.lang.IllegalStateException: Cannot access database on the main thread since it may potentially lock the UI for a long period of time.


3.构建数据库


继承RoomDatabase,并通过@Database注解进行数据库的信息配置,代码如下:


@Database(entities = {UserInfoEntity.class}, version = 1)
@TypeConverters(DateConverter.class)
public abstract class AppDatabase extends RoomDatabase {
  //注册数据库操作Dao
  public abstract UserInfoDao userInfoDao();
}


细心的你可能会发现,上面的数据库实体的字段里居然出现了”Date”对象!是的,Room数据库组件支持复杂类型的存储。只需要给数据库提供一个类型转化类,通过注解@TypeConverters配置即可,@TypeConverter是注解的转化方法。下面是Date转化为时间戳的方法:


public class DateConverter {
    @TypeConverter
    public static Date toDate(Long timestamp) {
        return timestamp == null ? null : new Date(timestamp);
    }
    @TypeConverter
    public static Long toTimestamp(Date date) {
        return date == null ? null : date.getTime();
    }
}


Room数据库的其他操作详解,可参见:


http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2017/0726/8249.html


5.将获取到的LiveData数据源填充到ViewModel中,并进行数据变化的绑定。


LiveData 是一款基于观察者模式的可感知生命周期的核心组件。LiveData 为界面代码 (Observer)的监视对象 (Observable),当 LiveData 所持有的数据改变时,它会通知相应的界面代码进行更新。代码如下:


public UserInfoListViewModel(Application application) {
    super(application);
    mObservableUserInfos = new MediatorLiveData<>();
    // set by default null, until we get data from the database.
    mObservableUserInfos.setValue(null);
    LiveData<List<UserInfoEntity>> userInfos = ((DemoApp) application).getRepository().getUserInfos();
    // observe the changes of the userInfos from the database and forward them
    mObservableUserInfos.addSource(userInfos, mObservableUserInfos::setValue);
}


6.如同MVVM框架中,将ViewModel绑定到View中


XML中注册ViewModel


<data>
    <variable
        name="UserInfoList"
        type="com.xuexiang.googlecomponentsdemo.viewmodel.UserInfoListViewModel" />
</data>


Activity/Fragment中设置绑定ViewModel


final UserInfoListViewModel viewModel = ViewModelProviders.of(this).get(UserInfoListViewModel.class);
binding.setUserInfoList(viewModel);


7.将LiveData数据源与View的生命周期进行绑定


这样LiveData数据源便能感知View的生命周期,并进行相应的处理。同时数据发生变化时,也能对View进行通知处理。


viewModel.getUserInfos().observe(this, new Observer<List<UserInfoEntity>>() {
    @Override
    public void onChanged(@Nullable List<UserInfoEntity> userInfoEntityList) {
        if (userInfoEntityList != null) {
            binding.setIsLoading(false);
            mUserInfoAdapter.setUserInfoList(userInfoEntityList);
        } else {
            binding.setIsLoading(true);
        }
        // espresso does not know how to wait for data binding's loop so we execute changes
        // sync.
        binding.executePendingBindings();
    }
});


以上便简单地使用了Google Architecture Components,总体来说功能比较实用,而且如果结合RxJava、Retrofit、Dagger2和ARouter后,将会更加强大。








相关文章
|
4月前
|
SQL API Android开发
Google I/O :Android Jetpack 最新变化(一) Architecture
Google I/O :Android Jetpack 最新变化(一) Architecture
70 0
|
3月前
|
数据可视化 定位技术 Sentinel
如何用Google Earth Engine快速、大量下载遥感影像数据?
【2月更文挑战第9天】本文介绍在谷歌地球引擎(Google Earth Engine,GEE)中,批量下载指定时间范围、空间范围的遥感影像数据(包括Landsat、Sentinel等)的方法~
551 0
如何用Google Earth Engine快速、大量下载遥感影像数据?
|
3月前
|
编解码 人工智能 算法
Google Earth Engine——促进森林温室气体报告的全球时间序列数据集
Google Earth Engine——促进森林温室气体报告的全球时间序列数据集
26 0
|
3月前
|
编解码 人工智能 数据库
Google Earth Engine(GEE)——全球道路盘查项目全球道路数据库
Google Earth Engine(GEE)——全球道路盘查项目全球道路数据库
45 0
|
3月前
|
编解码
Open Google Earth Engine(OEEL)——matrixUnit(...)中产生常量影像
Open Google Earth Engine(OEEL)——matrixUnit(...)中产生常量影像
21 0
|
3月前
Google Earth Engine(GEE)——导出指定区域的河流和流域范围
Google Earth Engine(GEE)——导出指定区域的河流和流域范围
45 0
|
3月前
|
传感器 编解码 数据处理
Open Google Earth Engine(OEEL)——哨兵1号数据的黑边去除功能附链接和代码
Open Google Earth Engine(OEEL)——哨兵1号数据的黑边去除功能附链接和代码
23 0
|
3月前
Google Earth Engine(GEE)——当加载图表的时候出现错误No features contain non-null values of “system:time_start“.
Google Earth Engine(GEE)——当加载图表的时候出现错误No features contain non-null values of “system:time_start“.
43 0
|
3月前
|
编解码 定位技术
Google Earth Engine(GEE)——导出后的影像像素不同于原始Landsat影像的分辨率(投影差异)
Google Earth Engine(GEE)——导出后的影像像素不同于原始Landsat影像的分辨率(投影差异)
24 0
|
3月前
|
机器学习/深度学习 算法 数据可视化
基于Google Earth Engine云平台构建的多源遥感数据森林地上生物量AGB估算模型含生物量模型应用APP
基于Google Earth Engine云平台构建的多源遥感数据森林地上生物量AGB估算模型含生物量模型应用APP
106 0

热门文章

最新文章