中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

怎么使用Jetpack paging

發布時間:2021-11-15 14:20:14 來源:億速云 閱讀:167 作者:iii 欄目:移動開發

本篇內容主要講解“怎么使用Jetpack paging”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學習“怎么使用Jetpack paging”吧!

1. Demo概述

在正式介紹paging 的使用之前,我們先來看看最終的效果是怎么樣的。

怎么使用Jetpack paging

效果是非常的簡單,就是有一個RecyclerView在顯示數據,然后我們向下滑動,滑動到一定位置,paging會自動請求數據,這也就是分頁請求的效果.paging的目的就是實現分頁加載,之前我們都是自己實現分頁,這次是Google爸爸為我們實現。不得不說,jetpack真香!

2. 準備components

要想使用paging,我們得準備幾個東西(當然,導依賴這種基本操作肯定是必須的,我就不介紹了哈)。

  1. DataSource:顧名思義,數據源,獲取數據是通過它實現的。

  2. PagedList: 數據源獲取的數據最終靠PagedList來承載。對于PagedList,我們可以這樣來理解,它就是一頁數據的集合。每請求一頁,就是新的一個PagedList對象。

  3. PagedListAdapter:這個Adapter就是一個RecyclerViewAdapter。不過我們在使用paging實現RecyclerView的分頁加載效果,不能直接繼承RecyclerViewAdapter,而是需要繼承PagedListAdapter

3. 自定義DataSource

說實話,自定義DataSource沒有什么難度,但是我為什么要單獨提出來呢?首先官方文檔上,實現的是ItemKeyedDataSource,而我這里實現的是PositionalDataSource。雖然差別不是很大,但是還是有點區別,因為在這里我踩過兩個坑。我相信,通過這兩個坑,以后遇到類似的問題,會找到解決思路。
??在貼代碼之前,我們先來看看實現PositionalDataSource需要注意的地方。
??首先,我們得了解一下需要實現的兩個方法:

方法名含義
loadInitial加載初始化數據,可以這么來理解,加載的是第一頁的數據。形象的說,當我們第一次打開頁面,需要回調此方法來獲取數據。
loadRange當有了初始化數據之后,滑動的時候如果需要加載數據的話,會調用此方法。

現在,我們來看看最終實現的代碼。

  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);
      }
  }

然后,我結合上面的代碼來介紹一下我踩過的兩個坑(其實這兩個坑可以歸并為一個坑,因為都是一個原因導致)。
??我先來描述我之前我遇到的問題,在第一次打開界面時,我發現,RecyclerView沒有顯示任何的數據,同時經過debug,發現loadInitial方法被回調到的,但是最終Adapter里面的itemCount為0。這是什么原因導致的呢?我們來看看現在的loadInitial方法的實現:

      @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);
      }

我們通過LoadInitialCallbackonResult方法一共傳遞了三個參數,這三個參數分別表示什么意思?我們先來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方法。而我這里出現了RecyclerView不顯示任何數據,是因為我調用得是兩個參數的onResult方法,導致了totalCount為0,所以顯示不出任何數據。
??第二個問題就是,數據顯示出來了,但是始終顯示一頁的數據,也就是說loadRange方法不會調用。其實也是totalCount導致的,當時我解決了第一個的問題時,直接給totalCount傳遞的是Listsize(假設為N條)。也就是說,PositionalDataSource最終一共只會獲取N條的數據,因為第一頁的大小恰好就等于N,所以不會調用loadRange方法去加載更多的數據。

3. 創建ViewModel

相信比較熟悉JetPack的同學都知道,在Jetpack的架構里面,推薦每個頁面持有一個ViewModel對象,以保證數據的正確性和避免其他的問題。本文就不介紹ViewModel,不太了解的同學可以看一下的官方文檔,這是鏈接:  ViewModel Overview Part of Android Jetpack。
??之前,我們已經成功的自定義一個DataSource,現在我們來看看怎么使用ViewModelDataSource連接起來。
??首先,我們得創建工廠類,用來創建DataSource對象,這在Jetpack架構里面是基本需要。

  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;
      }
  }

至于為什么需要一個MutableLiveDataDataSource包裝一下,這個我也不是很了解,官方文檔就是這么寫的(可能是讓DataSource監聽Activity或者Fragment的生命周期,以保證只在頁面活躍狀態(onStart或者onResume)獲取數據)。
??其次,就是創建對應的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;
      }
  }

4. RecyclerView

首先,我們來看一下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內部默認實現DiffUtil來進行數據的差量計算,所以我們在構造方法里面傳遞一個DiffUtil.ItemCallback。至于DiffUtil是什么,以及它內部的算法實現,我們這里就不介紹,有興趣的同學可以關注樓主的RecyclerView源碼分析系列文章,在不久的將來,我會詳細的分析它的內部實現。
??然后,我們再來看看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));
      }
  }

整個結構就這樣的,是不是非常簡單?不過,到這里可能有人可能有疑問,我就實現了一個RecyclerView加載更多的數據,你就讓我定義這么多的類,是不是有點小題大做呢?
??其實不然,Jetpack是Google官方推薦的一種App架構方案,在這種結構下,會避免很多的問題,比如說內存泄漏和空指針異常等等。之所以使用這種方案來架構App,不是我們吃飽撐的沒事干,而是為了解決傳統架構方案下不能解決的問題。當然可能還有其他的第三方解決方案,但是肯定不比Jetpack權威,畢竟Google爸爸親自設計的。

到此,相信大家對“怎么使用Jetpack paging”有了更深的了解,不妨來實際操作一番吧!這里是億速云網站,更多相關內容可以進入相關頻道進行查詢,關注我們,繼續學習!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

泰安市| 房产| 千阳县| 武隆县| 武定县| 金坛市| 清丰县| 开阳县| 千阳县| 龙川县| 诸城市| 许昌县| 东乌珠穆沁旗| 山丹县| 台安县| 托克托县| 囊谦县| 海口市| 潜山县| 通渭县| 榆树市| 博爱县| 太仆寺旗| 伊通| 金湖县| 禹州市| 邛崃市| 张家川| 个旧市| 辽阳市| 汝阳县| 德格县| 中西区| 石景山区| 乐平市| 青铜峡市| 阜康市| 英超| 灵台县| 会同县| 恩平市|