Android Jetpack--Architecture(架构 下) 返回首页

发表于 2019-01-02 | 本文共 2761 字

Android Jetpack–Architecture(架构)

[TOC]

五、DataBinding

1.简介

数据绑定库是一个支持库,允许您使用声明性的格式而不是以编程方式将布局中的UI组件绑定到应用程序中的数据源。 布局通常在具有调用UI框架方法的代码的活动中定义。

####2.如何使用DataBinding

数据绑定库提供了灵活性和广泛的兼容性 - 它是一个支持库,因此您可以将其用于运行Android 4.0(API级别14)或更高版本的设备。

建议在项目中使用最新的Gradle Android插件。但是,版本1.5.0及更高版本支持数据绑定。

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

注意:如果app依赖了一个使用 Data Binding 的库,那么app module 的 build.gradle 也必须配置 Data Binding。

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
   <data>
       <variable name="user" type="com.example.User"/>
   </data>
   <LinearLayout
       android:orientation="vertical"
       android:layout_width="match_parent"
       android:layout_height="match_parent">
       <TextView android:layout_width="wrap_content"
           android:layout_height="wrap_content"
           android:text="@{user.firstName}"/>
       <TextView android:layout_width="wrap_content"
           android:layout_height="wrap_content"
           android:text="@{user.lastName}"/>
   </LinearLayout>
</layout>
data class User(val firstName: String, val lastName: String)

为每个布局文件生成绑定类。 默认情况下,类的名称基于布局文件的名称,将其转换为Pascal大小写并向其添加Binding后缀。 上面的布局文件名是activity_main.xml,因此相应的生成类是ActivityMainBinding。 此类包含布局属性(例如,用户变量)到布局视图的所有绑定,并知道如何为绑定表达式指定值。创建绑定的推荐方法是在扩展布局时执行此操作,如 如下例所示:

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)

    val binding: ActivityMainBinding = DataBindingUtil.setContentView(
            this, R.layout.activity_main)

    binding.user = User("Test", "User")
}

在运行时,应用程序在UI中显示Test用户。或者,您可以使用LayoutInflater获取视图,如以下示例所示:

val binding: ActivityMainBinding = ActivityMainBinding.inflate(getLayoutInflater())

如果在Fragment,ListView或RecyclerView适配器中使用数据绑定项,则可能更喜欢使用绑定类或DataBindingUtil类的inflate()方法,如以下代码示例所示:

val listItemBinding = ListItemBinding.inflate(layoutInflater, viewGroup, false)
// or
val listItemBinding = DataBindingUtil.inflate(layoutInflater, R.layout.list_item, viewGroup, false)

表达式语言看起来很像托管代码中的表达式。您可以在表达式语言中使用以下运算符和关键字:

数学运算 + - / * %
字符串连接 +
逻辑运算 && ||
二进制运算 & | ^
一元运算符 + - ! ~
位移运算 >> >>> <<
比较运算 == > < >= <=
instanceof
组 ()
字面量 - 字符,字符串,数字,null
类型转换
函数调用
字段存取
数组存取 []
三元运算符 ?:
android:text="@{String.valueOf(index + 1)}"
android:visibility="@{age < 13 ? View.GONE : View.VISIBLE}"
android:transitionName='@{"image_" + id}'

3.参考内容

https://www.jianshu.com/p/c1403af34932

https://developer.android.com/topic/libraries/data-binding/?hl=zh-cn#using_the_data_binding_library

六、LiveData

1.简介

LiveData是一个用于持有数据并支持数据可被监听(观察)。和传统的观察者模式中的被观察者不一样,LiveData是一个生命周期感知组件,因此观察者可以指定某一个LifeCycle给LiveData,并对数据进行监听。

如果观察者指定LifeCycle处于Started或者RESUMED状态,LiveData会将观察者视为活动状态,并通知其数据的变化。

2.如何使用LiveData

3.参考内容

​ https://developer.android.com/topic/libraries/architecture/livedata?hl=zh-cn#transform_livedata

​ https://www.jianshu.com/p/13ed71d42b4e

​ https://juejin.im/post/5937e402a0bb9f005808d00e

七、Paging

1.简介

Paging 使您的应用程序配合RecyclerView更容易从数据源中高效优雅地加载所需的数据,不会因为数据库数据量大而造成查询时间过长。

在我们的实际项目中有大量的数据,但是我们常常只需要向用户展示一小部分信息。例如,一个应用中可能会有几千个item但是我们常常只需要显示十几个或者几十个。我们处理不当加载数据时可能会造成APP崩溃。如果数据被存储或与远程数据库同步,这也会减慢应用程序的速度,影响用户的体验。

Paging库能够提供给你的app观察和显示这个数据合理的子集。这个功能库有几个优点:

  1. 数据请求占用比较少的网络带宽和系统资源。
  2. 在数据更新和刷新期间,App也能够快速响应用户输入。 如果你的app已经包含了分页处理的逻辑,我们已经提供了更新现有app的指导。

2.如何使用Paging

