2017-08-08 138 views
0

我从互联网上获取电影数据,如名称,海报等,但对于电影类型,我需要从网上再次获取它。所以这是我对这个问题的解决方案。从RecyclerView.Adapter加载互联网数据

public class MoviesViewAllAdapter extends RecyclerView.Adapter<MoviesViewAllAdapter.MoviesViewHolder> { 

private Context mContext; 
private List<MovieBrief> mMovies; 

public MoviesViewAllAdapter(Context context, List<MovieBrief> movies) { 
    mContext = context; 
    mMovies = movies; 
} 

@Override 
public MoviesViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 
    return new MoviesViewHolder(LayoutInflater.from(mContext).inflate(R.layout.item_movie_large,parent,false)); 
} 

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

    holder.movieGenreTextView.setText(""); 
    setGenres(holder, mMovies.get(position).getId()); 

} 

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

public class MoviesViewHolder extends RecyclerView.ViewHolder { 

    public TextView movieGenreTextView; 

    public MoviesViewHolder(View itemView) { 
     super(itemView); 
     movieGenreTextView = (TextView) itemView.findViewById(R.id.text_view_genre_movie_card); 
    } 
} 

private void setGenres(final MoviesViewHolder holder, Integer movieId) { 
    ApiInterface apiService = ApiClient.getClient().create(ApiInterface.class); 
    Call<Movie> call = apiService.getMovieDetails(movieId,mContext.getResources().getString(R.string.MOVIE_DB_API_KEY)); 
    call.enqueue(new Callback<Movie>() { 
     @Override 
     public void onResponse(Call<Movie> call, Response<Movie> response) { 
      if(response.code() != 200) return; 
      List<Genre> genresList = response.body().getGenres(); 
      String genres = ""; 
      for (int i=0;i<genresList.size();i++) { 
       if(i == genresList.size()-1) { 
        genres = genres.concat(genresList.get(i).getGenreName()); 
       } 
       else { 
        genres = genres.concat(genresList.get(i).getGenreName()+", "); 
       } 
      } 
      holder.movieGenreTextView.setText(genres); 
     } 

     @Override 
     public void onFailure(Call<Movie> call, Throwable t) { 

     } 
    }); 
} 

} 

但这里的问题是,执行一扔,并去了recyclerview其显示风格是不相关的电影的时候,这是载入类型是随机的。 可能是因为我正在将数据加载到onBindViewHolder上,当持有者从屏幕上消失时,它会加载到随机的持有者中。是这样吗 ?

+0

你不应该在那里打电话。你无法控制被调用的次数。一个接一个地取回电影列表后去做,除非可以立即要求几个。 –

+0

另外,你想使用'if(!response.isSuccessful())return;'而不是代码。 –

+0

@MatiasOlocco我通过检查其代码200. 是response.isSuccessful()做同样的事情?不知道这种方法。 –

回答

1

我相信你的问题是你每次在列表中创建视图时都会收到整个电影列表。我不确定服务器如何返回这些数据,但我的猜测是,每次调用服务器时,都不能保证数据的顺序是一致的。你每次都得到一个随机顺序,但试图提取它的固定位置,这就是为什么这些流派不相关。

问题的行是onBindViewHolder被称为每次创建视图时,该功能是调用setGenres这是越来越新的电影列表是按随机顺序。

你可以做两件事情来解决这个问题:第一

  1. 搜索电影,发现它的索引,然后用它来获得体裁。但是,这仍然是一个非常糟糕的设计,因为对于N部电影的列表,您将N次调用服务器。
  2. 首先获取列表,将其作为ArrayList存储在Adapter中。现在遍历它,而不必每次

    public class MoviesViewAllAdapter extends RecyclerView.Adapter<MoviesViewAllAdapter.MoviesViewHolder> { 
    . 
    . 
    . 
    List<Movie> list = new ArrayList<>; 
    
    public void setList(List movies){ 
        //get data from server before creating the adapter. call this on your adapter and store the data here 
        this.list = movies; 
    } 
    
    private void setGenres(final MoviesViewHolder holder, Integer movieId){ 
        //iterate the field list instead of calling the server 
    } 
    . 
    . 
    . 
    } 
    
+0

那么你为什么不从同一个列表中获得流派呢?如果该列表没有流派,则添加另一个类似的字段,以便您不必每次都获取流派 – SoroushA

+0

好吧,所以您要说我应该将两个列表传递给我的适配器。 MovieBrief和其他电影之一。这将工作,我会猜...将尝试,并标记接受这个答案。谢谢 ! :) –

+0

确切。这些列表必须以相同的顺序。理想情况下,您将拥有一个包含所有数据的列表,但这当然取决于您的设计约束 – SoroushA

1

调用服务器的问题与错误的流派正在显示由视图/保持器由RecyclerView预制的再循环引起的。当您滚动MoviesViewHolder的实例并重新使用视图时,当您触发加载Movie详细信息时,ViewHolder将与MovieRef关联,但在获取电影细节的调用结束时,持有者现在被分配给不同的电影。

在我看来,最好的做法是加载电影细节并将它们缓存在地图中,例如HashMap<Integer, Movie> mMoviesDetails;,当调用API结束时,您可以将Movie对象存储在那里。

public void onResponse(Call<Movie> call, Response<Movie> response) { 
      if(response.code() != 200) return; 
     mMoviesDetails.put(movieId, response.body()); 
     notifyDataSetChanged(); 
    } 

然后在你的适配器可以将onBindViewHolder更改为类似下面:

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

    holder.movieGenreTextView.setText(""); 
    Movie movie = mMoviesDetails.get(mMovies.get(position).getId()); 
    if(movie != null){ 
     /// set data to holder 
    }else { 
     //load data from network 
     loadGenres(mMovies.get(position).getId()); 
    } 


} 

这是根据当前的实现只是示例代码,一般来说我不会加载内的这个数据适配器,但将这种类型的任务委派给可将数据存储在Realm等数据库中的专用API类,而不是使用映射。