在刷新

时间:2017-04-19 14:32:58

标签: android android-recyclerview android-adapter loader swiperefreshlayout

我有一个问题,当我滑动刷新数据时,第一次滑动就可以了,但之后每次刷卡重新加载并反复添加相同的数据,到最后我有一个包含相同项目的列表......我正在使用装载机。 我之前试图清除,但我不明白我的代码有什么问题,如果有人可以向我解释。谢谢。

这是我的代码:

public abstract class NewsFragment extends Fragment implements LoaderManager.LoaderCallbacks<ArrayList<Articles>> {

    protected ItemAdapter mArticleAdapter;
    protected RecyclerView mRecyclerView;
    protected NewsFragment.OnNewSelectedInterface mListener;
    protected RecyclerView.LayoutManager mManager;
    protected SwipeRefreshLayout mSwipeRefreshLayout;
    protected LoaderManager mLoaderManager;
    private boolean mStateSaved;

    private static final int NEWS_LOAD_ID = 1;
    public static final String KEY_LIST = "key_list";

    public interface OnNewSelectedInterface {
        void onListNewSelected(int index, ArrayList<Articles> articles);
    }


    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {

        View view = inflater.inflate(R.layout.list_present_news, container, false);

        mListener = (NewsFragment.OnNewSelectedInterface) getActivity();
        mSwipeRefreshLayout = (SwipeRefreshLayout) view.findViewById(R.id.swipeContainer);
        mRecyclerView = (RecyclerView) view.findViewById(R.id.recyclerview);
        mManager = new LinearLayoutManager(getActivity());
        mArticleAdapter = new ItemAdapter(getActivity(), new ArrayList<Articles>(), mListener);
        mLoaderManager = getLoaderManager();
        mStateSaved = mArticleAdapter.isStateSaved();

        mRecyclerView.setAdapter(mArticleAdapter);
        mRecyclerView.setLayoutManager(mManager);

        getData();
        refreshData();

        if(!isNetworkAvailable())alertUserAboutError();

        setDivider();

        return view;
    }

    private void setDivider() {
        DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(mRecyclerView
                .getContext(), DividerItemDecoration.VERTICAL);
        mRecyclerView.addItemDecoration(dividerItemDecoration);
    }

    private void getData() {
        getLoaderManager().initLoader(NEWS_LOAD_ID, null, this).forceLoad();
    }

    private void alertUserAboutError() {
        AlertDialogFragment alertDialogFragment = new AlertDialogFragment();
        alertDialogFragment.show(getActivity().getFragmentManager(), "error_dialog");
    }

    protected abstract String[] getUrl();

    private boolean isNetworkAvailable() {
        ConnectivityManager manager = (ConnectivityManager)
                getActivity().getSystemService(Context.CONNECTIVITY_SERVICE);
        NetworkInfo networkInfo = manager.getActiveNetworkInfo();
        boolean isAvailable = false;
        if (networkInfo != null && networkInfo.isConnected()) {
            isAvailable = true;
        }
        return isAvailable;
    }

    private void refreshData() {
        mSwipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
            @Override
            public void onRefresh() {
                mArticleAdapter.clear();
                mSwipeRefreshLayout.setRefreshing(false);

            }
        });

        mSwipeRefreshLayout.setColorSchemeResources(
                android.R.color.holo_orange_light,
                android.R.color.holo_red_light);
    }

    @Override
    public Loader<ArrayList<Articles>> onCreateLoader(int id, Bundle args) {
        return new NewsLoader(getActivity(), getUrl());
    }

    @Override
    public void onLoadFinished(Loader<ArrayList<Articles>> loader, ArrayList<Articles> data) {
        if (data != null && !data.isEmpty()) {
            mArticleAdapter.addAll(data);
        }
    }

    @Override
    public void onLoaderReset(Loader<ArrayList<Articles>> loader) {
        mArticleAdapter.clear();
    }
}

我的装载机课程:

public class NewsLoader extends AsyncTaskLoader<ArrayList<Articles>>{

    private ArrayList<Articles> mArticlesArrayList;
    private String[] mUrl;

    public NewsLoader(Context context, String[] url) {
        super(context);
        mUrl = url;
    }

