使用 SwipeRefreshLayout 获取重复的卡片视图

Posted

技术标签:

【中文标题】使用 SwipeRefreshLayout 获取重复的卡片视图【英文标题】:Getting duplicated cardviews using SwipeRefresh Layout 【发布时间】:2021-08-19 11:32:33 【问题描述】:

所以这是我的问题,我有一个 API 可以为我提供许多来源的最新消息。他们每个人都带有cardview。这里的问题是,当我使用swipeRefresh 时,它会被重复cardViews 与相同的新闻,就像如果我有10 条新闻,它会复制到20 条相同的新闻。 这是我应用swipeRefresh的代码:


package com.example.newsapp4;

import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;

import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Toast;

import com.example.newsapp4.Model.Articles;
import com.example.newsapp4.Model.Headlines;

import java.util.ArrayList;
import java.util.List;
import java.util.Locale;

import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;

public class bbcnews extends AppCompatActivity 
    Adapter adapter;
    Intent intencion;
    RecyclerView recyclerView;
    public static String source = "My Source";
    public static String API_KEY = "My API Key";
    SwipeRefreshLayout srl;

    List<Articles> articles = new ArrayList<>();
    @Override
    protected void onCreate(Bundle savedInstanceState) 
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_bbcnews);

        srl = findViewById(R.id.swipeRefresh);
        srl.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() 
            @Override
            public void onRefresh() 
                retrieveJson(source, API_KEY);
            
        );


        recyclerView = findViewById(R.id.recyclerView1);
        recyclerView.setLayoutManager(new LinearLayoutManager(this));


        adapter = new Adapter(bbcnews.this,articles);
        recyclerView.setAdapter(adapter);
        retrieveJson(source, API_KEY);

    

    public void retrieveJson(String source, String apiKey)

        srl.setRefreshing(true);
        Call<Headlines> call = ApiClient.getInstance().getApi().getHeadlines(source, apiKey);
        call.enqueue(new Callback<Headlines>() 
            @Override
            public void onResponse(Call<Headlines> call, Response<Headlines> response) 
                if(response.isSuccessful() && response.body().getArticles() != null)
                    srl.setRefreshing(false);
                    articles.clear();
                    articles = response.body().getArticles();
                    adapter.setArticles(articles);
                
            


            @Override
            public void onFailure(Call<Headlines> call, Throwable t) 
                srl.setRefreshing(false);
                Toast.makeText(bbcnews.this, t.getLocalizedMessage(), Toast.LENGTH_SHORT).show();
            
        );
    

    public String getCountry()
        Locale locale = Locale.getDefault();
        String country = locale.getCountry();
        return country.toLowerCase();

    

    public void aPerfil(View vista)
        intencion = new Intent(this, profile_activity.class);
        startActivity(intencion);
    


我认为我不需要将 xml 代码与 progressbarswipeRefresh 放在一起,但这里都是:

这是我创建cardViewItems.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_
    android:layout_
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <androidx.cardview.widget.CardView
        android:layout_
        android:layout_
        android:layout_margin="10dp"
        app:cardElevation="4dp"
        android:id="@+id/cardView"
        app:cardCornerRadius="10dp">

        <FrameLayout
            android:layout_
            android:layout_>

            <ProgressBar
                android:layout_
                android:layout_
                android:layout_gravity="center"
                android:id="@+id/loader"/>


            <ImageView
                android:layout_
                android:layout_
                android:id="@+id/image"
                android:scaleType="centerCrop"
                android:src="@drawable/img"/>

            <ImageView
                android:layout_
                android:layout_
                android:background="@drawable/gradient" />

            <TextView
                android:layout_
                android:layout_
                android:text="TITLE"
                android:textSize="20dp"
                android:padding="10dp"
                android:fontFamily="@font/g_bold"
                android:textColor="@color/white"
                android:id="@+id/tvTitle"/>

            <LinearLayout
                android:layout_
                android:layout_
                android:layout_gravity="bottom"
                android:orientation="horizontal">

                <TextView
                    android:layout_
                    android:layout_
                    android:text="Source"
                    android:textSize="16dp"
                    android:padding="10dp"
                    android:ems="15"
                    android:fontFamily="@font/g_light"
                    android:textColor="@color/white"
                    android:id="@+id/tvSource"/>
                <TextView
                    android:layout_
                    android:layout_
                    android:fontFamily="@font/g_light"
                    android:gravity="right"
                    android:text="Date"
                    android:textColor="@color/white"
                    android:padding="10dp"
                    android:textSize="16dp"
                    android:id="@+id/tvDate"/>




            </LinearLayout>
        </FrameLayout>

    </androidx.cardview.widget.CardView>



</LinearLayout>

