本篇內(nèi)容主要講解“怎么使用Jetpack paging”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強(qiáng)。下面就讓小編來帶大家學(xué)習(xí)“怎么使用Jetpack paging”吧!
為江西等地區(qū)用戶提供了全套網(wǎng)頁設(shè)計制作服務(wù),及江西網(wǎng)站建設(shè)行業(yè)解決方案。主營業(yè)務(wù)為網(wǎng)站制作、網(wǎng)站設(shè)計、江西網(wǎng)站設(shè)計,以傳統(tǒng)方式定制建設(shè)網(wǎng)站,并提供域名空間備案等一條龍服務(wù),秉承以專業(yè)、用心的態(tài)度為用戶提供真誠的服務(wù)。我們深信只要達(dá)到每一位用戶的要求,就會得到認(rèn)可,從而選擇與我們長期合作。這樣,我們也可以走得更遠(yuǎn)!
在正式介紹paging 的使用之前,我們先來看看最終的效果是怎么樣的。
效果是非常的簡單,就是有一個RecyclerView
在顯示數(shù)據(jù),然后我們向下滑動,滑動到一定位置,paging
會自動請求數(shù)據(jù),這也就是分頁請求的效果.paging
的目的就是實現(xiàn)分頁加載,之前我們都是自己實現(xiàn)分頁,這次是Google爸爸為我們實現(xiàn)。不得不說,jetpack
真香!
要想使用paging
,我們得準(zhǔn)備幾個東西(當(dāng)然,導(dǎo)依賴這種基本操作肯定是必須的,我就不介紹了哈)。
DataSource:顧名思義,數(shù)據(jù)源,獲取數(shù)據(jù)是通過它實現(xiàn)的。
PagedList: 數(shù)據(jù)源獲取的數(shù)據(jù)最終靠
PagedList
來承載。對于PagedList
,我們可以這樣來理解,它就是一頁數(shù)據(jù)的集合。每請求一頁,就是新的一個PagedList
對象。PagedListAdapter:這個Adapter就是一個
RecyclerView
的Adapter
。不過我們在使用paging
實現(xiàn)RecyclerView
的分頁加載效果,不能直接繼承RecyclerView
的Adapter
,而是需要繼承PagedListAdapter
。
說實話,自定義DataSource
沒有什么難度,但是我為什么要單獨提出來呢?首先官方文檔上,實現(xiàn)的是ItemKeyedDataSource
,而我這里實現(xiàn)的是PositionalDataSource
。雖然差別不是很大,但是還是有點區(qū)別,因為在這里我踩過兩個坑。我相信,通過這兩個坑,以后遇到類似的問題,會找到解決思路。
?在貼代碼之前,我們先來看看實現(xiàn)PositionalDataSource
需要注意的地方。
?首先,我們得了解一下需要實現(xiàn)的兩個方法:
方法名 | 含義 |
---|---|
loadInitial | 加載初始化數(shù)據(jù),可以這么來理解,加載的是第一頁的數(shù)據(jù)。形象的說,當(dāng)我們第一次打開頁面,需要回調(diào)此方法來獲取數(shù)據(jù)。 |
loadRange | 當(dāng)有了初始化數(shù)據(jù)之后,滑動的時候如果需要加載數(shù)據(jù)的話,會調(diào)用此方法。 |
現(xiàn)在,我們來看看最終實現(xiàn)的代碼。
public class ConcertDataSource extends PositionalDataSource<Concert> { private final Retrofit mRetrofit = new Retrofit.Builder() .baseUrl("http://api.apiopen.top/") .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) .addConverterFactory(GsonConverterFactory.create()) .build(); private final Service mService; public ConcertDataSource() { mService = mRetrofit.create(Service.class); } @Override public void loadInitial(@NonNull LoadInitialParams params, @NonNull final LoadInitialCallback<Concert> callback) { // fetchItem(0, params.pageSize, new Callback() { // @Override // public void onResult(Bean value) { // callback.onResult(value.getResult(), 0, 2000); // } // }); callback.onResult(fetchItems(0, 20), 0, 2000); } @Override public void loadRange(@NonNull LoadRangeParams params, @NonNull final LoadRangeCallback<Concert> callback) { // fetchItem(params.startPosition, params.loadSize, new Callback() { // @Override // public void onResult(Bean value) { // callback.onResult(value.getResult()); // } // }); callback.onResult(fetchItems(params.startPosition, params.loadSize)); } private List<Concert> fetchItems(int startPosition, int pageSize) { List<Concert> list = new ArrayList<>(); for (int i = startPosition; i < startPosition + pageSize; i++) { Concert concert = new Concert(); concert.setAuthor("author = " + i); concert.setContent("content = " + i); concert.setTitle("title = " + i); list.add(concert); } return list; } private void fetchItem(final int startPosition, int size, final Callback callback) { mService.getCall(startPosition, size).subscribe(new Observer<Bean>() { @Override public void onSubscribe(Disposable d) { } @Override public void onNext(Bean value) { callback.onResult(value); } @Override public void onError(Throwable e) { } @Override public void onComplete() { } }); } private interface Callback { void onResult(Bean value); } }
然后,我結(jié)合上面的代碼來介紹一下我踩過的兩個坑(其實這兩個坑可以歸并為一個坑,因為都是一個原因?qū)е?。
?我先來描述我之前我遇到的問題,在第一次打開界面時,我發(fā)現(xiàn),RecyclerView
沒有顯示任何的數(shù)據(jù),同時經(jīng)過debug,發(fā)現(xiàn)loadInitial
方法被回調(diào)到的,但是最終Adapter
里面的itemCount
為0。這是什么原因?qū)е碌哪??我們來看看現(xiàn)在的loadInitial
方法的實現(xiàn):
@Override public void loadInitial(@NonNull LoadInitialParams params, @NonNull final LoadInitialCallback<Concert> callback) { // fetchItem(0, params.pageSize, new Callback() { // @Override // public void onResult(Bean value) { // callback.onResult(value.getResult(), 0, 2000); // } // }); callback.onResult(fetchItems(0, 20), 0, 2000); }
我們通過LoadInitialCallback
的onResult
方法一共傳遞了三個參數(shù),這三個參數(shù)分別表示什么意思?我們先來LoadInitialCallback
這個類吧。
public abstract static class LoadInitialCallback<T> { public abstract void onResult(@NonNull List<T> data, int position, int totalCount); public abstract void onResult(@NonNull List<T> data, int position); }
LoadInitialCallback
一共有兩個onResult
方法。而我這里出現(xiàn)了RecyclerView
不顯示任何數(shù)據(jù),是因為我調(diào)用得是兩個參數(shù)的onResult
方法,導(dǎo)致了totalCount
為0,所以顯示不出任何數(shù)據(jù)。
?第二個問題就是,數(shù)據(jù)顯示出來了,但是始終顯示一頁的數(shù)據(jù),也就是說loadRange
方法不會調(diào)用。其實也是totalCount
導(dǎo)致的,當(dāng)時我解決了第一個的問題時,直接給totalCount
傳遞的是List
的size
(假設(shè)為N條)。也就是說,PositionalDataSource
最終一共只會獲取N條的數(shù)據(jù),因為第一頁的大小恰好就等于N,所以不會調(diào)用loadRange
方法去加載更多的數(shù)據(jù)。
相信比較熟悉JetPack
的同學(xué)都知道,在Jetpack
的架構(gòu)里面,推薦每個頁面持有一個ViewModel
對象,以保證數(shù)據(jù)的正確性和避免其他的問題。本文就不介紹ViewModel
,不太了解的同學(xué)可以看一下的官方文檔,這是鏈接:
ViewModel Overview Part of Android Jetpack。
?之前,我們已經(jīng)成功的自定義一個DataSource
,現(xiàn)在我們來看看怎么使用ViewModel
跟DataSource
連接起來。
?首先,我們得創(chuàng)建工廠類,用來創(chuàng)建DataSource
對象,這在Jetpack
架構(gòu)里面是基本需要。
public class ConcertFactory extends DataSource.Factory<Integer, Concert> { private MutableLiveData<ConcertDataSource> mSourceLiveData = new MutableLiveData<>(); @Override public DataSource<Integer, Concert> create() { ConcertDataSource concertDataSource = new ConcertDataSource(); mSourceLiveData.postValue(concertDataSource); return concertDataSource; } }
至于為什么需要一個MutableLiveData
將DataSource
包裝一下,這個我也不是很了解,官方文檔就是這么寫的(可能是讓DataSource
監(jiān)聽Activity
或者Fragment
的生命周期,以保證只在頁面活躍狀態(tài)(onStart
或者onResume
)獲取數(shù)據(jù))。
?其次,就是創(chuàng)建對應(yīng)的ViewModel
:
public class ConcertViewModel extends ViewModel { private final LiveData<PagedList<Concert>> convertList; private DataSource<Integer, Concert> concertDataSource; public ConcertViewModel() { ConcertFactory concertFactory = new ConcertFactory(); concertDataSource = concertFactory.create(); convertList = new LivePagedListBuilder<>(concertFactory, 20).build(); } public void invalidateDataSource() { concertDataSource.invalidate(); } public LiveData<PagedList<Concert>> getConvertList() { return convertList; } }
首先,我們來看一下Adapter
的定義:
public class RecyclerAdapter extends PagedListAdapter<Concert, RecyclerAdapter.RecyclerViewHolder> { protected RecyclerAdapter() { super(DIFF_CALLBACK); } @NonNull @Override public RecyclerViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_recyclerview, parent, false); return new RecyclerViewHolder(view); } @Override public void onBindViewHolder(@NonNull RecyclerViewHolder holder, int position) { Concert concert = getItem(position); if (concert != null) { holder.mTitleTextView.setText(concert.getTitle()); holder.mAuthorTextView.setText(concert.getAuthor()); holder.mContentTextView.setText(concert.getContent()); } } public static class RecyclerViewHolder extends RecyclerView.ViewHolder { TextView mTitleTextView; TextView mAuthorTextView; TextView mContentTextView; public RecyclerViewHolder(View itemView) { super(itemView); mTitleTextView = itemView.findViewById(R.id.title); mAuthorTextView = itemView.findViewById(R.id.author); mContentTextView = itemView.findViewById(R.id.content); } } private static DiffUtil.ItemCallback<Concert> DIFF_CALLBACK = new DiffUtil.ItemCallback<Concert>() { @Override public boolean areItemsTheSame(Concert oldConcert, Concert newConcert) { return oldConcert.getTitle().equals(newConcert.getTitle()); } @Override public boolean areContentsTheSame(Concert oldConcert, Concert newConcert) { return oldConcert.equals(newConcert); } }; }
在使用PagedListAdapter
時,我們需要注意的是,PagedListAdapter
內(nèi)部默認(rèn)實現(xiàn)DiffUtil
來進(jìn)行數(shù)據(jù)的差量計算,所以我們在構(gòu)造方法里面?zhèn)鬟f一個DiffUtil.ItemCallback
。至于DiffUtil
是什么,以及它內(nèi)部的算法實現(xiàn),我們這里就不介紹,有興趣的同學(xué)可以關(guān)注樓主的RecyclerView
源碼分析系列文章,在不久的將來,我會詳細(xì)的分析它的內(nèi)部實現(xiàn)。
?然后,我們再來看看Activity
里面是怎么使用的:
public class MainActivity extends AppCompatActivity { private RecyclerView mRecyclerView; private RecyclerAdapter adapter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mRecyclerView = findViewById(R.id.recyclerView); adapter = new RecyclerAdapter(); ConcertViewModel viewModel = ViewModelProviders.of(this).get(ConcertViewModel.class); viewModel.getConvertList().observe(this, concerts -> adapter.submitList(concerts)); mRecyclerView.setAdapter(adapter); mRecyclerView.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false)); mRecyclerView.addItemDecoration(new SimpleDividerDecoration(this)); } }
整個結(jié)構(gòu)就這樣的,是不是非常簡單?不過,到這里可能有人可能有疑問,我就實現(xiàn)了一個RecyclerView
加載更多的數(shù)據(jù),你就讓我定義這么多的類,是不是有點小題大做呢?
?其實不然,Jetpack
是Google官方推薦的一種App架構(gòu)方案,在這種結(jié)構(gòu)下,會避免很多的問題,比如說內(nèi)存泄漏和空指針異常等等。之所以使用這種方案來架構(gòu)App,不是我們吃飽撐的沒事干,而是為了解決傳統(tǒng)架構(gòu)方案下不能解決的問題。當(dāng)然可能還有其他的第三方解決方案,但是肯定不比Jetpack
權(quán)威,畢竟Google爸爸親自設(shè)計的。
到此,相信大家對“怎么使用Jetpack paging”有了更深的了解,不妨來實際操作一番吧!這里是創(chuàng)新互聯(lián)網(wǎng)站,更多相關(guān)內(nèi)容可以進(jìn)入相關(guān)頻道進(jìn)行查詢,關(guān)注我們,繼續(xù)學(xué)習(xí)!
當(dāng)前標(biāo)題:怎么使用Jetpackpaging
文章URL:http://chinadenli.net/article4/jsisoe.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供關(guān)鍵詞優(yōu)化、網(wǎng)站制作、ChatGPT、網(wǎng)站排名、網(wǎng)站內(nèi)鏈、網(wǎng)站維護(hù)
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)