dependencies {
    def paging_version = "2.1.0-rc01"

    implementation "androidx.paging:paging-runtime:$paging_version" // use -ktx for Kotlin

    // alternatively - without Android dependencies for testing
    testImplementation "androidx.paging:paging-common:$paging_version" // use -ktx for Kotlin

    // optional - RxJava support
    implementation "androidx.paging:paging-rxjava2:$paging_version" // use -ktx for Kotlin
}

Paging Library的关键组件是PagedList类,它是一个异步加载应用程序数据块或页面的集合。此类充当应用程序架构的其他部分之间的中介:

Data

PagedList的每个实例都从其DataSource加载应用程序数据的最新快照。数据从应用程序的后端或数据库流入PagedList对象。

分页库支持各种应用程序体系结构,包括独立数据库和与后端服务器通信的数据库

有关详细信息,请参阅数据组件和注意事项

UI

PagedList类与PagedListAdapter一起使用,可以将项目加载到RecyclerView中。这些类一起工作以在加载内容时获取和显示内容,预取视图内容并动画内容更改。

要了解更多信息,请参阅UI组件和注意事项

分页库实现了观察者模式。实际上,这些组件会创建一个LiveData<PagedList>数据对象(或者Rxjava2基础类的可观察数据对象)你的app UI就可以将这些数据从PagingList中展示,同时具有可控的生命周期。

分页库支持三种数据获取:仅从网络获取;仅从本地数据库获取;从网络和数据库同时获取。

我们提供了用于不同数据架构的推荐模式的示例。要查看它们,请参阅GitHub上的PagingWithNetwork示例

class ConcertViewModel {
    fun search(query: String): ConcertSearchResult {
        val boundaryCallback =
                ConcertBoundaryCallback(query, myService, myCache)
        // Use a LiveData object to communicate your network's state back
        // to your app's UI, as in the following example. Note that error
        // handling isn't shown in this snippet.
        // val loadingState: LiveData<MyNetworkState> =
        //        boundaryCallback.loadingState
    }
}

class ConcertBoundaryCallback(
        private val query: String,
        private val service: MyService,
        private val cache: MyLocalCache
) : PagedList.BoundaryCallback<Concert>() {
    // Requests initial data from the network, replacing all content currently
    // in the database.
    override fun onZeroItemsLoaded() {
        requestAndReplaceInitialData(query)
    }

    // Requests additional data from the network, appending the results to the
    // end of the database's existing data.
    override fun onItemAtEndLoaded(itemAtEnd: Concert) {
        requestAndAppendData(query, itemAtEnd.key)
    }
}

要查看分页库解决方案如何从网络和数据库中获取数据的更多扩展示例,请导航到GitHub上的Paging codelabPagingWithNetwork示例

3.参考内容

https://www.jianshu.com/p/a05943b8a9c1

https://juejin.im/entry/5b0d3b0251882532321468ff

https://developer.android.com/topic/libraries/architecture/paging/?hl=zh-cn

八、ViewModel

1.简介

ViewModel课程旨在存储和管理用户界面相关的数据生命周期中的意识的方式。在 ViewModel类允许数据生存如屏幕旋转配置更改。

Android框架管理UI控制器的生命周期,例如活动和片段。框架可以决定销毁或重新创建UI控制器以响应完全不受您控制的某些用户动作或设备事件。

如果系统销毁或重新创建UI控制器,则存储在其中的任何瞬态UI相关数据都将丢失。例如,您的应用可能会在其中一项活动中包含用户列表。为配置更改重新创建活动时,新活动必须重新获取用户列表。对于简单数据,活动可以使用该onSaveInstanceState()方法并从包中恢复其数据 onCreate(),但此方法仅适用于可以序列化然后反序列化的少量数据,而不适用于潜在的大量数据,如用户列表或位图。

另一个问题是UI控制器经常需要进行可能需要一些时间才能返回的异步调用。UI控制器需要管理这些调用并确保系统在销毁后清理它们以避免潜在的内存泄漏。此管理需要大量维护,并且在为配置更改重新创建对象的情况下,这会浪费资源,因为对象可能必须重新发出已经进行的调用。

诸如活动和片段之类的UI控制器主要用于显示UI数据,对用户操作作出反应或处理操作系统通信,例如许可请求。要求UI控制器也负责从数据库或网络加载数据,这会给类增加膨胀。为UI控制器分配过多的责任可能导致单个类尝试自己处理应用程序的所有工作,而不是将工作委托给其他类。以这种方式为UI控制器分配过多的责任也会使测试变得更加困难。

将视图数据所有权与UI控制器逻辑分离起来更容易,更有效。

2.如何使用ViewModel

dependencies {
    def lifecycle_version = "2.0.0"
    // alternatively - just ViewModel
    implementation "androidx.lifecycle:lifecycle-viewmodel:$lifecycle_version" // use -ktx for Kotlin
 
}

Architecture Components为ViewModelUI控制器提供 帮助程序类,负责为UI准备数据。 ViewModel在配置更改期间会自动保留对象,以便它们保存的数据可立即用于下一个活动或片段实例。例如,如果您需要在应用中显示用户列表,请确保分配责任以获取并保留用户列表 ViewModel,而不是活动或片段,如以下示例代码所示:

