首页 安卓& Kotlin Books 高级Android应用架构

4
Android建筑组件 由云成撰写

多年来,Android开发人员必须处理数据库映射,生命周期管理问题,异步操作和其他容易出错的棘手挑战,并导致样板代码。 2017年11月,谷歌介绍了 Android建筑组件,一个库的集合,以帮助一些与这些建筑相关的痛点。本书在各个分数的示例项目中使用其中几个: 房间, LiveData., viewmodel.数据绑定.

本章概述了这些库,并在示例项目中使用这些子集进行详细信息。虽然没有示例项目 章节,您将查看其他章节的示例项目,以查看这些库的操作。对于未在示例项目中未涵盖的Android架构组件,提供有关免费教程的链接,您可以在这里了解更多信息。

房间

房间 图书馆处理应用程序的持久性。房间提供了SQLite上的抽象层,可以轻松地将对象直接映射到原始数据库内容,并轻松定义与数据交互的类型安全查询。这是通过使用在场景后面生成样板代码的注释来实现的。

生命周期

该图书馆优惠中的课程集 生命周期管理,允许您创建可以根据当前的Android生命周期状态自动调整其行为的组件。

要查看使用此库的示例,您可以阅读本教程: www.raywenderlich.com/164-android-architionure-components-getting-started..

viewmodel.

A viewmodel. 在存储库和视图之间提供数据。与在配置更改的活动销毁的活动不同,ViewModels生存配置更改,保持数据安全和保存状态。

LiveData.

如果您之前使用过rxjava, LiveData. 是一个类似的库(具有缩小的功能),允许Android视图观察模型更改并相应地响应。 Livevata也是Lifecycle-Inveor,所以它只会告诉UI如果它是正确的生命周期状态,请更新内容。与您必须处理自己的Rxjava订阅,它也会为您进行清理干净。

数据绑定

数据绑定 库允许您在视图XML中直接观察ViewModel的更改。这节省您必须编写通常需要绑定数据以在代码中查看视图的水库代码。

分页

分页 库可帮助您通过在小块中加载数据并随着加载更多数据更新UI来显示列表(尤其是无限的)。

要了解有关此主题的更多信息,请阅读本教程: www.raywenderlich.com/6948-paging-library-for-android-with-kotlin-creating-infinite-lists..

导航

导航 架构组件允许您使用XML图形或通过内置于最新版本的Android Studio的图形编辑器在整个应用中指定导航。它通过样板代码减少了自己处理它的麻烦。

本教程将有助于您开始使用此库: www.raywenderlich.com/6014-the-neavigation-carchitecture-component-tutorial-getting-started..

WorkManager.

WorkManager. 图书馆管理需要保证执行的可推迟背景任务。

有关更多信息,请阅读本教程: www.raywenderlich.com/6040-workmanager-tutorial-for-android-getting-started..

使用Android架构组件

ph!这是一个长长的组件列表。将它们绑在一起可能是一个艰巨的任务,但每个人在谈论架构时都有一个非常重要的作用。在本节中,您将介绍Wewatch应用程序如何使用这些组件中的一些组件。

房间

在本书中,示例项目使用 房间 图书馆的数据库操作。

从中打开初学项目 MVC 第2章并查看代码以查看它的实施方式。具体来说,打开并查看移动实体 电影.Kt.,数据访问对象 moviedai.kt.,发现的数据库类 localDatabase.kt. 和找到的数据源类 localDataSource.kt..

In WeWatch, the main data object of interest is Movie, and the app persists a user’s list of movies by storing each movie as a row in a database table. With Room, it’s easy to create a table named movie_table representing the Movie class in the database.

For any class whose fields you wish to directly map in a database table, use the @Entity annotation above the declaration for the class. By default, this creates a table with the same name as the class. You can also give the table a different name by explicitly setting the tableName, as is done in 电影.Kt.:

@Entity(tableName = "movie_table")
data class Movie(...) {...}

