如何防止RecyclerView在拉动SwipeRefreshLayout时出现重复数据?

问题描述 投票:0回答:1

我知道这个问题被问了很多遍,我也知道通常情况下的答案,那就是 arraylist.clear() 扫除 arraylist 在拉动 SwipeRefreshLayout. 但我的情况似乎有点不一样,我完全没有任何头绪,所以让我一步步讲出来。

我想做什么。

我有一个 RecyclerView 通常只显示1种类型的数据,那就是 List<Post> posts. 从这里开始,这个工作完全正常。现在,我想添加 NatvieAds 从谷歌Admobs到第一元素的。RecyclerView.

所以这是我的代码设置。

PostFragment:

public class PostFragment extends Fragment implement .....{

    @Override
    public void onViewCreated(@NonNull final View view, @Nullable Bundle savedInstanceState) {
        initializeRecyclerView();

        setUpSwipeRefreshLayout();

        mSwipeRefreshLayout.post(new Runnable() {
            @Override
            public void run() {
                mSwipeRefreshLayout.setRefreshing(true);
                postAdapter.removeAllStuff(); //Here clear all the item in post
                getPostInRoom(roomId);
            }
        });
    }

   private void initializeRecyclerView() {
       recyclerView = binding.postRecyclerView;
       recyclerView.setLayoutManager(new LinearLayoutManager(getActivity(),RecyclerView.VERTICAL,false));
       postAdapter = new PostAdapter(this);
       recyclerView.setAdapter(postAdapter);
   }

    private SwipeRefreshLayout mSwipeRefreshLayout;
    private void setUpSwipeRefreshLayout() {
        mSwipeRefreshLayout = binding.swipeRefreshLayout;
        mSwipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
            @Override
            public void onRefresh() {
                mSwipeRefreshLayout.setRefreshing(true);
                postAdapter.removeAllStuff(); //Here clear all the item in post
                getPostInRoom(roomId);
            }
        });
    }


    // I calling my own API in ViewModel and observe the LiveData returned.
    private void getPostInRoom(String roomId) {
        viewModel.getAllPostInRoom(roomId).observe(getViewLifecycleOwner(), new Observer<List<Post>>() {
            @Override
            public void onChanged(List<Post> posts) {
                mSwipeRefreshLayout.setRefreshing(false);

                if(posts != null && posts.size() > 0){
                    binding.postRecyclerView.setVisibility(View.VISIBLE);
                    binding.emptyStateContainer.setVisibility(View.GONE);
                    binding.unblockRoomButton.setVisibility(View.GONE);

                    postAdapter.addAllPostToList(posts); // Here add all the arraylist item into the list in adapter
                    getNativeAdsFromAdmobForPostFragment(); // here called for Admobs 

                }else if(Objects.requireNonNull(posts).size() == 0){
                    binding.emptyStateContainer.setVisibility(View.VISIBLE);
                    binding.postRecyclerView.setVisibility(View.GONE);
                }


            }
        });
    }

所以你可以看到,在 getPostInRoom() 所谓 SwipeRefreshLayout我已经打电话给你了 postAdapter.removeAllStuff() (我将在下面附上代码)。所以如果我没有弄错的话,数组列表应该是很清楚的。

以下是代码 PostFragment 致电给Admob索取广告

   //HERE CALLED TO GOOGLE ADMOB FOR THE ADS 
    private AdLoader adLoader;
    public void getNativeAdsFromAdmobForPostFragment(){


    NativeAdOptions adOptions = new NativeAdOptions.Builder()
            .setAdChoicesPlacement(ADCHOICES_TOP_RIGHT)
            .build();

    adLoader = new AdLoader.Builder(getActivity(), getResources().getString(R.string.admob_test_ad))
            .forUnifiedNativeAd(new UnifiedNativeAd.OnUnifiedNativeAdLoadedListener() {
                @Override
                public void onUnifiedNativeAdLoaded(UnifiedNativeAd unifiedNativeAd) {
                    // Show the ad.

                    if(!adLoader.isLoading()){

                        postAdapter.addAdsToList(unifiedNativeAd); //here update the ads into the arraylist of the recyclerView
                    }
                }
            })
            .withAdListener(new AdListener() {
                @Override
                public void onAdFailedToLoad(int errorCode) {
                    // Handle the failure by logging, altering the UI, and so on.
                    Log.e("MainActivity", "The previous native ad failed to load. Attempting to"
                            + " load another.");
                    if (!adLoader.isLoading()) {

                    }
                }
            })
            .withNativeAdOptions(adOptions)
            .build();

    adLoader.loadAd(new AdRequest.Builder().build());
  }


}

