【问题标题】:Endless RecyclerView with ProgressBar for paginationEndless RecyclerView 和 ProgressBar 用于分页
【发布时间】:2016-03-29 15:44:11
【问题描述】:

我正在使用RecyclerView 并以十个批次从 API 获取对象。对于分页,我使用EndlessRecyclerOnScrollListener。

一切正常。现在剩下的就是在列表底部添加一个进度微调器,同时由 API 获取下一批对象。这是 Google Play 商店应用程序的屏幕截图,显示ProgressBar 肯定是RecyclerView:

问题是,RecyclerView 和 EndlessRecyclerOnScrollListener 都没有内置支持在获取下一批对象时在底部显示 ProgressBar。

我已经看到了以下答案:

1. Put an indeterminate ProgressBar as footer in a RecyclerView grid.

2. Adding items to Endless Scroll RecyclerView with ProgressBar at bottom.

我对这些答案不满意(都是同一个人)。这涉及在用户滚动时将null 对象插入数据集中,然后在下一批交付后将其取出。它看起来像一个 hack,它回避了可能正常工作也可能不正常工作的主要问题。它会在列表中造成一些不和谐和失真

在这里使用SwipeRefreshLayout 不是解决方案。 SwipeRefreshLayout 涉及从顶部拉取 最新 项,无论如何它不会显示进度视图。

有人可以为此提供一个好的解决方案吗?我很想知道谷歌是如何为他们自己的应用程序实现的(Gmail 应用程序也有)。有没有详细介绍过的文章?所有答案和 cmets 将不胜感激。谢谢。

其他一些参考资料:

1. Pagination with RecyclerView。 (精湛的概述......)

2. RecyclerView header and footer。 (更多相同...)

3. Endless RecyclerView with ProgressBar at bottom.

【问题讨论】:

  • 好的 - 我问了你提到的问题 2,直到现在我找不到更好的解决方案来解决 Vilen 提出的问题。我还在一些包含 recyclerview 的活动中使用了他的解决方案,完全没有问题。据我所知,recyclerview 中没有对 progressBar 的内置支持,因为谷歌将它构建为没有内置花里胡哨的开发人员的香草选项,所以如果你想要花里胡哨,你需要自己将它们构建到 recyclerview .您是否有理由怀疑 Vilen 的代码并且有没有对您不起作用的情况?
  • 好吧,我会更详细地解释...使用notifyItemInserted() 和notifyItemRemoved() 当用户滚动会导致列表中出现一些滞后和不和谐的效果。这种方法总是会发生这种情况,尤其是当用户扔列表时。谷歌自己的应用程序也在其分页列表中显示微调器,但没有任何类型的列表项滞后或移动。我得出的结论是,他们使用了其他一些方法,这些方法不涉及在用户滚动时将null 对象添加到数据集中......所以我对他们的解决方案感兴趣...... :)
  • 所以使用的“null”对象有点问题——我不使用它,我在对象arrayList 中添加了一个名为“viewType”的额外字段,并将其值设置为“progressBar”。在我的适配器的“getItemViewType”方法中,我检索对象的“viewType”,然后使用它来确定我应该显示哪个视图,它是普通的recyclerview 视图还是progressBar。这有助于防止空指针异常。滚动时我没有遇到任何滞后或锯齿状的影响。如果你想自己测试一下,试试我做的这个 repo:github.com/Winghin2517/ReverseLayoutRecyclerview
  • repo 是一个 reverseLayoutRecyclerview,里面有他的代码,但它是一个反向的 recyclerview,在 recyclerview 中只包含 3 个项目。您可以取消注释代码部分,如果您向上滚动以使其更具功能性,它将添加 15 个以上的项目。
  • 如果您不想破解适配器,让 getItemCount 在等待下一页时返回实际大小 + 1,您可以尝试在布局中的 RecyclerView 下方添加微调器并更改其可见性相应。我使用第二种方法让微调器重叠最新的可见项目(具有半透明背景)

标签: android android-listview android-recyclerview android-5.0-lollipop android-progressbar


【解决方案1】:

这是更简单、更清洁的方法。