By default, the columns for this table have the same names as the fields in the constructor for this class, such as id, titlereleaseDate. If you want a column to have a different name from the field name in the class, you can use the @ColumnInfo annotation before a field.

To set the primary key for a table, use the @PrimaryKey annotation. In the case of the movie table, the primary key is id:

@PrimaryKey  
@SerializedName("id")  
@Expose  
var id: Int? = null

笔记: The @SerializedName@Expose annotations are from the g library, not from Room. The app uses Gson to convert JSON data from API web calls to Kotlin data objects. Thus, this single Movie class can fluidly convert between JSON to Kotlin object to Room database entity all through the use of annotations.

接下来是该表上的操作,例如检索,插入和删除。该应用程序通过以下方式访问这些操作 数据访问对象 (DAO). Generally, each table has its own DAO interface, specified using the @Dao annotation.

打开 moviedai.kt.,DAO为电影表,查看以下CRUD(创建,读取,更新,删除)操作:

@Dao  
interface MovieDao {  
  @get:Query("SELECT * FROM movie_table")  
  val all: Observable<List<Movie>>  

  @Insert(onConflict = REPLACE)  
  fun insert(movie: Movie)  

  @Query("DELETE FROM movie_table WHERE id = :id")  
  fun delete(id: Int?)  

  @Query("DELETE FROM movie_table")  
  fun deleteAll()  

  @Update  
  fun update(movie: Movie)  
}

Each type of operation for a function is labeled with its own annotation: @Insert, @Query@Update, with the corresponding SQLite query included to modify the data in the database.

接下来,您需要声明房间数据库对象本身。打开 localDatabase.kt. 并检查这是如何完成的:

@Database(entities = [Movie::class], version = 1)  
@TypeConverters(IntegerListTypeConverter::class)  
abstract class LocalDatabase : RoomDatabase() {...}

LocalDatabase is abstract and inherits from 房间Database. It’s marked with a Room @Database annotation that lists the Entities that are in this database (corresponding to the 桌子 在此数据库中)和版本号。

Wewatch数据库中唯一的实体是电影实体,所以这就是列出的那个。如果数据库的模式更改,则数据库的版本号是您需要递增数据库迁移的数字 - 但现在不要担心。

localDatabase.kt. 类然后实例化房间数据库,如下所示:

LocalDatabase.INSTANCE =  
  Room.databaseBuilder(application, LocalDatabase::class.java, LocalDatabase.DB_NAME)  
  .allowMainThreadQueries()  
  .build()

Singleton模式用于仅在应用程序中创建房间数据库。

数据库的实例化发生在 localDataSource.kt.。打开此文件,您将看到这是数据库的单个实例所在的位置:

val db = LocalDatabase.getInstance(application)

LocalDataSource is the source of data for the app, providing the list of movies from the database to the rest of the app. LocalDataSource also acts as the point of contact for the rest of the app to expose the DAO’s other database calls. Any time a database call from the DAO is needed somewhere in the app, the calling Activity obtains an instance of LocalDataSource 和 calls insert(), delete()update().

LiveData.

In some chapters of this book, you’ll use the RxJava library to perform asynchronous web calls and database operations on the Schedulers.io() thread and to receive responses from them on the MainThread. In the MVVM 章节,撰写了rxjava的替代方案: LiveData..

LiveData. is a lifecycle-aware component that wraps around objects you wish to emit in a reactive way, much the same way the Observable object does in RxJava. LiveData is “live” in the sense that when the underlying data updates, anything observing that data will also receive the updates. For example, when paired with Room, LiveData retrieved from the Room database automatically updates when the data in the database changes.

在MVVM中使用Android架构组件章节项目, moviedai.kt. class从数据库中返回一个电影列表作为livevata,如下所示:

@Query("select * from movie")
fun getAll(): LiveData<List<Movie>>

要了解有关Liveata的更多信息,请阅读第11章: MVVM与Android架构组件.

