android各组件翻译,【翻译】安卓架构组件(7)-分页库

相关文章:

分页库使你的app能够在需要从一个数据源逐步加载数据时更为轻松,避免了过度加载以及为了一个大型数据的查询等待太多时间。

综述

许多app伴随着大量的数据,但是在任意时刻往往只需要加载和显示其中的一小部分。一个app可能存在数以万计的数据以供显示,但在某一时刻仅仅需要访问其中的几十条。如果app没有认真处理这个这个问题,会请求实际上并不需要的数据,并导致不必要的性能负担和网络带宽。如果数据并没有被存储起来或同步到远程数据库,这同样会减慢app的运行速度以及浪费用户的流量。

当然现有的安卓API允许对内容进行分页,它们伴有明显的约束和缺点:

CursorAdapter使得将数据库查询结果映射到ListView列表项更为轻松,但它会在UI线程执行数据库查询,并且使用Cursor的分页并不高效。对于使用CursorAdapter的更多缺陷,请查询这里。

AsyncListUtil允许将基于位置的分页数据加载至RecyclerView,但是并不允许无位置的分页,而且它会强迫使用空白占用位。

新的分页库致力于解决这些问题。这个类库包含一些类,以流水线的方式处理你所需数据的请求过程。这些类也可以和已经存在的架构类组件无缝结合,如Room。

分页库提供以下的类以及额外的支持类:

DataSource

使用这个类定义一个你用来分页拉取的数据源。根据如何访问你的数据,你可以集成以下两个子类之一:

KeyedDataSource 如果你需要从第N个数据项获取第N+1个数据项。例如,如果你的线程在一个讨论的app获取评论,你可能需要传递一个评论的id来获取下一个评论。

TiledDataSource 如果你需要从你的数据源中获取任意指定位置的分页数据。这个类支持从你选择的任何位置请求数据,例如:“返回从位置1200开始的20条数据”。

如果你使用Room来管理你的数据,它会自动创建一个TiledDataSource,例如:

@Query("select * from users WHERE age > :age order by name DESC, id ASC")

TiledDataSource usersOlderThan(int age);

PagedList

这个类从DataSource加载数据。你可以配置在任何时刻该获取多少数据,以及需要预加载多少数据,以最小化用户等待数据被加载时等待的时间。这个类可以给其他类提供更新信号,例如RecyclerView.Adapter,允许当数据分页加载时更新你的RecyclerView。

PagedListAdapter

这个类是RecyclerView.Adapter的子类,使得数据从PagedList中展现。例如,当新的一页数据被加载时,PagedListAdapter通知RecyclerView数据已经到达,这让RecyclerView替换任何占位项,并展示合适的动画效果。

PagedListAdapter使用后台线程计算从一个PagedList到另一个的变化(例如,当数据库的变更导致数据的更新),并调用notifyItem...()方法,并在需要时更新列表数据内容。之后RecyclerView展现必要的变化。例如,当一个数据项在不同的PagedList版本间变更位置时,RecyclerView动画会展示数据项移动到新的位置。

LivePagedListProvider

这个生成从你提供的DataSource生成一个LiveData。此外,如果你使用Room持久化类库来管理你的数据库,DAO可以使用TiledDataSource生成LivePagedListProvider,例如:

@Query("SELECT * from users order WHERE age > :age order by name DESC, id ASC")

public abstract LivePagedListProvider usersOlderThan(int age);

Integer参数告知Room基于位置加载的TiledDataSource。

分页库组件在后台线程组织了数据流,并在UI线程展示。例如:当一个新的数据项被插入到你的数据库时,DataSource会失效, 后台线程产生一个新的PagedList。

05bc7ab5d768

图1 分页库组件在后台线程执行大部分工作,因此并不会影响UI线程

新创建的PagedList在UI线程被发送到PagedListAdapter。之后PagedListAdapter使用DiffUtil在后台线程计算当前列表和新列表的不同。当比较结束时,PagedListAdapter使用比较得到的差异信息适当地调用RecyclerView.Adapter.notifyItemInserted()来通知新的数据项被插入。

RecyclerView在UI线程知道仅仅需要绑定一个新的数据项,并使用动画展示在屏幕上。

下面的代码示例显示了所有相关部分的工作。当数据库添加、删除或者更新时,RecyclerView的内容自动且高效地更新:

@Dao

interface UserDao {

@Query("SELECT * FROM user ORDER BY lastName ASC")

public abstract LivePagedListProvider usersByLastName();

}

class MyViewModel extends ViewModel {

public final LiveData> usersList;

public MyViewModel(UserDao userDao) {

usersList = userDao.usersByLastName().create(

/* 初始化加载位置 */ 0,

new PagedList.Config.Builder()

.setPageSize(50)

.setPrefetchDistance(50)

.build());

}

}

class MyActivity extends AppCompatActivity {

@Override

public void onCreate(Bundle savedState) {

super.onCreate(savedState);

MyViewModel viewModel = ViewModelProviders.of(this).get(MyViewModel.class);

RecyclerView recyclerView = findViewById(R.id.user_list);

UserAdapter adapter = new UserAdapter();

viewModel.usersList.observe(this, pagedList -> adapter.setList(pagedList));

recyclerView.setAdapter(adapter);

}

}

class UserAdapter extends PagedListAdapter {

public UserAdapter() {

super(DIFF_CALLBACK);

}

@Override

public void onBindViewHolder(UserViewHolder holder, int position) {

User user = getItem(position);

if (user != null) {

holder.bindTo(user);

} else {

// NULL时定义了一个占位项——当实际的对象被从数据库加载时,PagedListAdapter会自动失效该行

holder.clear();

}

}

public static final DiffCallback DIFF_CALLBACK = new DiffCallback() {

@Override

public boolean areItemsTheSame(@NonNull User oldUser, @NonNull User newUser) {

// 用户属性可能会在重新加载时变化,但id是固定的。

return oldUser.getId() == newUser.getId();

}

@Override

public boolean areContentsTheSame(@NonNull User oldUser, @NonNull User newUser) {

// 注意:如果你使用equals,你的对象会重载Object.equals()方法

// 如果不正确地返回false会导致许多动画效果

return oldUser.equals(newUser);

}

}

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值