这里是recyclerView 中带有swipeRefresh 的那个:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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_
    android:layout_
    android:orientation="vertical"
    android:background="@color/white"
    tools:context=".bbcnews">

    <TextView
        android:layout_
        android:layout_
        android:text="DINGO BBC NEWS"
        android:textColor="@color/black"
        android:textSize="20sp"
        android:fontFamily="@font/g_bold"
        android:background="@color/white"
        android:padding="10dp"
        android:textAlignment="center"/>



    <GridLayout
        android:layout_
        android:layout_
        android:layout_margin="10dp"
        android:paddingTop="10dp"
        android:paddingBottom="10dp"
        android:columnCount="2"
        android:paddingLeft="20dp"
        android:paddingRight="5dp"
        android:background="@drawable/black_background"
        android:rowCount="2">

        <EditText
            android:id="@+id/editTextTextPersonName"
            android:layout_
            android:layout_
            android:ems="10"
            android:hint="Search"
            android:textColor="@color/grey"
            android:textColorHint="@color/grey"
            android:padding="5dp"
            android:layout_column="0"
            android:background="@drawable/black_background"
            android:layout_row="0"
            android:layout_columnWeight="1"
            android:inputType="textPersonName" />

        <Button
            android:id="@+id/button2"
            android:layout_
            android:layout_
            android:paddingRight="20dp"
            android:background="@drawable/black_background"
            android:drawableRight="@drawable/ic_baseline_search_24"
            android:layout_column="1"
            android:layout_row="0"/>

    </GridLayout>


    <androidx.swiperefreshlayout.widget.SwipeRefreshLayout
        android:layout_
        android:layout_
        android:id="@+id/swipeRefresh">

        <androidx.recyclerview.widget.RecyclerView
            android:layout_
            android:layout_
            android:layout_marginTop="5dp"
            android:id="@+id/recyclerView1"/>

    </androidx.swiperefreshlayout.widget.SwipeRefreshLayout>


</LinearLayout>

这也是我的adapter.java 代码:


package com.example.newsapp4;

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;

import androidx.annotation.NonNull;
import androidx.cardview.widget.CardView;
import androidx.recyclerview.widget.RecyclerView;

import com.example.newsapp4.Model.Articles;
import com.squareup.picasso.Picasso;

import java.util.List;

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

    Context context;
    List<Articles> articles;

    public Adapter(Context context, List<Articles> articles) 
        this.context = context;
        this.articles = articles;
    

    @NonNull
    @Override
    public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) 
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.items, parent, false);
        return new ViewHolder(view);
    

    @Override
    public void onBindViewHolder(@NonNull ViewHolder holder, int position) 
        final Articles a = articles.get(position);

        String imageUrl = a.getUrlToImage();

        holder.tvTitle.setText(a.getTitle());
        holder.tvSource.setText(a.getSource().getName());
        holder.tvDate.setText(a.getPublishedAt());


        Picasso.with(context).load(imageUrl).into(holder.imageView);
    

    @Override
    public int getItemCount() 
        return articles.size();
    

    public static class ViewHolder extends RecyclerView.ViewHolder 

        TextView tvTitle,tvSource,tvDate;
        ImageView imageView;
        CardView cardView;

        public ViewHolder(@NonNull View itemView) 
            super(itemView);

            tvTitle = itemView.findViewById(R.id.tvTitle);
            tvSource = itemView.findViewById(R.id.tvSource);
            tvDate = itemView.findViewById(R.id.tvDate);
            imageView = itemView.findViewById(R.id.image);
            cardView = itemView.findViewById(R.id.cardView);

        
    

    public void setArticles(List<Articles> articles) 
        this.articles.addAll(articles);
        int count = getItemCount();
        notifyItemRangeInserted(count, count + articles.size());
    



感谢您的宝贵时间!

【问题讨论】:

能否为您的适配器添加代码以供参考? 完成,我更新了部分。 刷新时您的确切要求是需要用新数据替换所有以前的数据还是比较现有数据和新数据并仅添加不存在的数据? 我的确切要求是,当我刷新数据时,它会出现新数据,替换旧数据,但是在这种情况下,我有重要的新闻,所以即使我刷新它也会出现在那里.我只想显示例如 10 条新闻,即使我刷新并且仍然相同,但我得到了 20 条,可能有几个不同但 20 条不是我的 API 所说的 10 条,因为许多 API 链接都有大量新闻要显示像 10 甚至 100。希望你能理解我。 【参考方案1】:
   // Clear adapter list before add to list.

  public void setArticles(List<Articles> articles) 
        
                   if(this.articles!=null && this.articles.size()>0)
                      this.articles.clear();
        
                this.articles.addAll(articles);
                int count = getItemCount();
                notifyItemRangeInserted(count, count + articles.size());
            

【讨论】:

这个简单的代码对我很有用,非常感谢!【参考方案2】:

据我在您的代码中可以理解的是,在 Swipe Refresh 之后 API 调用是否成功,这就是这里的这一部分

articles.clear();
articles = response.body().getArticles();
adapter.setArticles(articles);

您正在清除 Activity 中的文章,但在您的 Adapter 中,已经有另一个文章列表,您没有清除它们。

然后,当您在以下函数中进行 adapter.setArticles(articles); 调用时,您的文章将被添加到现有的文章列表中,从而被添加到重复列表中。

public void setArticles(List<Articles> articles) 
        this.articles.addAll(articles);
        int count = getItemCount();
        notifyItemRangeInserted(count, count + articles.size());
    

要解决此问题,您可以对函数进行以下修改。

public void setArticles(List<Articles> articles, boolean clearAll) 
        if(clearAll) this.articles.clear(); 
        this.articles.addAll(articles);
        notifyDataSetChanged();
    

然后修改你的函数调用如下

adapter.setArticles(articles, true);

这样,当布尔值为真时,它将清除现有列表。另外,我建议您将插入调用替换为数据集更改调用。否则,您可以一起创建一个单独的函数来添加元素和清除现有元素。

【讨论】:

以上是关于使用 SwipeRefreshLayout 获取重复的卡片视图的主要内容,如果未能解决你的问题,请参考以下文章

android之官方下拉刷新组件SwipeRefreshLayout

Android基础控件——SwipeRefreshLayout最简单的下拉刷新

怎样实现SwipeRefreshLayout的自动刷新

如何在 SwipeRefreshLayout 中调整向下滑动的距离?

swipeRefreshLayout与webview滑动冲突

SwipeRefreshLayout源码解析