GVKun编程网logo

Android Architecture Components 系列(六)Paging Library(android appcompat library)

1

在本文中,我们将详细介绍AndroidArchitectureComponents系列的各个方面,并为您提供关于六PagingLibrary的相关解答,同时,我们也将为您带来关于./src/compo

在本文中,我们将详细介绍Android Architecture Components 系列的各个方面,并为您提供关于六Paging Library的相关解答,同时,我们也将为您带来关于./src/components/CustomNavbar.jsx找不到模块:无法解析“ / Users / Documents / GitHub / myweb_app / src / components”中的“ react-router-dom”、./src/Components/Pages/About.js 未找到模块:无法解析“C:\Users\user\Desktop\yat2\yoaz\src\Components\Pages”中的“../logo.svg”、Android Architecture Components Part1:Room、Android Architecture Components Part2:LiveData的有用知识。

本文目录一览:

Android Architecture Components 系列(六)Paging Library(android appcompat library)

Android Architecture Components 系列(六)Paging Library(android appcompat library)

Paging Library 分页加载库 
    用于逐步从数据源加载信息,而不会耗费过多的设备资源或是等待太长的时间。
 
现有的分页加载功能的优点 mix 缺陷:
CursorAdapter ,使得从数据库加载数据到ListVIew变得非常容易。
                            但是这是在主线程中查询数据库,并且分也的内容实用低效的Cursor返回。 更多使用CursorAdapter带来的问题参考Large Database Queries on Android。
AsyncListUtils  ,提供基于位置的 分页加载到RecycleView中。
                            但是无法使用不基于位置 的分页加载,而且强制把null 作为占位符
 
 DataSource 数据源
    根据想要访问数据的方式,可以有两种子类可供选择:
        KeyedDataSource用于加载从第N到N+1 条数据
        TiledDataSource用于从任意位置的分页数据
 
    例如使用  Room persistence library就可以自动创建返回  TiledDataSource类型的数据:
 
   @Query("select * from users WHERE age > :age order by name DESC, id ASC")
TiledDataSource<User> usersOlderThan(int age);
 
PagedList 定量数据
   从上面DataSource 获取指定数量的数据,并且可以制定预取多少数据。这样可以最大程度减少加载数据的时间。
    ps:这个类提供更新信息给其他类  比如RecyclerView.Adapter来更新 RecyclerView的UI。
 
PagedListAdapter 适配器
    这个类是 RecyclerView.Adapter得到一个实现类,用于当数据加载完毕时,通知Recycle数据1已经到达可以进行加载显示。Recycleview就可以把数据填充进行显示操作。
 