class MyViewModel : ViewModel() {
    private lateinit var users: MutableLiveData<List<User>>

    fun getUsers(): LiveData<List<User>> {
        if (!::users.isInitialized) {
            users = MutableLiveData()
            loadUsers()
        }
        return users
    }

    private fun loadUsers() {
        // Do an asynchronous operation to fetch users.
    }
}

然后,您可以从活动中访问列表,如下所示:

class MyActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        // Create a ViewModel the first time the system calls an activity's onCreate() method.
        // Re-created activities receive the same MyViewModel instance created by the first activity.

        val model = ViewModelProviders.of(this).get(MyViewModel::class.java)
        model.getUsers().observe(this, Observer<List<User>>{ users ->
            // update UI
        })
    }
}

如果重新创建活动,它将接收由第一个活动创建的相同MyViewModel实例。当所有者活动完成时,框架调用ViewModel对象的onCleared()方法,以便它可以清理资源。

注意:ViewModel绝不能引用视图,生命周期或任何可能包含对活动上下文的引用的类。

ViewModel对象被设计为比视图的特定实例更长久 LifecycleOwners。此设计还意味着您可以编写测试以ViewModel更轻松地覆盖, 因为它不了解视图和 Lifecycle对象。 ViewModel 对象可以包含 LifecycleObservers,例如LiveData对象。但是, ViewModel对象必须永远不会观察到生命周期感知的可观察LiveData对象(例如对象)的更改。如果 ViewModel需要 Application上下文,例如查找系统服务,它可以扩展 AndroidViewModel 类并具有在构造函数中接收Application 的构造函数,因为Application类扩展Context

ViewModel对象的范围是Lifecycle传递给 ViewModelProvider 获取时的 ViewModelViewModel内存中的 遗骸直到Lifecycle 它的范围永久消失:在活动的情况下,当它完成时,在片段的情况下,当它被分离时。

图1显示了活动经历轮换然后结束时的各种生命周期状态。该图还显示ViewModel了相关活动生命周期的 下一个生命周期。此特定图表说明了活动的状态。相同的基本状态适用于片段的生命周期。

说明ViewModel作为æ´"动更改状态的生命周期。

您通常ViewModel在系统第一次调用活动对象的onCreate()方法时 请求 。系统可以onCreate()在活动的整个生命周期中多次调用 ,例如在旋转设备屏幕时。在 ViewModel存在从当你第一次请求 ViewModel,直到活动结束和销毁。

活动中的两个或多个片段需要相互通信是很常见的。想象一下主从细节片段的常见情况,其中有一个片段,用户从列表中选择一个项目,另一个片段显示所选项目的内容。这种情况从来都不是微不足道的,因为两个片段都需要定义一些接口描述,并且所有者活动必须将两者绑定在一起。此外,两个片段都必须处理尚未创建或可见其他片段的场景。

这个常见的痛点可以通过使用ViewModel对象来解决 。这些片段可以共享 ViewModel使用其活动范围来处理此通信,如以下示例代码所示:

class SharedViewModel : ViewModel() {
    val selected = MutableLiveData<Item>()

    fun select(item: Item) {
        selected.value = item
    }
}

class MasterFragment : Fragment() {

    private lateinit var itemSelector: Selector

    private lateinit var model: SharedViewModel

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        model = activity?.run {
            ViewModelProviders.of(this).get(SharedViewModel::class.java)
        } ?: throw Exception("Invalid Activity")
        itemSelector.setOnClickListener { item ->
            // Update the UI
        }
    }
}

class DetailFragment : Fragment() {

    private lateinit var model: SharedViewModel

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        model = activity?.run {
            ViewModelProviders.of(this).get(SharedViewModel::class.java)
        } ?: throw Exception("Invalid Activity")
        model.selected.observe(this, Observer<Item> { item ->
            // Update the UI
        })
    }
}

请注意,两个片段都会检索包含它们的活动。这样,当每个片段都获得时 ViewModelProvider,它们会收到相同的SharedViewModel实例,该实例的范围限定为此活动。

​ 这种方法具有以下优点:

类似的Loader类CursorLoader经常用于将应用程序UI中的数据与数据库保持同步。您可以使用 ViewModel其他几个类来替换加载器。使用a ViewModel将UI控制器与数据加载操作分开,这意味着类之间的强引用较少。

在使用加载器的一种常见方法中,应用程序可能使用a CursorLoader来观察数据库的内容。当数据库中的值发生更改时,加载程序会自动触发重新加载数据并更新UI:

图2.使用加载器加载数据

ViewModelRoomLiveData一起使用来替换加载器。在ViewModel该数据存续的设备配置改变确保。 房间通知您LiveData数据库更改的时间,然后LiveData会使用修改后的数据更新您的UI。

图3.使用ViewModel加载数据

3.参考内容

https://developer.android.google.cn/topic/libraries/architecture/viewmodel

https://www.jianshu.com/p/a05943b8a9c1

https://www.jianshu.com/p/59adff59ed29


显示评论