viewmodel.

One problem with Activities and the Android lifecycle is that if the Activity gets destroyed, data held by that Activity also gets destroyed. So, how can you return the Activity to the state it was in once it is rebuilt? It’s possible to save some state through the Activity’s onSaveInstanceState(outState: Bundle?), but this solution is cumbersome and doesn’t work for more complicated data.

Android架构组件现在为数据提供更强大的方式,以便通过该数据生存 viewmodel.。 ViewModel是一个生命周期感知的类,用于抓住LiveData,以便在配置更改之类的配置变化时不会被破坏。 ViewModel在整个活动的生命周期中保持其状态,但必须避免对观点或活动的参考是必不可少的 a ViewModel because these throw a nullPoinerException when destroyed.

看到ViewModel如何工作,打开一个例子 mainviewModel.kt. 从Android架构组件章节的MVVM项目。

class MainViewModel(private val repository: MovieRepository = MovieRepositoryImpl()): ViewModel() {}

Here, MainViewModel extends viewmodel. 和 takes in a MovieRepository in its constructor.

接下来,查看ViewModel如何持有电影列表作为LiveData:

private val allMovies = MediatorLiveData<List<Movie>>()

init {
  getAllMovies()
}

fun getSavedMovies() = allMovies

fun getAllMovies() {
  allMovies.addSource(repository.getSavedMovies()) { movies ->
    allMovies.postValue(movies)
  }
}

allMovies list, in this case, is of type MediatorLiveData, which is a subclass of regular LiveData. that allows you to mutate the LiveData and react to updates on the LiveData’s value via an onChanged() event.

这 app can then access allMovies in any Activity, such as in mainactivity.kt.,如此:

override fun onCreate(savedInstanceState: Bundle?) {  
  ...
  viewModel = ViewModelProviders.of(this).get(MainViewModel::class.java)  

  viewModel.getSavedMovies().observe(this, Observer { movies ->  
    movies?.let {  
      adapter.setMovies(movies)  
    }  
  })   
}

Here, the ViewModel is instantiated by using a viewmodel.Provider to provide the ViewModel. The Activity can then access the list of movies by calling viewModel.getSavedMovies() 和 observing the LiveData returned from that call. In this example, the list of movies is set on the Adapter when observed.

务必阅读第11章: MVVM与Android架构组件 要完整地查看代码。

数据绑定

这 Data Binding library allows you to bind UI components in your Layouts to data sources. Normally, this is done in code — such as setting the text of a TextView using movieTitleTextView.setText = movie.title — but with the Data Binding library, you’ll be able to do it directly in the XML Layout files.

例如,从MVVM章节中打开项目,数据绑定并查看此片段 item_movie_main.xml.:

<TextView
  android:id="@+id/movieTitleTextView"
  android:text="@={movie.title}"
  ... />

您可以在第10章中阅读有关数据绑定的更多信息: MVVM具有数据绑定章节.

关键点

  • Android架构组件是一组库,可以帮助处理Android架构的各种挑战。
  • 房间处理数据库持久性。
  • 生命周期可帮助您创建意识到当前Android生命周期状态的组件。
  • viewmodel.保存数据并求生存配置更改。
  • LiveData.提供可观察数据以查看。
  • 数据绑定允许Android视图观察XML中数据的更改。
  • 寻呼处理显示无限列表。
  • 导航处理复杂的导航。
  • WorkManager.管理背景任务。

然后去哪儿?

很好地了解Android架构组件,因为您导航使用它们的各种章节是有用的。接下来,您将了解整本书中存在的另一个有用的概念:依赖注入。

有一个技术问题?想报告一个错误吗? 您可以向官方书籍论坛中的书籍作者提出问题和报告错误 这里.

有反馈分享在线阅读体验吗? 如果您有关于UI,UX,突出显示或我们在线阅读器的其他功能的反馈,您可以将其发送到设计团队,其中表格如下所示:

© 2021 Razeware LLC