从this Codepath Guide 实现无限滚动,然后按照以下步骤操作。

1.在 RecyclerView 下添加进度条。

    <android.support.v7.widget.RecyclerView
        android:id="@+id/rv_movie_grid"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:paddingBottom="50dp"
        android:clipToPadding="false"
        android:background="@android:color/black"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent">

    </android.support.v7.widget.RecyclerView>

    <ProgressBar
        android:id="@+id/progressBar"
        style="?android:attr/progressBarStyle"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:visibility="invisible"
        android:background="@android:color/transparent"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent" />

这里 android:paddingBottom="50dp" 和 android:clipToPadding="false" 非常重要。

2。获取对进度条的引用。

progressBar = findViewById(R.id.progressBar);

3.定义显示和隐藏进度条的方法。

void showProgressView() {
    progressBar.setVisibility(View.VISIBLE);
}

void hideProgressView() {
    progressBar.setVisibility(View.INVISIBLE);
}

【讨论】:

  • 当没有更多数据要加载时如何移除底部填充。它显示50dp的空间,看起来很奇怪
  • @BhargavThanki 您可以通过获取 RecyclerView 的实例以编程方式删除填充。删除 hideProgressView() 中的填充并添加到 showProgressView() 中。
  • 这个实现有一些缺点,当项目在移动设备的全屏时不显示加载器,所以你最好使用标准样式并在你的视图中定义不同的视图类型进行分页。
  • 使用 View.GONE ,它将使进度不可见,并将您的 recyclerview 限制在底部
【解决方案2】:

我在我的旧项目上实现了这个,我做了如下......

我已经创建了一个interface,就像你的例子中的人所做的那样

public interface LoadMoreItems {
  void LoadItems();
}

然后我在我的Adapter 上添加了一个addOnScrollListener()

 recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
            @Override
            public void onScrolled(RecyclerView recyclerView,
                                   int dx, int dy) {
                super.onScrolled(recyclerView, dx, dy);

                totalItemCount = linearLayoutManager.getItemCount();
                lastVisibleItem = linearLayoutManager
                        .findLastVisibleItemPosition();
                if (!loading
                        && totalItemCount <= (lastVisibleItem + visibleThreshold)) {
                    //End of the items
                    if (onLoadMoreListener != null) {
                        onLoadMoreListener.LoadItems();
                    }
                    loading = true;

                }
            }
        });

onCreateViewHolder() 是我放置 ProgressBar 的位置。

@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent,
                                                  int viewType) {
    RecyclerView.ViewHolder vh;
    if (viewType == VIEW_ITEM) {
        View v = LayoutInflater.from(parent.getContext()).inflate(
                R.layout.list_row, parent, false);

        vh = new StudentViewHolder(v);
    } else {
        View v = LayoutInflater.from(parent.getContext()).inflate(
                R.layout.progressbar_item, parent, false);

        vh = new ProgressViewHolder(v);
    }
    return vh;
}

在我的MainActivity 上,我放置LoadItems() 以添加其他项目是:

mAdapter.setOnLoadMoreListener(new LoadMoreItems() {
        @Override
        public void LoadItems() {
            DataItemsList.add(null);
            mAdapter.notifyItemInserted(DataItemsList.size() - 1);

            handler.postDelayed(new Runnable() {
                @Override
                public void run() {
                    //   remove progress item
                    DataItemsList.remove(DataItemsList.size() - 1);
                    mAdapter.notifyItemRemoved(DataItemsList.size());
                    //add items one by one
                    //When you've added the items call the setLoaded()
                    mAdapter.setLoaded();
                    //if you put all of the items at once call
                    // mAdapter.notifyDataSetChanged();
                }
            }, 2000); //time 2 seconds

        }
    });

有关更多信息,我只是关注了这个Github repository(注意:这是使用AsyncTask 也许它作为我的答案很有用,因为我是手动完成的,而不是来自API 的数据,但它应该工作也很好)这篇文章也对我有帮助endless-recyclerview-with-progress-bar

另外我不知道你有没有给它起名字,但我也找到了这个帖子infinite_scrolling_recyclerview,也许它也对你有帮助。

