2017-08-08 140 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類,而不是使用映射。