    @Override
    public ArrayList<Articles> loadInBackground() {

        OkHttpClient mClient = new OkHttpClient();
        for (String aMUrl : mUrl) {
            Request mRequest = new Request.Builder().url(aMUrl).build();
            try {
                Response response = mClient.newCall(mRequest).execute();
                try {
                    if (response.isSuccessful()) {
                        String json = response.body().string();
                        getMultipleUrls(json);
                    }
                } catch (IOException | JSONException e) {
                    e.printStackTrace();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return mArticlesArrayList;
    }

    private void getMultipleUrls(String jsonData) throws JSONException {

        if (mArticlesArrayList == null) {
            mArticlesArrayList = getArticleForecast(jsonData);
        } else {
            mArticlesArrayList.addAll(getArticleForecast(jsonData));
        }
    }

    private ArrayList<Articles> getArticleForecast(String jsonData) throws JSONException {
        JSONObject forecast = new JSONObject(jsonData);
        JSONArray articles = forecast.getJSONArray("articles");

        ArrayList<Articles> listArticles = new ArrayList<>(articles.length());

        for (int i = 0; i < articles.length(); i++) {
            JSONObject jsonArticle = articles.getJSONObject(i);
            Articles article = new Articles();

            String urlImage = jsonArticle.getString("urlToImage");

            article.setTitle(jsonArticle.getString("title"));
            article.setDescription(jsonArticle.getString("description"));
            article.setImageView(urlImage);
            article.setArticleUrl(jsonArticle.getString("url"));

            listArticles.add(i, article);
        }

        return listArticles;
    }
}

我的适配器类:

public class ItemAdapter extends RecyclerView.Adapter<ItemAdapter.ArticleViewHolder> {

    private static final String TAGO = ItemAdapter.class.getSimpleName();
    private final NewsFragment.OnNewSelectedInterface mListener;
    private ArrayList<Articles> mArticlesList;
    private Context mContext;
    private int lastPosition = -1;
    private boolean mStateSaved = false;


    public boolean isStateSaved() {
        return mStateSaved;
    }

    public void setStateSaved(boolean stateSaved) {
        mStateSaved = stateSaved;
    }

    public ItemAdapter(Context context, ArrayList<Articles> articles, NewsFragment.OnNewSelectedInterface listener){
        mContext = context;
        mArticlesList = articles;
        mListener = listener;
    }

    @Override
    public ArticleViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {

        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_card_view, parent, false);

        ArticleViewHolder articleViewHolder = new ArticleViewHolder(view);
        articleViewHolder.setIsRecyclable(false);
        return articleViewHolder;
    }

    @Override
    public void onBindViewHolder(ArticleViewHolder holder, int position) {

        holder.bindArticle(mArticlesList.get(holder.getAdapterPosition()));
        setAnimation(holder.itemView, holder.getAdapterPosition());
    }

    private void setAnimation(View viewToAnimate, int position) {
        if (position > lastPosition) {
            Animation animation = AnimationUtils.loadAnimation(viewToAnimate.getContext(), android.R.anim.slide_in_left);
            viewToAnimate.startAnimation(animation);
            lastPosition = position;
        }

    }

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

    public void clear() {
        mArticlesList.clear();
        notifyDataSetChanged();
    }

    public void addAll(ArrayList<Articles> articles) {
        mArticlesList.addAll(articles);
        notifyDataSetChanged();
    }


    protected class ArticleViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener{

        private ImageView mImageView;
        private TextView mTitleTextView, mDescriptionTextView;
        private FloatingActionButton mSaveButton;

        private ArticleViewHolder(View itemView) {
            super(itemView);

            mImageView = (ImageView) itemView.findViewById(R.id.photoImageView);
            mTitleTextView = (TextView) itemView.findViewById(R.id.titleWithoutImage);
            mDescriptionTextView = (TextView) itemView.findViewById(R.id.descriptionTextView);
            mSaveButton = (FloatingActionButton) itemView.findViewById(R.id.floatingActionButton);

            itemView.setOnClickListener(this);
        }

        private void bindArticle(final Articles article) {

            Glide.with(mContext).load(article.getImageView()).into(mImageView);
            mTitleTextView.setText(article.getTitle());
            mDescriptionTextView.setText(article.getDescription());
            if(mDescriptionTextView.getText().equals("")){
                mDescriptionTextView.setVisibility(View.GONE);
            }

            mSaveButton.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    insertArticle(article);
                    article.setStateSaved(true);
                }
            });

            Log.v(TAGO, "Item id : " + getItemId()
                    + "Item count : " + getItemCount()
                    + "Item position : " + getAdapterPosition()
                    + String.valueOf(article.isStateSaved()));
        }