PostAdapater.java

public class PostAdapter  extends RecyclerView.Adapter<RecyclerView.ViewHolder> {  

    private static final int UNIFIED_ADS_VIEW  = 1;

    private static final int POST_ITEM_VIEW = 2;

    private List<Object> mRecyclerViewItem = new ArrayList<>();

    public PostAdapter(PostAdapterListener listener) {
        this.listener = listener;
    }

    public void addAllPostToList(List<Post> posts){

        mRecyclerViewItem.addAll(posts); // Here add all the post into the mRecyclerViewItem
        notifyDataSetChanged();
    }

    public void addAdsToList(UnifiedNativeAd unifiedNativeAd){
        mRecyclerViewItem.add(0,unifiedNativeAd); // Here add the 1 nativeAds into the arrayList
        notifyDataSetChanged();
    }

    public void removeAllStuff(){
        mRecyclerViewItem.clear(); // Here already called before `getPostInRoom()` in SwipeFreshLayout
        notifyDataSetChanged();
    }

    @Override
    public int getItemViewType (int position) {


        Object recyclerViewItem = mRecyclerViewItem.get(position);
        if (recyclerViewItem instanceof UnifiedNativeAd) {
            return UNIFIED_ADS_VIEW;
        }
        return POST_ITEM_VIEW;
    }

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

    ... all other code 

}

我现在有什么。

经过上面所有的代码,

  1. 第一次加载时 PostFragment:行为是正确的,这意味着广告出现在第一项的 recyclerView那么,以下是 post 我从服务器获取的。

  2. 当我把 SwipeRefreshLayout同上 post (这是3个帖子)重复和一个新的广告出现在。RecyclerView每次我拉动 SwipeRefreshLayout另外3个相同的帖子和1个新的广告被插入到了这个网站。RecyclerView 再。

这意味着, mRecyclerViewItemPostAdapater 从来没有 clear()但是,新的项目会不断地加入到 ArrayList虽然我已经 clear() 在我获取新项目之前。

问题:我在上面的情况中做错了什么?

  1. 在上述情况下,我做错了什么?

  2. 正确的处理2种类型的 data (PostUnifiedNativeAd 在我的例子中)还是在1个RecyclerView中使用2个arraylist?

android android-recyclerview admob android-livedata swiperefreshlayout
1个回答
0
投票

RecyclerView的构建目的是 recycle views. 其中的所有内容都是一个独立的过程。

  • 设置布局管理器
  • 设置适配器
  • 定义ViewHolders

即使在 Setting Adapter 部分。Adapter 不在乎 what 数据正在被传递,它只关心的是 data is there.

在你的情况下,我的建议是不要使用 ArrayList,使用 Set. a Set你不能重复这些元素,因为这是它的基本标准。保留所有的刷新逻辑封装在 ViewController在你的情况下,它看起来像一个 Fragment.

我想指出的是这个功能。

public void removeAllStuff(){
        mRecyclerViewItem.clear(); // Here already called before `getPostInRoom()` in SwipeFreshLayout
        notifyDataSetChanged();
}

这应该被避免,因为增加或删除一个项目在 DataSet 不应要求摧毁一切在 RecyclerView,然后重建它。你实际上是在阻碍主要目标的实现 RecyclerViewజజజజజజజజజజజజజజజజజజజజజజజజజజజజజజజజజజజజజజజ recycling 部分。而是利用智能方法,如 notifyItemChanged(position: Int),它将通知 RecyclerView 只有该位置的元素发生了变化,所以不必担心其他元素。

© www.soinside.com 2019 - 2024. All rights reserved.