PagedListProvider
    从数据源中产生 LiveData<PagedList>。此外如果使用的是 Room persistence library,DAO还能使用 TiledDataSource生成 LivePagedListProvider。示例代码:
 
        @Query("SELECT * from users order WHERE age > :age order by name DESC, id ASC”)
     public abstract LivePagedListProvider<Integer, User> usersOlderThan(int age);
 
Paging Library从后台线程获取数据流,再在Ui线程中展示就是通过以上几个重要类。
 
流程图:
 
当新的item插入到数据库,DataSource被更新,LivePagedListProvider在后台线程产生了新的PagedList
 
 
    继而,中间新生成的PagedList 在主线程中被发送到PagedListAdapter中,让它使用后台线程DiffUtil计算新的List和原来的List的差距,
当差异比较完后,PagedListAdapter用 RecyclerView.Adapter.notifyItemInserted()来通知数据刷新。
    
    实例代码:
 
/**
* Dao数据库操作
*/
@Dao 
interface UserDao{ 
    @Query("SELECT * FROM user ORDER BY lastName ASC”) 
    public abstractLivePagedListProvider<Integer, User>usersByLastName(); 
/**
* ViewModel 数据源
*/
class MyViewModel extends ViewModel{ 
    public final LiveData<PagedList<User>> usersList ;//数据list 
    public MyViewModel(UserDao userDao) { 
        usersList =userDao.usersByLastName().create( 
           /* initial load position */ 0,
             new PagedList.Config.Builder()
                     .setPageSize(50) 
                    .setPrefetchDistance(50) .build()); 
        }
 }
/**
*  View层的实现
*  初始化ViewModel、RecycleView并绑定PagedListAdapter
* 通过observe方法将ViewMode数据加载到数据List中
*/
 class MyActivity extends AppCompatActivity { 
       @Override 
        public void onCreate(Bundle savedState) { 
            super.onCreate(savedState); 
        MyViewModel viewModel = ViewModelProviders.of(this).get(MyViewModel.class); 
        RecyclerViewrecyclerView = findViewById(R.id.user_list); 
       UserAdapter<User> adapter= new UserAdapter();
         viewModel.usersList.observe(this,
                     pagedList -> adapter.setList(pagedList));
         recyclerView.setAdapter(adapter);
         } 
    } 
/**
*  PagedListAdapter 适配器配置
*  覆写onBindViewHolder()方法
*  @param UserViewHolder
*  @param position
    
*/
class UserAdapter extends PagedListAdapter<User, UserViewHolder> { 
        public UserAdapter() { 
            super(DIFF_CALLBACK);
        }
     
    @Override
    public void onBindViewHolder(UserViewHolder holder, int position) { 
        User user = getItem(position); //通过position 获取当条数据
        if (user != null) { 
            holder.bindTo(user); 
        } else { 
            // Null defines a placeholder item - PagedListAdapter will automatically invalidate
             // this row when the actual object is loaded from the database 
            holder.clear(); 
        } 
    } 
 
/**
* 后台线程DiffUtil类回调: 计算新的List和原来的List的差距
*/
    public static final  DiffCallback<User> DIFF_CALLBACK = new DiffCallback<User>() { 
            @Override 
            public boolean areItemsTheSame(@NonNull User oldUser, @NonNull User newUser) { 
               // User properties may have changed if reloaded from the DB, but ID is fixed 
                return oldUser.getId() == newUser.getId(); 
            } 
            @Override 
            public boolean areContentsTheSame(@NonNull User oldUser, @NonNull User newUser) { 
                // NOTE: if you use equals, your object must properly override Object#equals() 
                // Incorrectly returning false here will result in too many animations. 
                return oldUser.equals(newUser); 
            } 
    } 
}
 
 
PS.鉴于大家的都建议给一个整体框架的demo,这里可以提供一个更好的方案: Google Android Architecture Components,这是Google官方提供的样例可以用来参考。
 
系列文章列表:
   Android Architecture Components 系列(一)初识
   Android Architecture Components 系列(二) LifeCycle
        Android Architecture Components 系列(三) LiveData
   Android Architecture Components 系列(四)ViewModel
   Android Architecture Components 系列(五)Room
   Android Architecture Components 系列(七)WorkManager
        Android Architecture Components 系列(八)小结
 
 

./src/components/CustomNavbar.jsx找不到模块:无法解析“ / Users / Documents / GitHub / myweb_app / src / components”中的“ react-router-dom”

./src/components/CustomNavbar.jsx找不到模块:无法解析“ / Users / Documents / GitHub / myweb_app / src / components”中的“ react-router-dom”

如何解决./src/components/CustomNavbar.jsx找不到模块:无法解析“ / Users / Documents / GitHub / myweb_app / src / components”中的“ react-router-dom”

继续收到此错误,不确定我在做什么错

编译失败 ./src/components/CustomNavbar.jsx 找不到模块:无法解析“ / Users / mikemutabazi / Documents / GitHub / myweb_app / src / components”中的“ react-router-dom”

代码

id    date      product  early_product
1   2010-02-01     c         c
1   2010-02-02     v         c
1   2010-02-03     d         c
1   2010-02-04     g         c
2   2010-02-03     h         h
2   2010-02-04     w         h
2   2010-02-05     t         h
2   2010-02-06     d         h
3   2010-02-04     x         x
3   2010-02-05     f         x
3   2010-02-06     x         x

./src/Components/Pages/About.js 未找到模块:无法解析“C:\Users\user\Desktop\yat2\yoaz\src\Components\Pages”中的“../logo.svg”

./src/Components/Pages/About.js 未找到模块:无法解析“C:\Users\user\Desktop\yat2\yoaz\src\Components\Pages”中的“../logo.svg”

如何解决./src/Components/Pages/About.js 未找到模块:无法解析“C:\\Users\\user\\Desktop\\yat2\\yoaz\\src\\Components\\Pages”中的“../logo.svg”

请帮忙,我正在尝试将 logo.svg 导入 about.js 页面。 About.js 被放置在组件下的 Pages 文件夹中,但我似乎不知道显示它的最佳方式,我尝试以所有可能的方式引用它我知道我enter image description here 不断收到错误{{ 3}}

Android Architecture Components Part1:Room

Android Architecture Components Part1:Room

前言

Android Architecture Components(AAC)首次发布与 2017 GoogleI/O 大会,经过近一年的维护,现在 Google 团队已经发布了稳定版(v1.1.1)。能够更好的帮助我们来构建自己的 App 应用,如果你还没有了解 ACC 现在时间刚刚好,来不及解释,赶紧上车吧。

ACC 是一个架构组件,它能帮忙我们更好的来管理我们的 App,方便我们的开发。它能帮助我们的 App 更好的存储数据、管理生命周期、进行模块化、避免常见的错误、减少样板文件的编写。

ACC 主要由 4 个单一组件组成,分别为:Room、LiveData、Lifecycle 与 ViewModel。它们每一个都是独立存在的组件,我们可以单独使用其中几个,又或者可以将它们全部整合到一起。所以对于 ACC 它提供了更好的使用灵活性,方便我们集成到我们的 App 中。

今天主要是对 ACC 其中的 Room 组件进行分析。Room 是一个稳健的 SQL 对象映射库,用来帮助我们快速的实现数据本地存储。至于为何要使用本地数据库,自然是当用户无网络或者网络差的时候,能够更好的提高用户对我们 App 的体验。

添加依赖

在使用 Room 之前,我们还是要在项目中对其进行依赖添加。 首先在你的项目的根目录下的 build.gradle 中添加 google () 库,代码如下:

allprojects {
    repositories {
        jcenter()
        google()
    }
}

之后打开你的 App 或者 module 中的 build.gradle 文件,在 dependencies 中添加如下代码:

dependencies {
    def room_version = "1.1.0" // or, for latest rc, use "1.1.1-rc1"
 
    implementation "android.arch.persistence.room:runtime:$room_version"
    annotationProcessor "android.arch.persistence.room:compiler:$room_version"
 
    // optional - RxJava support for Room
    implementation "android.arch.persistence.room:rxjava2:$room_version"
 
    // optional - Guava support for Room, including Optional and ListenableFuture
    implementation "android.arch.persistence.room:guava:$room_version"
 
    // Test helpers
    testImplementation "android.arch.persistence.room:testing:$room_version"
}

Room

上面的依赖添加完成后,接下来我们可以正式使用 Room。在 Android App 中进行本地数据的存储都是使用 SQLite,当我们使用原生的 SQLite 进行本地数据库的编写时,我们不仅要定义数据库结构,还要创建 SQLiteHelper,编写一连串的 SQL 语句。这样代码量与复杂度不断上升,这不是我们想要的。而 Room 正好可以帮助我们减少代码、简化复杂度。

对于 Room 的使用主要由三部分构成:

  1. Entity:标识数据库中的表结构
  2. DAO: 标识提供获取数据库表中的数据方法
  3. Database:标识所需要创建的数据库

以上三部分在代码中都是通过注释来实现,从而达到代码的精简。

Entity

Entity 作用在 model 上,即我们与数据表中的字段所匹配的 model 类。现在我们来建立一个联系人相关的 model,对于正常的 model 建立如下:

data class ContactsModel(val id: Int, val name: String, val phone: String)

现在我们要把 ContactsModel 映射到数据库中的一种表,只需进行如下操作:

@Entity(tableName = "contacts")
data class ContactsModel(
        @PrimaryKey
        @ColumnInfo(name = "contacts_id")
        val id: Int,
        @ColumnInfo(name = "name")
        val name: String,
        @ColumnInfo(name = "phone")
        val phone: String
)

首先我们在 ContactsModel 中添加 @Entity 注释,表明它将映射成一种表。在 Entity 中可以通过使用 tableName 来为该表命名,这里将其命名未 contacts。

除此之外,使用 @ColumnInfo 来标明表中的字段,@PrimaryKey 来标明表的主键。其中 @ColumnInfo 也可以通过 (name = "name") 来命名字段名。当然还有别的注释例如外键的标明:@ForeignKey

DAO

数据库表建好了,现在是提供操作数据表中的数据的方法。

@Dao
interface ContactsDao {
 
    @Query("SELECT * FROM contacts")
    fun getAllContacts(): List<ContactsModel>
 
    @Query("SELECT * FROM contacts WHERE contacts_id = :id")
    fun getContactsById(id: Int): LiveData<ContactsModel>
 
    @Insert(onConflict = OnConflictStrategy.REPLACE)
    fun insertContacts(contactsModel: ContactsModel)
 
    @Query("UPDATE contacts SET name = :name AND phone = :phone WHERE contacts_id = :id")
    fun updateContacts(id: Int, name: String, phone: String)
 
    @Query("DELETE FROM contacts WHERE contacts_id = :id")
    fun deleteContacts(id: Int)

这里我们只需创建一个接口,通过 @Dao 来标明它是提供操作数据表的方法集。要注意它必须为 interface,在接口中我们只需定义接口方法即可。与平常的接口方法定义不同的是,我们必须在每一个接口方法上通过注释来标明该方法的作用。

例如 getAllContacts () 方法,我们为了让它实现获取 contacts 表中的所有数据,我们需要在其方法中添加 @Query 注释,由于是查询方法,自然是使用 Query,如果是插入方法就是 Insert (第三个方法)。其次 () 中的内容就是正常的查询语句。这里是获取所有的 Contacts,所以我们使用

@Query("SELECT * FROM contacts")

对于有参数的 sql 语句编写,可以查看第二个方法,参数值只需在对应的方法参数名前加入:前缀,这就是传参的格式。

@Query("SELECT * FROM contacts WHERE contacts_id = :id")
fun getContactsById(id: Int): LiveData<ContactsModel>

Room 就是这么简单,通过定义接口与接口方法的形式,再结合注释来简化代码量与复杂度。当然最终 Room 会根据注释,编译器会帮我们实现这些接口方法。我们可以 build 项目,然后我们就可以搜索到 ContactsDao_Impl 类,这个读者可以自行尝试。本质是 ContactsDao_Impl 实现了 ContactsDao 接口。

Room 的强大之一是:它可以在编译时检测你的 SQL 语句是否编写正确,如果编写错误将导致编译失败。这样就可以避免 App 在运行时导致崩溃。这个读者可以自行测试一下。

Database

现在数据表有了,对表的操作方法也有了,最后就差数据库来保存各个数据表了。Talk is cheap. Show me the code。

@Database(entities = arrayOf(ContactsModel::class), version = 1)
abstract class ContactsDataBase : RoomDatabase() {
 
    abstract fun contactsDao(): ContactsDao
 
    companion object {
        private var instance: ContactsDataBase? = null
        fun getInstance(context: Context): ContactsDataBase {
            if (instance == null) {
                instance = Room.databaseBuilder(context.applicationContext,
                        ContactsDataBase::class.java,
                        "contacts.db").build()
            }
            return instance as ContactsDataBase
        }
    }
}

没错,还是使用注释,这里我们定义 ContactsDataBase 抽象类,让它继承 RoomDatabase 抽象类。当然也是同 @Database 来标明它是一个数据库。它接收两个参数,分别为 entities 与 version,前者接收的类型是 Class [] 数组,内容为对于表的 Class;后者是 int 的数据库版本号。

在 ContactsDataBase 中还需定义一个抽象方法,让它返回由 @Dao 注释的 ContactsDao,即提供获取数据表的方法。本质的为数据库暴露操作数据表的入口。至于它的具体方法实现也可以通过 build 来查看对应的自动生成文件 ContactsDataBase_Impl 类。

因为 contactsDao 是数据库的唯一入口,避免每次对数据库进行操作时都创建 ContactsDataBase 实例,如上代码我们可以使用单例模式来减少实例频繁创建的开销。

使用

经过上面的 Entity、DAO 与 Database 的创建,现在我们已经有了完整的本地数据库结构。接下来我们来看史上最简数据库使用的调用代码:

private val mContactsDao by lazy { ContactsDataBase.getInstance(application).contactsDao() }
 
fun getContactsById(id: Int): LiveData<ContactsModel> = mContactsDao.getContactsById(id)

你没看错只需两行代码,我们就能获取数据库中 Contacts 表中的所用数据。

第一行代码我们获取了 ContactsDao 实例,该实例包含操作数据表的所以方法。而第二行代码就是调用 ContactsDao 中的操作方法。返回我们所需的数据。

在第二行代码,细心的你们可能会发现它返回了 LiveData<ContactsModel> 类型数据。它是 ACC 的另一强大组件,这也是 Room 的另一强大之处,它可以直接返回 LiveData 数据类型,完美与 LiveData 结合。至于 LiveData 的作用,敬请关注下一篇文章 Android Architecture Components Part2:LiveData。

总结

如果你的 App 使用了 Room,那么你的 App 本地数据获取架构将会是这样的

最后文章中的代码都可以在 Github 中获取到。使用时请将分支切换到 feat_architecture_components

相关文章

Android Architecture Components Part2:LiveData

Android Architecture Components Part3:Lifecycle

Android Architecture Components Part4:ViewModel

关注

怪谈时间到了

Android Architecture Components Part2:LiveData

Android Architecture Components Part2:LiveData

clipboard.png

感谢你的再次光临,欢迎来到Android Architecture Components(ACC)系列文章。上篇文章我们一起讨论了Room,通过Room我们能够方便的操作App的数据库。如果你的App对本地数据库有所依赖的话,Room你值得拥有。

今天这篇文章继续上篇文章的步伐,让我们一起来全面了解ACC另一强大的组件LiveData。相信你马上会喜欢上她!

简述

LiveData是一种可观测数据容器,它会在数据变化时通知观测器,以便更新页面;同时它具备生命感知能力,可以实时观察Activity/Fragment的生命周期状态。

既然它是可观察数据容器与具备生命感知能力,那么它的优点也很明显,可以归纳与以下几点

  1. 确保ui跟随数据更新
  2. 具备生命感知能力从而减少内存泄露
  3. 防止异常crashs
  4. 无需管理绑定者的生命周期
  5. ui获取的数据都是最近最终的更新数据

使用场景

当我们要监听某一个数据的变化时,LiveData将大显身手。例如界面数据的更新,当数据发生变化时,我们要通知界面进行更新ui,这时我们可以使用LiveData在当前Activity/Fragment中对该数据注册一个观察者,实时监听数据的任何改动。每一次改动LiveData都会发送通知给观察者。

另一方面,LiveData感知界面的生命周期,所以只有在界面生命周期的STARTED或者RESUMED状态才会通知观察者。如果你一直处于后台且数据一直在变化,LiveData是不会发生通知,只有在界面再一次回到前台,这时LiveData才会发生通知且只会发送一次,数据的更新取的是最后一次的变化数据。这样可以有效的避免内存泄露与ui不存在时导致的NullPointerException

使用

首页我们需要在我们的app下的build.gradle中添加如下依赖代码

dependencies {
    def lifecycle_version = "1.1.1"
 
    // ViewModel and LiveData
    implementation "android.arch.lifecycle:extensions:$lifecycle_version"
    // alternatively - just LiveData
    implementation "android.arch.lifecycle:livedata:$lifecycle_version"
 
    annotationProcessor "android.arch.lifecycle:compiler:$lifecycle_version"
}

然后我们就能正式使用LiveData,看如下代码:

class ContactsViewModel(application: Application, private val defTitle: String = "Contacts") : AndroidViewModel(application) {
    val message: MutableLiveData<String> by lazy { MutableLiveData<String>() }
    val contactsList: MutableLiveData<List<ContactsModel>> = MutableLiveData()
     
   fun getContacts(refresh: Boolean): LiveData<List<ContactsModel>> {
        message.value = ""
        if (refresh) {
            getDataFromRemote()
        } else if (contactsList.value == null || contactsList.value?.size ?: 0 <= 0) {
            message.value = "数据请求中,请稍后!"
            if (mLocalData.isEmpty()) {
                getDataFromLocal()
            }
        }
        return contactsList
    }
     
    private fun getDataFromLocal() {
        val runnable = Runnable {
            val dao = mContactsDao.getAllContacts()
            if (dao.isNotEmpty()) {
                contactsList.postValue(dao)
            } else {
                getDataFromRemote()
            }
        }
        mExecutors.disIoExecutor.execute(runnable)
    }
 
    private fun getDataFromRemote() {
        Handler().postDelayed({
            contactsList.value = mRemoteData
            mLocalData = mRemoteData
            saveContacts(mRemoteData)
            Thread(Runnable {
                title.postValue("Remote Contacts")
            }).start()
            message.value = "数据加载完成~"
        }, MDELAY_MILLIS)
    }
}    

首先我们使用MutableLiveDat对我们所需要的数据进行了包裹,MutableLiveData它继承与LiveData,暴露了postValue()setValue()方法。一旦MutableLiveData所包裹的数据发生变化,我们可以通过postValue()(asynchronously)与setValue()(synchronously)来设置值与发送通知,告诉观察者数据已经改变。

getDataFromLocal()方法中,我们使用了Room来操作数据库,同时直接通过返回LiveData数据类型的数据,使得Room与LiveData完美结合。

所以我们再来看看观察者的代码:

class ContactsActivity : AppCompatActivity() {
 
    private lateinit var mViewModel: ContactsViewModel
 
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_contacts_layout)
        setupViewModel()
    }
    
    private fun setupViewModel() {
        mViewModel = ViewModelProviders.of(this, ContactsFactory.getInstance(application))[ContactsViewModel::class.java]
        //active STARTED、RESUMED
        mViewModel.getContacts(true).observe(this,
                Observer {
                    //todo ...
                })
        mViewModel.message.observe(this,
                Observer {
                    //todo ...
                })
    }   
}

我们为所需要观察的数据添加了observer方法,该方法第一个参数是LifecyleOwner,以便让LiveData具有生命感知能力,这里要感知的是ContactsActivity,所以传入this即可。第二个参数是一个回调方法,一旦数据发生变化它的onChanged()就会回调,并将数据带回,这样界面就能实时更新数据。

最后由于LiveData是生命感知的所以我们也无需担心他的register/unregister

Extend

我们已经知道LiveData会对处于STATERD或者RESUMED状态进行发送通知,如果该状态下存在observer,由无到有,我们称之为active,反正称之为inactive。如果我们能够知道何时为active与何时为inactive,那么我们就可以实现自己的LiveData。为了解决这个问题,LiveData提供了两个方法,分别为onActive()onInactive()

例如我们想为一个监听器实现生命感知能力,可以进行如下操作

public class StockLiveData extends LiveData<BigDecimal> {
    private static StockLiveData sInstance;
    private StockManager mStockManager;
 
    private SimplePriceListener mListener = new SimplePriceListener() {
        @Override
        public void onPriceChanged(BigDecimal price) {
            setValue(price);
        }
    };
 
    @MainThread
    public static StockLiveData get(String symbol) {
        if (sInstance == null) {
            sInstance = new StockLiveData(symbol);
        }
        return sInstance;
    }
 
    private StockLiveData(String symbol) {
        mStockManager = new StockManager(symbol);
    }
 
    @Override
    protected void onActive() {
        mStockManager.requestPriceUpdates(mListener);
    }
 
    @Override
    protected void onInactive() {
        mStockManager.removeUpdates(mListener);
    }
}

一旦observer由无到有,那么我们就在onActive()方法中进行监听器的注册。observer由有到无,我们可以在onInactive()中进行注销。这样就可以是我们的监听器具备生命感知能力。避免不必要的内存泄露或者一次crash。同时一旦监听器的回调方法生效时,我们又可以通过LiveData的setValue()来对观察者进行数据的更新。所以观察者的代码如下:

public class MyFragment extends Fragment {
    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        StockLiveData.get(getActivity()).observe(this, price -> {
            // Update the UI.
        });
    }
}

如果细心的话,可以发现上面的StockLiveData已经实现了监听器共享。我们可以在多个界面中使用StockLiveData进行添加observer。例如在Activity中,只要有一个observer,那么它将一直监听数据的变化。

案例:对于App统计需求,一旦涉及到多个页面间的统计参数传递,可以自定义一个扩展LiveData来全局监听参数的传递与变化。

Transform

在通知观察者数据改变之前,如果你想改变LiveData中的值类型,可以使用Transformations

Transformations.map()

获取原有类型中的某个特定的类型值,可以比喻为解包,可以使用map()方法

LiveData<User> userLiveData = ...;
LiveData<String> userName = Transformations.map(userLiveData, user -> {
    user.name + " " + user.lastName
});

Transformations.switchMap()

与map对应的是switchMap()方法,这里就是打包。

private LiveData<User> getUser(String id) {
  ...;
}
 
LiveData<String> userId = ...;
LiveData<User> user = Transformations.switchMap(userId, id -> getUser(id) );

MediatorLiveData

与LiveData相关的还有一个MediatorLiveData,它的作用是:可以同时监听多个LiveData。例如同时监听本地数据与远程数据。

LiveData<List<User>> usersFromDatabase;
LiveData<List<User>> usersFromNetwork;
 
MediatorLiveData<List<User>> usersLiveData = 
    new MediatorLiveData<>();
     
usersLiveData.addSource(usersFromDatabase, newUserList ->
    usersLiveData.setValue(value));
     
usersLiveData.addSource(usersFromNetwork, newUserList ->
    usersLiveData.setValue(value));

一旦其中一个发送变化,MediatorLiveData都会发送通知给observer。

是否感觉LiveData很强大呢?那么赶紧行动起来吧,让你的App中数据也具有可观察与生命感知能力。

最后文章中的代码都可以在Github中获取到。使用时请将分支切换到feat_architecture_components

相关文章

Android Architecture Components Part1:Room
Android Architecture Components Part3:Lifecycle
Android Architecture Components Part4:ViewModel

关注

私人博客

clipboard.png

我们今天的关于Android Architecture Components 系列六Paging Library的分享已经告一段落,感谢您的关注,如果您想了解更多关于./src/components/CustomNavbar.jsx找不到模块:无法解析“ / Users / Documents / GitHub / myweb_app / src / components”中的“ react-router-dom”、./src/Components/Pages/About.js 未找到模块:无法解析“C:\Users\user\Desktop\yat2\yoaz\src\Components\Pages”中的“../logo.svg”、Android Architecture Components Part1:Room、Android Architecture Components Part2:LiveData的相关信息,请在本站查询。

本文标签: