何时为RecyclerView创建新的适配器 - notifyDataSet()不工作?

时间:2016-12-27 06:29:14

标签: java android android-recyclerview

我目前正致力于创建一个应用程序,该应用程序将向最终用户显示当前电影海报的网格。我使用TheMovieDB API获取电影数据,并使用ASync任务在应用程序中获取数据。我希望最终能够在我的应用程序中实现分页,其中向用户显示准无限的电影海报网格。

因此,我接近这个的方式是我创建了我的Movie模型对象,它将存储关于每部电影的一些数据。然后,当我从API中提取数据时,我会填充ArrayList个完整的电影对象。但是,我不确定一旦实现分页,将创建多少部电影。为了安全起见,我已将ArrayList初始化为不包含任何电影。我的ASync任务完成后(如在onPostExecute()中),我将所有电影附加到我的阵列。

我现在面临的问题是,在onPostExecute()的任务中,我认为notifyDataSetChanged()会给我一个电影海报网格。但是,情况似乎并非如此。我不确定为什么,但我必须用我新添加的数组重新创建适配器,以便海报显示在屏幕上。我在onPostExecute()中重新创建适配器的唯一原因是因为我在网上的其他地方看到了它,但没有完全理解为什么使用它。

以下是我正在使用的代码:

package com.example.android.popularmovies_stage1;

import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;

import com.squareup.picasso.Picasso;

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

public class MovieSelection extends AppCompatActivity {

    RecyclerView mRecyclerView;
    MovieAdapter mAdapter;
    List<Movie> mMoviesList = new ArrayList<>();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_movie_selection);

        mRecyclerView = (RecyclerView) findViewById(R.id.rv_movie_selection);
        GridLayoutManager layoutManager = new GridLayoutManager(getApplicationContext(), 3);
        mRecyclerView.setLayoutManager(layoutManager);

        mRecyclerView.setHasFixedSize(true);

        mAdapter = new MovieAdapter(mMoviesList);
        mRecyclerView.setAdapter(mAdapter);

        new FetchMoviesTask().execute();
    }

    private class MovieAdapter extends RecyclerView.Adapter<MovieHolder>{
        private List<Movie> adapterMovies;

        public MovieAdapter(List<Movie> movies){
            adapterMovies = movies;
        }

        @Override
        public MovieHolder onCreateViewHolder(ViewGroup viewGroup, int viewType){
            LayoutInflater inflater = LayoutInflater.from(viewGroup.getContext());
            View view = inflater.inflate(R.layout.movie_list_item, viewGroup, false);

            return new MovieHolder(view);
        }

        @Override
        public void onBindViewHolder(MovieHolder holder, int position){
            Movie currentMovie = adapterMovies.get(position);
            Picasso.with(getApplicationContext())
                    .load("https://image.tmdb.org/t/p/w185/" + currentMovie.getPosterPath())
                    .into(holder.holderImageView);
        }

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

    }

    private class MovieHolder extends RecyclerView.ViewHolder{
        ImageView holderImageView;

        public MovieHolder(View movieView){
            super(movieView);
            holderImageView = (ImageView) movieView.findViewById(R.id.list_item_image_view);
        }


    }


    private class FetchMoviesTask extends AsyncTask<Void, Void, List<Movie>>{
        @Override
        protected List<Movie> doInBackground(Void... params){
            return new MovieFetcher().fetchMovies();
        }

        @Override
        protected void onPostExecute(List<Movie> parsedMovies){
            mMoviesList = parsedMovies;
//            mAdapter.notifyDataSetChanged();  Unsure of why this is not working as I expected?
            mAdapter = new MovieAdapter(mMoviesList);
            mRecyclerView.setAdapter(mAdapter);
        }
    }
}

为什么notifyDataSetChanged()方法不能按预期工作?如果在没有任何数据的情况下初始化ArrayList,为什么必须重新创建我的适配器?当然,非常感谢对此问题的任何帮助!

4 个答案:

答案 0 :(得分:2)

您正在更改适配器所持有的ListView的引用。

// New reference which is causing issue, use .addAll() property of ArrayList.
mMoviesList = parsedMovies;     

在postExecute() -

中更新您的代码
@Override
    protected void onPostExecute(List<Movie> parsedMovies){
        mMoviesList.addAll(parsedMovies);
        // Now I am sure this will work :)
        mAdapter.notifyDataSetChanged(); 
    }

原因 - 您的新MovieFetcher().fetchMovies()必须在postExecute中创建新的ArrayList,并且如果您将新的ArrayList分配给传递给Adapter的新列表你的ListView然后引用被更改,你的适配器将不会监听更新(notifyDataSetChanged),因为你的数据集没有改变,只有参考被更改。

答案 1 :(得分:1)

@Override
    protected void onPostExecute(List<Movie> parsedMovies){
        mMoviesList.add(parsedMovies);
        mAdapter.notifyDataSetChanged(); 
    }

答案 2 :(得分:1)

在将适配器设置到RecyclerView之前,您应该调用notifyDataSetChanged()方法。

像:

private class FetchMoviesTask extends AsyncTask<Void, Void, List<Movie>>{
    @Override
    protected List<Movie> doInBackground(Void... params){
        return new MovieFetcher().fetchMovies();
    }

    @Override
    protected void onPostExecute(List<Movie> parsedMovies){
        mMoviesList = parsedMovies;
        mAdapter = new MovieAdapter(mMoviesList);
        mRecyclerView.setAdapter(mAdapter);
        mAdapter.notifyDataSetChanged();
    }
}

答案 3 :(得分:1)

在onPostExecute()中添加以下行

 mMoviesList = parsedMovies;

表示mMoviesList创建新实例,因此mAdapter.notifyDataSetChanged();无效。

使用以下代码

private class FetchMoviesTask extends AsyncTask<Void, Void, List<Movie>>{
    @Override
    protected List<Movie> doInBackground(Void... params){
        return new MovieFetcher().fetchMovies();
    }

    @Override
    protected void onPostExecute(List<Movie> parsedMovies){
      // mMoviesList.clear();// If you want clear existing data add this line, otherwise remove it
       if(parsedMovies != null){
           mMoviesList.addAll(parsedMovies);
       }
        mAdapter.notifyDataSetChanged();  Unsure of why this is not working as I expected?
    }  //end of onPostExecute
}  //end of FetchMoviesTask 

供参考check here