2016-12-27 78 views
3

我目前正在创建一个应用程序,它将向最终用户显示当前电影海报的网格。我通过使用TheMovieDB API获取电影数据,并通过使用ASync任务在应用程序中获取数据。我希望最终能够在我的应用中实现分页功能,在这种情况下,用户会看到电影海报的准无尽网格。何时为RecyclerView创建新适配器 - notifyDataSet()不工作?

因此,我接触到这个的方式是我创建了我的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在没有任何数据的情况下初始化,为什么我必须重新创建适配器?当然,对这个问题的任何帮助将不胜感激!

+1

面糊适配器创建一个方法'addData',只是调用该方法PN'onPostExecute()''一样mAdpater.setData( ');然后'mAdapter.notifyDataSetChanged();' –

+0

'notifyItemRangeInserted(int positionStart, int itemCount)'也可以使用 – Raghunandan

回答

2

您正在更改哪个Adapter适用的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()必须在创建新ArrayList得到postExecute回报,如果分配新的ArrayList到列表将其传递给ListView的Adapter,然后引用被更改,并且Adapter不会侦听更新(notifyDataSetChanged),因为您的数据集没有更改,只有引用发生更改。

+0

谢谢!这已经完全解决了我的问题。你的解释是有道理的:D – coolDude

1
@Override 
    protected void onPostExecute(List<Movie> parsedMovies){ 
     mMoviesList.add(parsedMovies); 
     mAdapter.notifyDataSetChanged(); 
    } 
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(); 
    } 
} 
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