        private void insertArticle(Articles articles) {

            String title = articles.getTitle();
            String description = articles.getDescription();
            String url = articles.getArticleUrl();

            ContentValues contentValues = new ContentValues();
            contentValues.put(ArticleContract.ArticleEntry.COLUMN_TITLE_ARTICLE, title);
            contentValues.put(ArticleContract.ArticleEntry.COLUMN_DESCRIPTION_ARTICLE, description);
            contentValues.put(ArticleContract.ArticleEntry.COLUMN_URL_ARTICLE, url);

            Uri uri = mContext.getContentResolver().insert(ArticleContract.ArticleEntry.CONTENT_URI, contentValues);

            if(uri == null) {
                Log.v(TAGO, "Error");
            } else Toast.makeText(mContext, "Article Saved", Toast.LENGTH_SHORT).show();
        }

        @Override
        public void onClick(View view) {
            mListener.onListNewSelected(getLayoutPosition(), mArticlesList);
        }

    }
}

2 个答案:

答案 0 :(得分:1)

您错误地使用了ViewHolder#setIsRecyclable;此方法旨在用于防止ViewHolder在对其进行更改时仅回收 。根据文件:

  

setIsRecyclable()的来电应始终配对(一次拨打电话)   setIsRecyclabe(false)应始终与之后的调用相匹配   setIsRecyclable(true))。

这意味着您的ViewHolder个对象都不会被回收,有效地使RecyclerView毫无价值,并阻止它在您尝试将新对象绑定到{{1}时重用视图}}

因此,简而言之,删除该行代码。

我还注意到您的适配器代码还有一些其他小问题,这可能会在将来引起许多麻烦;所以我冒昧地强调了我会做出的一些改变。

为了我自己的理智,我会将您的RecyclerView课程称为Articles

通过Article遍布整个地方通常不是一个好主意。传递给Context的{​​{1}}已经引用了View,因此您可以使用它。

对于ViewHolder代码,Context应该正在处理此问题。因此,您可以将insertArticle()传递回Activity,将听众传递给Article(以及随后的每个Activity),而不是Adapter。< / p>

您还应该考虑使用DiffUtil课程,而不是仅仅调用ViewHolder;效率更高。只需确保您的Context班级正在实施notifyDataSetChanged()Article,否则它将无效。

我没有包含动画代码(可以轻松添加回来)或保存的州代码(主要是因为我不知道你想要做什么)。

equals()
hashCode()

修改

实际问题是您的加载程序每次都使用相同的public class ArticleAdapter extends RecyclerView.Adapter<Article> { private List<Article> mData; private ArticleViewHolder.OnSelectedListener mOnSelectedListener; private ArticleViewHolder.OnSaveListener mOnSaveListener; public ArticleAdapter(ArticleViewHolder.OnSelectedListener onSelectedListener, ArticleViewHolder.OnSaveListener onSaveListener) { mOnSelectedListener = onSelectedListener; mOnSaveListener = onSaveListener; mData = new ArrayList<>(); } public void replaceData(final List<Article> data) { final List<Article> oldData = new ArrayList<>(mData); mData.clear(); if (data != null) { mData.addAll(data); } DiffUtil.calculateDiff(new DiffUtil.Callback() { @Override public int getOldListSize() { return oldData.size(); } @Override public int getNewListSize() { return mData.size(); } @Override public int areItemsTheSame(int oldItemPosition, int newItemPosition) { return oldData.get(oldItemPosition).equals(mData.get(newItemPosition)); } @Override public boolean areContentsTheSame(int oldItemPosition, int newItemPosition) { return oldData.get(oldItemPosition).equals(mData.get(newItemPosition)); } }).dispatchUpdatesTo(this); } @Override public ArticleViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_card_view, parent, false); return new SelectLocationViewHolder(view, mOnSelectedListener, mOnSaveListener); } @Override public void onBindViewHolder(ArticleViewHolder holder, int position) { holder.bind(mData.get(position)); } @Override public int getItemCount() { return mData.size(); } } ,并不断向其添加新结果。