如果这不是您要查找的内容,请告诉我并告诉我此代码有什么问题,我会尝试根据您的喜好对其进行修改。

希望对你有帮助。

编辑

既然你不想删除一个项目...我发现我猜一个人只删除了这个帖子上的footer:diseño-android-endless-recyclerview。

这是给ListView的,但我知道你可以把它改成RecyclerView他没有删除任何他只是把Visible/Invisible放在ProgressBar看的项目:detecting-end-of-listview

也看看:这个问题android-implementing-progressbar-and-loading-for-endless-list-like-android

【讨论】:

  • 谢谢 .... 这是我试图避免的方法,因为我不想在滚动进行时添加和删除项目... :)
  • 但是你只去掉算作项的进度,你试过了吗?
  • 是的......我们添加和删除空对象......我试图避免这种情况,因为它会导致列表抖动......谷歌自己的应用程序似乎没有使用这种方法。 .. :)
  • 抱歉回复晚了,Skizo ...我正在研究您提供的那些链接... :)
  • @Y.S.你找到更好的了吗?如果你这样做了,如果你愿意,请随时与我分享。我想知道如何更有效地做到这一点:P
【解决方案3】:

还有另一种方法可以做到这一点。

  • 首先你的适配器的 getItemCount 返回listItems.size() + 1

  • 在getItemViewType() 中为position &gt;= listItems.size() 返回VIEW_TYPE_LOADING。这样,加载程序将仅显示在回收站视图列表的末尾。此解决方案的唯一问题是即使在到达最后一页后,也会显示加载程序,因此为了解决您将 x-pagination-total-count 存储在适配器中的问题,并且

  • 然后你改变条件以返回视图类型

    (position &gt;= listItem.size())&amp;&amp;(listItem.size &lt;= xPaginationTotalCount).

我刚想出这个主意,你觉得呢?

【讨论】:

  • 它工作正常吗?没有滞后和失真?
  • 为什么会有任何失真像每个获取项目视图类型的 2 个条件检查这种逻辑的缺点不是效率,但是在下一页的网络请求失败的情况下,加载程序图标仍会显示在列表末尾
  • 感谢您的努力......我会试试这个...... :)
  • 我已经这样做了,但是没有分页最大计数检查和网络请求失败时的回退>.>,无论如何它是平滑的,没有失真或任何东西
【解决方案4】:

这是我不添加虚假项目的解决方法(在 Kotlin 中但很简单):

在您的适配器中添加:

private var isLoading = false
private val VIEWTYPE_FORECAST = 1
private val VIEWTYPE_PROGRESS = 2

override fun getItemCount(): Int {
    if (isLoading)
        return items.size + 1
    else
        return items.size
}

override fun getItemViewType(position: Int): Int {
    if (position == items.size - 1 && isLoading)
        return VIEWTYPE_PROGRESS
    else
        return VIEWTYPE_FORECAST
}

override fun onCreateViewHolder(parent: ViewGroup?, viewType: Int): RecyclerView.ViewHolder {
    if (viewType == VIEWTYPE_FORECAST)
        return ForecastHolder(LayoutInflater.from(context).inflate(R.layout.item_forecast, parent, false))
    else
        return ProgressHolder(LayoutInflater.from(context).inflate(R.layout.item_progress, parent, false))
}

override fun onBindViewHolder(holder: RecyclerView.ViewHolder?, position: Int) {
    if (holder is ForecastHolder) {
        //init your item
    }
}

public fun showProgress() {
    isLoading = true
}


public fun hideProgress() {
    isLoading = false
}

现在您可以在 API 调用之前轻松调用showProgress()。和hideProgress() API 调用完成后。

