2017-10-20 8 views
0

adapterには、曲名、曲番号、お気に入りアイコンの3つのコンポーネントが含まれているカスタムlistを作成しました。 。お気に入りのアイコンは、お気に入りのアイテムをマークするか、マークを解除するためのアイコンです。 問題が何かを理解するために添付のビデオをご覧ください。 私のアンドロイドアプリでカスタムリストをスクロールすると、カスタムアダプターの一部であるお気に入りのアイコンが独自に変更されます

Video

私は星をクリック

は、アイコンが選択されていない/選択と setOnFavoriteChangeListenerイベントを発生させます。イベントで私は isFavoriteステータスをチェックし、それに応じてデータベースを更新します。ここでは、アダプタの完全なコードは次のとおりです。

public class song_index_adapter extends ArrayAdapter<song_index_model>{ //implements View.OnClickListener { 
private ArrayList<song_index_model> dataSet; 
Context mContext; 
private int lastPosition = -1; 

public song_index_adapter(ArrayList<song_index_model> data, Context context) { 
    super(context, R.layout.song_index_row, data); 
    this.dataSet = data; 
    this.mContext=context; 
} 
// View lookup cache 
private static class ViewHolder { 
    TextView txt_sno; 
    TextView txt_title; 
    MaterialFavoriteButton favorite; 
} 
@NonNull 
@Override 
public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) { 
    // Get the data item for this position 
    final song_index_model dataModel = getItem(position); 

    // Check if an existing view is being reused, otherwise inflate the view 
    final ViewHolder viewHolder; // view lookup cache stored in tag 

    final View result; 

    if (convertView == null) { 
     viewHolder = new ViewHolder(); 
     LayoutInflater inflater = LayoutInflater.from(getContext()); 
     convertView = inflater.inflate(R.layout.song_index_row, parent, false); 

     viewHolder.txt_sno = (TextView) convertView.findViewById(R.id.sno); 
     viewHolder.txt_title = (TextView) convertView.findViewById(R.id.songTitle); 
     viewHolder.favorite = (MaterialFavoriteButton) convertView.findViewById(R.id.indexfav); 

     result=convertView; 

     convertView.setTag(viewHolder); 
    } else { 
     viewHolder = (ViewHolder) convertView.getTag(); 
     result=convertView; 
    } 

    Animation animation = AnimationUtils.loadAnimation(mContext, (position > lastPosition) ? R.anim.up_from_bottom : R.anim.down_from_top); 
    result.startAnimation(animation); 
    lastPosition = position; 

    viewHolder.txt_sno.setText(dataModel.getSno()); 
    viewHolder.txt_title.setText(dataModel.getTitle()); 

    //--- following conditional statements take care to 
    //--- not to show a star with the index letter 
    if(viewHolder.txt_sno.getText().toString().equals("")) 
     viewHolder.favorite.setVisibility(View.GONE); 
    else 
     viewHolder.favorite.setVisibility(View.VISIBLE); 

    viewHolder.favorite.setFavorite(dataModel.getFav()); 

    int fsize = (gvar.fontsize * gvar.fontstep) + gvar.fontmin; 
    viewHolder.txt_title.setTextSize(fsize); 
    viewHolder.txt_sno.setTextSize(fsize); 

    viewHolder.favorite.setOnFavoriteChangeListener(new MaterialFavoriteButton.OnFavoriteChangeListener() { 
     @Override 
     public void onFavoriteChanged(MaterialFavoriteButton buttonView, boolean isfavorite) { 
      DBHelper db = new DBHelper(mContext); 
      SQLiteDatabase sdb = db.getWritableDatabase(); 

      boolean isUpdate = db.updateData(gvar.table,dataModel.getSno(),dataModel.getTitle(),dataModel.getSong(),dataModel.getCategory(),isfavorite); 
      if(!isUpdate) 
       Toast.makeText(mContext, "Song Selection could not be saved", Toast.LENGTH_SHORT).show(); 
      else { 
       Toast.makeText(mContext, "Updated " + dataModel.getSno(), Toast.LENGTH_SHORT).show(); 
       Log.e("UPDATED", dataModel.getSno() + " " + isfavorite); 
      } 
     } 
    }); 
    return convertView; 
} 

}

このイベントはlistviewに設定し、それが基本的に好きなスターの状態をチェックし、歌のステータスを更新しているadapterファイル内にありますデータベースに格納されます。 Toast更新に関するメッセージが表示されます。

私の問題は、単にスターアイコンを押さずに上下にスクロールしていても、setOnFavoriteChangeListenerというイベントが発火し続けるということです。これは、ToastメッセージとLogレコードに見ることができます。あなたが見ることができるログ記録のスナップショットを添付しています。 Log record

私は個人的に最初の曲番号9と42と35の最後のお気に入りのアイコンを変更しました。その間に私は上下にスクロールしていただけで、UPDATEがどうやって起こっているのか分かりました。

私の目的は、お気に入りのアイテムのリストをマークすることです。

なぜ私に触れることなくsetOnFavoriteChangeListenerが解雇されるのですか?

お気に入りのアイテムをリストから選択してデータベースに保存する方法はありますか?

ありがとうございます。

+0

完全なアダプタコードを掲載することはできますか?それは間違いなく助けになるだろう。 –

+0

完全なアダプタコード – pamo

+0

アダプタコードが表示されません。 –

答えて

0

私はあなたの問題を理解したと思います。あなたのListViewのアイテムをリサイクルしているという事実と関係しています。最初のロード中はすべて正常に動作し、何も選択されていないため、dataFrame()コールはfalseを返すので、ViewFolder.favorite.setFavorite()呼び出しがOnFavoriteChangeListenerを設定したMaterialFavoriteButtonを起動しません。これは、不要な作業(I checked the source code)を防止するための最適化として、新しいお気に入り状態が前回と異なるかどうかを内部的にチェックするためです。しかし、一度選択すると、新しい状態が違うのでonFavoriteChangedが発生し、その値をデータベースに保存します。あなたの問題はスクロールを開始すると発生します。ビューがリサイクルされ、MaterialFavoriteButtonのお気に入りの状態が設定されますが、dataModel.getFav()を呼び出すとfalseに戻り、MaterialFavoriteButtonのお気に入りの状態をfalseに戻します。したがって、MaterialFavoriteButtonの古いOnFavoriteChangeListenerがもう一度起動するようになります(なぜボタンが優先されないのか)。また、以前のdataModel(注:これはクロージャの問題です)を使用してデータベースを更新しています。そのため、画面がスクロールされたビューのテキストが使用されています。ビューがリサイクルされているために古いOnFavoriteChangeListenerが呼び出されていて、初期ロード中に渡されたインスタンスがまだ存在する理由です。だから、すべてのビューには、画面全体を埋めるために、最初のものをスクロールするとトップ画面がconvertViewとしてgetView()に渡されます。viewHolder.favorite.setOnFavoriteChangeListenerをsetFavoriteの前に移動する必要があります)コール。コードにデバッグステートメントを配置し、viewHolder.favorite.setFavorite()の呼び出しをステップ実行すると、私が何を話しているのかがわかるはずです。私はこれがすべてあなたのもとにあることを願っています。そうでない場合は、コメントしてみてください。私の推奨する解決策は、保存ボタンが押されるか、Activity/Fragmentが一時停止または停止され、getView(...)の位置引数を使ってアクセスされるArrayListの中に好きな状態を格納するまで、データベースの書き込みを保留することです。これは、ListViewがスクロールされるたびにデータベースに常にアクセスする必要がないため、はるかに効率的です。

関連する問題