public class ArticleViewHolder extends RecyclerView.ViewHolder {

    public interface OnSelectedListener {
        void onSelected(Article article);
    }

    public interface OnSaveListener {
        void onSave(Article article);
    }

    private View mView;
    private Article mArticle;

    private OnSelectedListener mOnSelectedListener;
    private OnSaveListener mOnSaveListener;

    private ImageView mImageView;
    private TextView mTitleTextView, mDescriptionTextView;
    private FloatingActionButton mSaveButton;

    public ArticleViewHolder(View itemView, final OnSelectedListener onSelectedListener, final OnSaveListener onSaveListener) {
        super(itemView);

        mImageView = (ImageView) itemView.findViewById(R.id.photoImageView);
        mTitleTextView = (TextView) itemView.findViewById(R.id.titleWithoutImage);
        mDescriptionTextView = (TextView) itemView.findViewById(R.id.descriptionTextView);
        mSaveButton = (FloatingActionButton) itemView.findViewById(R.id.floatingActionButton);

        mView = itemView;
        mView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                onSelectedListener.onSelected(mArticle);
            }
        });

        mSaveButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                onSaveListener.onSave(mArticle);
            }
        });
    }

    public void bind(Article article) {
        mArticle = article;
        mTitleTextView.setText(article.getTitle());

        mDescriptionTextView.setText(article.getDescription());
        if(TextUtils.isEmpty(article.getDescription())) {
            mDescriptionTextView.setVisibility(View.GONE);
        }

        Glide.with(mView.getContext()).load(article.getImage()).into(mImageView);
    }

}

另外,您可能已经注意到,我对您的ArrayList构造函数进行了一些小改动。您应该考虑创建public class NewsLoader extends AsyncTaskLoader<List<Article>> { private final String[] mUrls; private final OkHttpClient mClient; public NewsLoader(Context context, OkHttpClient client, String... urls) { super(context); mClient = client; mUrls = urls; } @Override public List<Article> loadInBackground() { List<Article> articles = new ArrayList<>(); for (String url : mUrls) { Request request = new Request.Builder().url(url).build(); try { Response response = mClient.newCall(request).execute(); if (response.isSuccessful()) { parseData(response.body().string(), articles); } } catch (IOException | JSONException e) { e.printStackTrace(); } } return articles; } private void parseData(List<Article> articles, String data) throws JSONException { JSONObject forecast = new JSONObject(data); JSONArray a = forecast.getJSONArray("articles"); for (int i = 0; i < a.length(); i++) { JSONObject o = a.getJSONObject(i); Article article = new Article( o.getString("title"), o.getString("description"), o.getString("url"), o.getString("urlToImage")); articles.add(article); } } } immutable,因为这可以防止您在处理多线程时出错。看起来应该是这样的:

Article

答案 1 :(得分:0)

@Override
public void onBindViewHolder(ArticleViewHolder holder, int position) {
    holder.bindArticle(mArticlesList.get(position));
    setAnimation(holder.itemView, position);
}


public void addAll(ArrayList<Articles> articles) {
    mArticlesList.clear();
    mArticlesList.addAll(articles);
    notifyDataSetChanged();
}

如果这不会破坏那么我认为你的api正在为你提供冗余数据。 为什么使用articleViewHolder.setIsRecyclable(false);

另一个可能导致问题的地方是

private void getMultipleUrls(String jsonData) throws JSONException {

    if (mArticlesArrayList == null) {
         mArticlesArrayList = getArticleForecast(jsonData);
    } else {
        mArticlesArrayList.addAll(getArticleForecast(jsonData));
    }
}

您正在循环调用它添加向您的arraylist添加数据。在某种程度上,您可以在ArrayList

中插入多个数据