【讨论】:

    【解决方案5】:

    我喜欢向适配器添加进度视图持有者的想法,但它往往会导致一些丑陋的逻辑操作来获得你想要的东西。视图持有者方法通过处理getItemCount()、getItemViewType()、getItemId(position) 的返回值以及您可能想要包含的任何类型的getItem(position) 方法来强制您防止额外的页脚项目。

    另一种方法是在加载开始和结束时分别在RecyclerView 下方显示或隐藏ProgressBar,以管理Fragment 或Activity 级别的ProgressBar 可见性。这可以通过将ProgressBar 直接包含在视图布局中或将其添加到自定义RecyclerView ViewGroup 类中来实现。这种解决方案通常会导致更少的维护和更少的错误。

    更新:当您在内容加载时向上滚动视图时,我的建议会造成问题。 ProgressBar 将粘在视图布局的底部。这可能不是您想要的行为。出于这个原因,向适配器添加进度视图支架可能是最好的功能性解决方案。只是不要忘记保护您的项目访问器方法。 :)

    【讨论】:

    • 是的,我相信这也很好。和 ListView 中的页眉页脚概念很像吧?
    • @Y.S.我用代码 sn-p 更新了我的答案以澄清我的建议。
    【解决方案6】:

    此解决方案的灵感来自此页面上的 Akshar Patels 解决方案。我稍微修改了一下。

    1. 加载第一个项目时,ProgressBar 居中看起来不错。

    2. 当没有更多要加载的项目时,我不喜欢底部剩余的空白填充。此解决方案已将其删除。

    首先是 XML:

    <android.support.v7.widget.RecyclerView
        android:id="@+id/video_list"
        android:paddingBottom="60dp"
        android:clipToPadding="false"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent">
    
    </android.support.v7.widget.RecyclerView>
    
    <ProgressBar
        android:id="@+id/progressBar2"
        style="?android:attr/progressBarStyle"
        android:layout_marginTop="10dp"
        android:layout_width="wrap_content"
        android:layout_centerHorizontal="true"
        android:layout_height="wrap_content"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"/>
    

    然后我以编程方式添加了以下内容。

    加载第一个结果后,将其添加到您的 onScrollListener。它将 ProgressBar 从中心移动到底部:

    ConstraintLayout.LayoutParams layoutParams = (ConstraintLayout.LayoutParams) loadingVideos.getLayoutParams();
    layoutParams.topToTop = ConstraintLayout.LayoutParams.UNSET;
    loadingVideos.setLayoutParams(layoutParams);
    

    当没有更多项目存在时,像这样删除底部的填充:

    recyclerView.setPadding(0,0,0,0);
    

    像往常一样隐藏和显示您的 ProgressBar。

    【讨论】:

      【解决方案7】:

      另一种可能的解决方案是使用 RecyclerView 1.2.0 中提供的 ConcatAdapter。缺点是这个库版本还处于 alpha 阶段。

      使用这种方法,单独的适配器用于进度指示器,与主适配器连接。

       val concatAdapter = ConcatAdapter(dataAdapter, progressAdapter)
      

      progressAdapter 应该从 getItemCount() 方法返回 0 或 1,具体取决于加载状态。

      更多信息:https://medium.com/androiddevelopers/merge-adapters-sequentially-with-mergeadapter-294d2942127a

      并查看recyclerview库当前的稳定版本,可能在阅读的时候已经是稳定版本了:https://developer.android.com/jetpack/androidx/releases/recyclerview


      另一种可行的方法是使用回收站视图项目装饰。使用这种方法还可以避免修改 ViewHolders。 也可以为装饰器设置动画,例如:https://medium.com/mobile-app-development-publication/animating-recycler-view-decorator-9b15fa4b2c23

      基本上,当加载指示器应该存在时添加项目装饰器,使用 recyclerView.addItemDecoration() 函数,然后使用 recyclerView.removeItemDecoration() 删除。在显示项目装饰以使动画运行时,在 recyclerView 上不断地 invalidateItemDecorations()。


      第三种可能性是使用 Google 的 Paging 库(Jetpack 的一部分)、v3 中提供的页眉和页脚适配器(仍处于测试阶段) https://www.youtube.com/watch?v=1cwqGOku2a4

      【讨论】:

        【解决方案8】:

        试试这个简单的代码:

        <?xml version="1.0" encoding="utf-8"?>
        <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".MainActivity">
        
        <androidx.recyclerview.widget.RecyclerView
            android:id="@+id/recyclerview_cities"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_above="@id/preogressbar"
            />
        <ProgressBar
            android:id="@+id/preogressbar"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:visibility="gone"
            android:layout_alignParentBottom="true"
            android:layout_centerHorizontal="true"
            />
        </RelativeLayout>
        

        当您的列表项已经滚动时显示进度条,当您从服务获取数据时隐藏进度条。

        【讨论】:

          【解决方案9】:

          你可以像这样在 recycleView 中使用 layout_above 标签:

          <RelativeLayout
                              android:layout_width="match_parent"
                              android:layout_height="match_parent"
                              android:layout_marginLeft="16dp"
                              android:layout_marginRight="16dp"
                              android:orientation="vertical">
                              <androidx.recyclerview.widget.RecyclerView
                                  android:id="@+id/rv"
                                  android:layout_below="@+id/tv2"
                                  android:layout_width="match_parent"
                                  android:focusable="false"
                                  android:layout_height="wrap_content"
                                  android:layout_marginTop="24dp"
                                  android:layout_above="@+id/pb_pagination"/>
          
                               <ProgressBar
                                  android:id="@+id/pb_pagination"
                                  style="@style/Widget.AppCompat.ProgressBar"
                                  android:layout_width="30dp"
                                  android:layout_height="30dp"
                                  android:indeterminate="true"
                                   android:visibility="gone"
                                  android:layout_alignParentBottom="true"
                                  android:layout_centerHorizontal="true" />
              </RelativeLayout>
          

          【讨论】:

            【解决方案10】:

            添加适配器

            在 RecyclerView 的预定义位置插入一个新项目

             public void insert(int position, JobModel data) {
                         joblist.add(position, data);
                         notifyItemInserted(position);
                    }.
                
              public void updateList(  ArrayList<JobModel> data) {
                    try {
                        for (int i = joblist.size(); i < data.size(); i++)
                            insert(i, data.get(i));   
                  }catch (Exception e){} }.
            

            当 page==2 时从活动调用 apiSaveJobsAdapter.updateList(joblist);

            【讨论】:

              【解决方案11】:

              不同的方法是在 onBindViewHolder 中启动 API 调用,并在项目视图中初始放置一些进度指示器。通话结束后,您更新视图(隐藏进度并显示接收到的数据)。例如,使用 Picasso 进行图像加载,onBindViewHolder 方法如下所示

              @Override
              public void onBindViewHolder(final MovieViewHolder holder, final int position) {
                  final Movie movie = items.get(position);
                  holder.imageProgress.setVisibility(View.VISIBLE);
                  Picasso.with(context)
                          .load(NetworkingUtils.getMovieImageUrl(movie.getPosterPath()))
                          .into(holder.movieThumbImage, new Callback() {
                              @Override
                              public void onSuccess() {
                                  holder.imageProgress.setVisibility(View.GONE);
                              }
                              @Override
                              public void onError() {
              
                              }
                          });
              }
              

              在我看来,可能会出现两种情况:

              1. 您只需一次调用即可下载所有精简版本的项目(例如,适配器立即知道他必须处理 40 张图片,但按需下载 -> 我之前与 Picasso 一起展示的案例)
              2. 您正在使用真正的延迟加载,并且您要求服务器为您提供额外的数据块。在这种情况下,第一个先决条件是从服务器获得足够的响应以及必要的信息。举例 { “偏移”:0, “总数”:100, “项目”:[{项目}] }

              那里的响应意味着您收到了总共 100 条数据的第一块。我的方法是这样的:

              查看 在获得第一块数据(例如 10 个)后,将它们添加到适配器中。

              RecyclerView.Adapter.getItemCount 只要当前可用项目的数量低于总数量(例如可用 10 个;总计 100 个),在 getItemCount 方法中您将返回 items.size() + 1

              RecyclerView.Adapter.getItemViewType 如果数据总量大于适配器中可用项目的数量并且 position = items.size() (即您在 getItemCount 方法中虚构添加了项目),则作为视图类型,您将返回一些进度指示器。否则你会返回正常的布局类型

              RecyclerView.Adapter.onCreateViewHolder 当您被要求使用进度指示器视图类型时,您需要做的就是要求您的演示者获取额外的项目块并更新适配器

              因此,基本上,这是您不必从列表中添加/删除项目并且您可以控制触发延迟加载的情况的方法。

              下面是代码示例:

              public class ForecastListAdapter extends RecyclerView.Adapter<ForecastListAdapter.ForecastVH> {
              private final Context context;
              private List<Forecast> items;
              private ILazyLoading lazyLoadingListener;
              
              public static final int VIEW_TYPE_FIRST         = 0;
              public static final int VIEW_TYPE_REST          = 1;
              public static final int VIEW_TYPE_PROGRESS      = 2;
              
              public static final int totalItemsCount = 14;
              
              public ForecastListAdapter(List<Forecast> items, Context context, ILazyLoading lazyLoadingListener) {
                  this.items = items;
                  this.context = context;
                  this.lazyLoadingListener = lazyLoadingListener;
              }
              
              public void addItems(List<Forecast> additionalItems){
                  this.items.addAll(additionalItems);
                  notifyDataSetChanged();
              }
              
              @Override
              public int getItemViewType(int position) {
                  if(totalItemsCount > items.size() && position == items.size()){
                      return VIEW_TYPE_PROGRESS;
                  }
                  switch (position){
                      case VIEW_TYPE_FIRST:
                          return VIEW_TYPE_FIRST;
                      default:
                          return VIEW_TYPE_REST;
                  }
              }
              
              @Override
              public ForecastVH onCreateViewHolder(ViewGroup parent, int viewType) {
                  View v;
                  switch (viewType){
                      case VIEW_TYPE_PROGRESS:
                          v = LayoutInflater.from(parent.getContext()).inflate(R.layout.forecast_list_item_progress, parent, false);
                          if (lazyLoadingListener != null) {
                              lazyLoadingListener.getAdditionalItems();
                          }
                          break;
                      case VIEW_TYPE_FIRST:
                          v = LayoutInflater.from(parent.getContext()).inflate(R.layout.forecast_list_item_first, parent, false);
                          break;
                      default:
                          v = LayoutInflater.from(parent.getContext()).inflate(R.layout.forecast_list_item_rest, parent, false);
                          break;
                  }
                  return new ForecastVH(v);
              }
              
              @Override
              public void onBindViewHolder(ForecastVH holder, int position) {
                  if(position < items.size()){
                      Forecast item = items.get(position);
                      holder.date.setText(FormattingUtils.formatTimeStamp(item.getDt()));
                      holder.minTemperature.setText(FormattingUtils.getRoundedTemperature(item.getTemp().getMin()));
                      holder.maxTemperature.setText(FormattingUtils.getRoundedTemperature(item.getTemp().getMax()));
                  }
              
              }
              
              @Override
              public long getItemId(int position) {
                  long i = super.getItemId(position);
                  return i;
              }
              
              @Override
              public int getItemCount() {
                  if (items == null) {
                      return 0;
                  }
                  if(items.size() < totalItemsCount){
                      return items.size() + 1;
                  }else{
                      return items.size();
                  }
              }
              
              public class ForecastVH extends RecyclerView.ViewHolder{
                  @BindView(R.id.forecast_date)TextView date;
                  @BindView(R.id.min_temperature)TextView minTemperature;
                  @BindView(R.id.max_temperature) TextView maxTemperature;
                  public ForecastVH(View itemView) {
                      super(itemView);
                      ButterKnife.bind(this, itemView);
                  }
              }
              
              public interface ILazyLoading{
                  public void getAdditionalItems();
              }}
              

              也许这会激发您制作适合您需求的东西

              【讨论】:

              • 在集合的每个项中进行 Web 服务/API 调用? 真的吗? 听起来乏味且效率极低/昂贵。谢谢你的回答... :)
              • 您还需要查看零件吗?
              • 只是出于好奇 - 你有没有试一试?如果有帮助,我也很高兴收到积极的反馈
              • @Y.S. Picasso 非常擅长缓存图像,因此图像会从网络加载一次,并在随后对该图像的 onBindViewHolder 调用中重复使用。
              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 2015-08-21
              • 1970-01-01
              • 2017-11-20
              • 1970-01-01
              • 2016-03-25
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多