当前位置: 首页 > 知识库问答 >
问题:

RecyclerView OnBindViewWholder仅在选项卡布局中调用一次

汲永嘉
2023-03-14

我有四个选项卡和四个片断(每个片断代表每个选项卡)。

每个片段都有一个垂直的回收器视图。由于所有片段视图看起来都很相似,我重新使用了相同的布局文件、相同的回收器视图项和相同的适配器。

问题是在第一个选项卡和第三个选项卡和第四个选项卡下只加载了一个项,而第二个选项卡成功地加载了整个数据。

我希望下面添加的图片能更好地理解这个问题。

这是我的适配器代码

public class OthersAdapter extends RecyclerView.Adapter<OthersAdapter.OthersViewHolder> {

    private final Context context;
    private final ArrayList<LocalDealsDataFields> othersDataArray;
    private LayoutInflater layoutInflater;

    public OthersAdapter(Context context, ArrayList<LocalDealsDataFields> othersDataArray) {
        this.context = context;
        this.othersDataArray = othersDataArray;
        if (this.context != null) {
            layoutInflater = LayoutInflater.from(this.context);
        }
    }

    class OthersViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
        TextView othersSmallTitleTextView;
        ImageView othersImageView;

        OthersViewHolder(View itemView) {
            super(itemView);
            othersSmallTitleTextView = (TextView) itemView.findViewById(R.id.others_small_title);
            othersImageView = (ImageView) itemView.findViewById(R.id.others_image);
            itemView.setOnClickListener(this);
        }

        @Override
        public void onClick(View view) {
            Intent couponDetailsItem = new Intent(context, LocalDealsActivity.class);
            Bundle extras = new Bundle();
            extras.putString(Constants.SECTION_NAME, context.getString(R.string.local_deals_section_title));
            // Add the offer id to the extras. This will be used to retrieve the coupon details
            // in the next activity
            extras.putInt(Constants.COUPONS_OFFER_ID, othersDataArray.get(
                    getAdapterPosition()).getLocalDealId());
            couponDetailsItem.putExtras(extras);
            context.startActivity(couponDetailsItem);
        }
    }

    @Override
    public OthersViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view = layoutInflater.inflate(R.layout.others_items, parent, false);
        return new OthersViewHolder(view);
    }

    @Override
    public void onBindViewHolder(OthersViewHolder holder, int position) {
        String lfImage = othersDataArray.get(position).getLocalDealImage();
        String lfCategoryName = othersDataArray.get(position).getLocalDealSecondTitle();
        if (lfCategoryName != null) {
            // Set the second title
            holder.othersSmallTitleTextView.setText(lfCategoryName);
        }
        if (lfImage != null) {
            if (!lfImage.isEmpty()) {
                // Get the Uri
                Uri lfUriImage = Uri.parse(lfImage);
                // Load the Image
                Picasso.with(context).load(lfUriImage).into(holder.othersImageView);
            }
        }
    }

    @Override
    public int getItemCount() {
        return othersDataArray.size();
    }
}

我想指出几件事-

和其他答案提到的对所有支持库使用相同的版本,我已经对所有支持库使用了25.1.0版本。

数据数组的大小为20并且从适配器的GetItemCount()方法返回20。

数据数组中有预期数量的项,并且它们不为null或空。

Clean build、invalidate/caches也不起作用。

最后,我使用FragmentStatePagerAdapter在选项卡处于焦点时加载片段。

编辑:

