Android Architecture Components 系列(六)Paging 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官方提供的樣例能夠用來參考。
 
相關文章
相關標籤/搜索