2017-11-01 8 views
2

私のアプリケーションではRecyclerViewのかなり奇妙な問題に直面しています。 RecyclerViewを初めて使用するのではありませんが、それは初めてです。私はこれを説明するための最良の方法は、写真にあると思う:通知メソッドが頻繁に呼び出されてRecyclerViewはアイテムをオーバードローする

リストは常に更新されます。コードは少し複雑すぎて投稿できませんが、私はすべてがUIスレッドから呼び出されていると確信しています。

ここで要求されるのはコードとレイアウトです。

コード:

public class PlayersAdapter extends RecyclerView.Adapter<PlayersAdapter.ViewHolder> { 
    private final List<GameInfo.Player> players; 
    private final LayoutInflater inflater; 

    public PlayersAdapter(Context context, List<GameInfo.Player> players) { 
     this.inflater = LayoutInflater.from(context); 
     this.players = players; 
     setHasStableIds(true); 
    } 

    @Override 
    public long getItemId(int position) { 
     return players.get(position).name.hashCode(); 
    } 

    @Override 
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 
     return new ViewHolder(parent); 
    } 

    @Override 
    public void onBindViewHolder(ViewHolder holder, int position) { 
     GameInfo.Player player = players.get(position); 
     holder.name.setText(player.name); 
     holder.update(player); 
    } 

    @Override 
    public void onBindViewHolder(ViewHolder holder, int position, List<Object> payloads) { 
     if (payloads.isEmpty()) { 
      onBindViewHolder(holder, position); 
     } else { 
      holder.update((GameInfo.Player) payloads.get(0)); 
     } 
    } 

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

    public void notifyItemChanged(GameInfo.Player player) { 
     int pos = players.indexOf(player); 
     if (pos != -1) { 
      players.set(pos, player); 
      notifyItemChanged(pos, player); 
     } 
    } 

    public void notifyDataSetChanged(List<GameInfo.Player> players) { 
     this.players.clear(); 
     this.players.addAll(players); 
     notifyDataSetChanged(); 
    } 

    public class ViewHolder extends RecyclerView.ViewHolder { 
     final TextView name; 
     final SuperTextView score; 
     final ImageView status; 

     ViewHolder(ViewGroup parent) { 
      super(inflater.inflate(R.layout.player_item, parent, false)); 
      setIsRecyclable(false); 

      name = itemView.findViewById(R.id.playerItem_name); 
      score = itemView.findViewById(R.id.playerItem_score); 
      status = itemView.findViewById(R.id.playerItem_status); 
     } 

     void update(GameInfo.Player player) { 
      score.setHtml(R.string.score, player.score); 

      switch (player.status) { 
       case HOST: 
        status.setImageResource(R.drawable.ic_person_black_48dp); 
        break; 
       case IDLE: 
        status.setImageResource(R.drawable.ic_access_time_black_48dp); 
        break; 
       case JUDGING: 
       case JUDGE: 
        status.setImageResource(R.drawable.ic_gavel_black_48dp); 
        break; 
       case PLAYING: 
        status.setImageResource(R.drawable.ic_hourglass_empty_black_48dp); 
        break; 
       case WINNER: 
        status.setImageResource(R.drawable.ic_star_black_48dp); 
        break; 
       case SPECTATOR: 
        status.setImageResource(R.drawable.ic_remove_red_eye_black_48dp); 
        break; 
      } 
     } 
    } 
} 

GameInfo.Playerクラス:

public static class Player { 
     public final String name; 
     public final int score; 
     public final PlayerStatus status; 

     public Player(JSONObject obj) throws JSONException { 
      name = obj.getString("N"); 
      score = obj.getInt("sc"); 
      status = PlayerStatus.parse(obj.getString("st")); 
     } 

     @Override 
     public boolean equals(Object o) { 
      if (this == o) return true; 
      if (o == null || getClass() != o.getClass()) return false; 
      Player player = (Player) o; 
      return name.equals(player.name); 
     } 
    } 

カスタムアイテムのレイアウト(R.layout.player_item):

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    android:layout_width="match_parent" 
    android:layout_height="wrap_content" 
    android:gravity="center_vertical" 
    android:orientation="horizontal" 
    android:padding="4dp"> 

    <ImageView 
     android:id="@+id/playerItem_status" 
     android:layout_width="32dp" 
     android:layout_height="32dp" 
     android:alpha="0.54" 
     android:padding="4dp" 
     android:scaleType="fitCenter" /> 

    <LinearLayout 
     android:layout_width="match_parent" 
     android:layout_height="wrap_content" 
     android:orientation="vertical" 
     android:paddingStart="8dp"> 

     <TextView 
      android:id="@+id/playerItem_name" 
      android:layout_width="match_parent" 
      android:layout_height="wrap_content" 
      android:ellipsize="end" 
      android:lines="1" 
      android:textColor="@android:color/primary_text_light" 
      android:textSize="14sp" /> 

     <com.gianlu.commonutils.SuperTextView 
      android:id="@+id/playerItem_score" 
      android:layout_width="match_parent" 
      android:layout_height="wrap_content" /> 
    </LinearLayout> 
</LinearLayout> 

EDIT: はonBindViewHolder(ViewHolder holder, int position, List<Object> payloads)削除メソッドはnotifyItemChanged(pos, player)を使用した場合にのみ問題を解決し、問題はnotifyItemChanged(pos)のままです。なぜそれが起こるか知っていいだろう。

+0

あなたは 'RecyclerView'のコードを投稿できますか? –

+0

は、RecyclerViewアイテムからあなたのカスタムレイアウトを共有します。 –

+0

@NileshRathod質問 – Gianlu

答えて

1

私は、onBindViewHolder(ViewHolder holder, int position, List<Object> payloads)除去方法notifyItemChanged(pos)代わりのnotifyItemChanged(pos, player)を使用してsetIsRecyclable(true)とリサイクルViewHolderを設定することで、問題を修正しました。 @ RahulKumarのおかげで提案に感謝します。

+0

ありがとう。 10 char –

関連する問題