private void parseLocalDeals(String stringResponse) throws JSONException {
    JSONArray localJSONArray = new JSONArray(stringResponse);
    // If the array length is less than 10 then display to the end of the JSON data or else
    // display 10 items.
    int localArrayLength = localJSONArray.length() <= 20 ? localJSONArray.length() : 20;
    for (int i = 0; i < localArrayLength; i++) {
        // Initialize Temporary variables
        int localProductId = 0;
        String localSecondTitle = null;
        String localImageUrlString = null;
        JSONObject localJSONObject = localJSONArray.getJSONObject(i);
        if (localJSONObject.has(JSONKeys.KEY_LOCAL_DEAL_ID)) {
            localProductId = localJSONObject.getInt(JSONKeys.KEY_LOCAL_DEAL_ID);
        }
        if (localJSONObject.has(JSONKeys.KEY_LOCAL_DEAL_CATEGORY)) {
            localSecondTitle = localJSONObject.getString(JSONKeys.KEY_LOCAL_DEAL_CATEGORY);
        }
        if (localJSONObject.has(JSONKeys.KEY_LOCAL_DEAL_IMAGE)) {
            localImageUrlString = localJSONObject.getString(JSONKeys.KEY_LOCAL_DEAL_IMAGE);
        }

        if (localImageUrlString != null) {
            if (!localImageUrlString.isEmpty()) {
                // Remove the dots at the start of the Product Image String
                while (localImageUrlString.charAt(0) == '.') {
                    localImageUrlString = localImageUrlString.replaceFirst(".", "");
                }
                // Replace the spaces in the url with %20 (useful if there is any)
                localImageUrlString = localImageUrlString.replaceAll(" ", "%20");
            }
        }

        LocalDealsDataFields localDealsData = new LocalDealsDataFields();
        localDealsData.setLocalDealId(localProductId);
        localDealsData.setLocalDealSecondTitle(localSecondTitle);
        localDealsData.setLocalDealImage(localImageUrlString);

        localDealsDataArray.add(localDealsData);
    }

    // Initialize the Local Deals List only once and notify the adapter that data set has changed
    // from second time. If you initializeRV the localDealsRVAdapter at an early instance and only
    // use the notifyDataSetChanged method here then the adapter doesn't update the data. This is
    // because the adapter won't update items if the number of previously populated items is zero.
    if (localDealsCount == 0) {
        if (localArrayLength != 0) {
            // Populate the Local Deals list
            // Specify an adapter
            localDealsRVAdapter = new OthersAdapter(context, localDealsDataArray);
            localDealsRecyclerView.setAdapter(localDealsRVAdapter);
        } else {
            // localArrayLength is 0; which means there are no rv elements to show.
            // So, remove the layout
            contentMain.setVisibility(View.GONE);
            // Show no results layout
            showNoResultsIfNoData(localArrayLength);
        }
    } else {
        // Notify the adapter that data set has changed
        localDealsRVAdapter.notifyDataSetChanged();
    }
    // Increase the count since parsing the first set of results are returned
    localDealsCount = localDealsCount + 20;
    // Remove the progress bar and show the content
    prcVisibility.success();
}

编辑2:

对于那些想要详细探究代码的人,我已经将部分代码移到了另一个项目中,并在GitHub上共享了它。下面是链接https://github.com/gsrikar/tablayout,要了解层次结构,请查看自述文件。

谁能告诉我我错过了什么?

共有1个答案

佟云
2023-03-14

这不是一个很好的回答,但太长了,不适合发表评论。

我已经复制了(几乎)你的适配器代码,它完全为我工作。我相信我也做了和你一样的事。我使用相同的布局文件,相同的项目和相同的适配器用于所有选项卡。我认为您的适配器代码没有问题。

我说‘几乎’是因为我不得不更改一些东西,因为我没有访问您的数据。我更改了LocalDealsDataField模型以包含BitmapDrawable&我更改了OnBindViewWholder()来处理它。

    BitmapDrawable lfImage = othersDataArray.get(position).getLocalDealImage();
    holder.othersImageView.setBackground(lfImage);

这里是如何在onCreateView()中设置适配器的

    rootView = inflater.inflate(R.layout.recycler_view, container, false);
    mRecyclerView = (RecyclerView) rootView.findViewById(R.id.recyclerview);
    mRecyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
    mAdapter = new OthersAdapter(this.getContext(), list);
    mRecyclerView.setAdapter(mAdapter);
 类似资料:
  • 我是Android新手,因此面临这样的问题。 fragment_main: 所以我需要这些标签有不同内容的网格布局。

  • 页边距在它们之间的选项卡和选定的选项卡上有一个勾号

  • 我已经搜索了很多关于如何使用SlidengTablayout在片段之间进行通信的内容,但还没有找到一个好的答案。我知道使用ActionBar,但我想要的是androidLollipop使用SlidingTabLayout的新方式。我试过了-

  • 我想创建一个应用程序,使用带有滑动视图的选项卡布局(类似于这样): 问题来了:我在网上到处找一个可以解释如何做这种事情的指南,但我所做的一切都对我不起作用。我在某个地方读到标签布局与Lollipop是不推荐的,所以我试图找到一个替代的方法来做我想做的事情,但什么也没有。我试图创建的每个选项卡布局应用程序在测试时都以崩溃告终,我认为这是由于的某些原因,总是因为选项卡在Lollipop中是不推荐的。我

  • 我有一个应用程序,它使用选项卡进行导航。通过这些选项卡,我在布局中使用和。 我已经在应用程序的主中配置了这些内容。在这里,我为添加了一个页面更改监听器,并更改了关于位置的选项卡。当按下选项卡时,我也会以另一种方式进行操作。这都没问题。 然后我就有了标签中的内容。它们都扩展了类。第一个必须根据设备改变布局。在横向平板电脑()上,我有一个包含两个片段的布局,而其他设备只有一个片段。这是由appiate

  • 问题是:我的MainActivity中的布局是在我有机会完成调用firebase以恢复应用程序数据之前生成的。如果我旋转屏幕,从而导致onCreate在MainActivity中再次运行,则生成的所有内容都正常。 在我的应用程序中,我有一个自定义的应用程序类实现,它对Firebase进行一系列调用,以恢复数据/确保数据始终同步。然而,我有大约20个ValueEventListeners,而不是几个