質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
86.02%
Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

Android

Androidは、Google社が開発したスマートフォンやタブレットなど携帯端末向けのプラットフォームです。 カーネル・ミドルウェア・ユーザーインターフェイス・ウェブブラウザ・電話帳などのアプリケーションやソフトウェアをひとつにまとめて構成。 カーネル・ライブラリ・ランタイムはほとんどがC言語/C++、アプリケーションなどはJavaSEのサブセットとAndroid環境で書かれています。

Android Studio

Android Studioは、 Google社によって開発された、 Androidのネイティブアプリケーション開発に特化した統合開発ツールです。

Q&A

解決済

[AndroidStudio]ListViewの最初の項目だけCheckboxが外れてしまう[Java]

退会済みユーザー

退会済みユーザー

総合スコア0

Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

Android

Androidは、Google社が開発したスマートフォンやタブレットなど携帯端末向けのプラットフォームです。 カーネル・ミドルウェア・ユーザーインターフェイス・ウェブブラウザ・電話帳などのアプリケーションやソフトウェアをひとつにまとめて構成。 カーネル・ライブラリ・ランタイムはほとんどがC言語/C++、アプリケーションなどはJavaSEのサブセットとAndroid環境で書かれています。

Android Studio

Android Studioは、 Google社によって開発された、 Androidのネイティブアプリケーション開発に特化した統合開発ツールです。

2回答

0グッド

0クリップ

367閲覧

投稿2022/10/28 07:03

編集2022/10/28 07:08

前提

AndroidStudio[Java]で在庫管理アプリを作っています。
詰まったところがありますので質問させてください。

実現したいこと

  • チェックボックスの状態を引き継ぐ

発生している問題・エラーメッセージ

  • ListViewの最初のアイテムだけCheckBoxにチェックをしてもデータ追加の際に戻ってしまう

該当のソースコード

Java

1package com.example.zaikokanri; 2 3import android.content.Context; 4import android.graphics.Color; 5import android.os.Bundle; 6import android.util.Log; 7import android.view.LayoutInflater; 8import android.view.View; 9import android.view.ViewGroup; 10import android.widget.ArrayAdapter; 11import android.widget.Button; 12import android.widget.CheckBox; 13import android.widget.CompoundButton; 14import android.widget.EditText; 15import android.widget.ListView; 16import android.widget.TextView; 17 18import androidx.annotation.NonNull; 19import androidx.appcompat.app.AppCompatActivity; 20 21import java.text.DecimalFormat; 22import java.text.SimpleDateFormat; 23import java.util.ArrayList; 24import java.util.Date; 25import java.util.List; 26import java.util.Timer; 27import java.util.TimerTask; 28 29public class MainActivity extends AppCompatActivity { 30 31 List<CellData> cellDataList; 32 private int count; 33 private TextView clockText; 34 private ListView listView; 35 36 private Timer timer; 37 38 private ArrayAdapter<CellData> adapter; 39 40 @Override 41 protected void onCreate(Bundle savedInstanceState) { 42 super.onCreate(savedInstanceState); 43 setContentView(R.layout.activity_main); 44 45 // 初期化 46 count = 0; 47 cellDataList = new ArrayList<>(); 48 adapter = new ListViewAdapter(this, R.layout.list); 49 50 // アクションバーの変更 51 getSupportActionBar().setTitle(R.string.app_name); 52 53 // Viewの取得 54 final TextView countText = findViewById(R.id.count_text); 55 final Button plusButton = findViewById(R.id.plus_button); 56 final Button minusButton = findViewById(R.id.minus_button); 57 final Button addButton = findViewById(R.id.add_button); 58 59 clockText = findViewById(R.id.clock_text); 60 listView = findViewById(R.id.list_view); 61 62 // 加算・減算 63 plusButton.setOnClickListener(new View.OnClickListener() { 64 @Override 65 public void onClick(View v) { 66 count++; 67 if (count > 9999) { 68 count = 9999; 69 } 70 countText.setText(formatThousand(count)); 71 } 72 }); 73 minusButton.setOnClickListener(new View.OnClickListener() { 74 @Override 75 public void onClick(View v) { 76 count--; 77 if (count < 0) { 78 count = 0; 79 } 80 countText.setText(formatThousand(count)); 81 } 82 }); 83 84 // リスト追加 85 addButton.setOnClickListener(new View.OnClickListener() { 86 @Override 87 public void onClick(View v) { 88 TextView time = findViewById(R.id.clock_text); 89 TextView count = findViewById(R.id.count_text); 90 EditText comment = findViewById(R.id.comment_text); 91 92 CellData cellData = new CellData(time.getText().toString(), count.getText().toString(), comment.getText().toString()); 93 cellDataList.add(cellData); 94 adapter.add(cellData); 95 listView.setAdapter(adapter); 96 } 97 }); 98 } 99 100 @Override 101 protected void onStart() { 102 super.onStart(); 103 timer = new Timer(); 104 timer.schedule(new MainTimerTask(), 0, 100); 105 } 106 107 @Override 108 protected void onStop() { 109 super.onStop(); 110 timer.cancel(); 111 } 112 113 // 3桁ごとにカンマ挿入 114 private String formatThousand(int num) { 115 DecimalFormat df = new DecimalFormat("#,###"); 116 return df.format(num); 117 } 118 119 // データを保持するクラス 120 private class CellData { 121 boolean check; 122 String time; 123 String count; 124 String comment; 125 126 CellData(String time, String count, String comment) { 127 this.check = false; 128 this.time = time; 129 this.count = count; 130 this.comment = comment; 131 } 132 } 133 134 // カスタムアダプタークラス 135 private class ListViewAdapter extends ArrayAdapter<CellData> { 136 private CellData cellDataItem; 137 private LayoutInflater inflater; 138 private int itemLayout; 139 140 ListViewAdapter(Context context, int itemLayout) { 141 super(context, itemLayout); 142 this.inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); 143 this.itemLayout = itemLayout; 144 } 145 146 @Override 147 public @NonNull 148 View getView(final int position, View convertView, @NonNull ViewGroup parent) { 149 ViewHolder viewHolder; 150 151 if (convertView == null) { 152 convertView = inflater.inflate(itemLayout, parent, false); 153 viewHolder = new ViewHolder(); 154 viewHolder.viewCheck = convertView.findViewById(R.id.listCheckBox); 155 viewHolder.viewTime = convertView.findViewById(R.id.listTime); 156 viewHolder.viewCount = convertView.findViewById(R.id.listCount); 157 viewHolder.viewComment = convertView.findViewById(R.id.listComment); 158 convertView.setTag(viewHolder); 159 160 viewHolder.viewCheck.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { 161 @Override 162 public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { 163 // リストデータを変更 164 final CellData buf = cellDataList.get(position); 165 buf.check = isChecked; 166 cellDataList.set(position, buf); 167 Log.i("Test", "cellDataList["+position+"]のcheckに["+isChecked+"]を入れました"); 168 169 // 背景色を変更 170 final View parentView = (View) buttonView.getParent(); 171 changeBackgroundColor(parentView, position, isChecked); 172 } 173 }); 174 } else { 175 viewHolder = (ViewHolder) convertView.getTag(); 176 } 177 cellDataItem = getItem(position); 178 if (cellDataItem != null) { 179 viewHolder.viewCheck.setChecked(cellDataItem.check); 180 viewHolder.viewTime.setText(cellDataItem.time); 181 viewHolder.viewCount.setText(cellDataItem.count); 182 viewHolder.viewComment.setText(cellDataItem.comment); 183 } 184 185 // 背景色の変更 186 changeBackgroundColor(convertView, position, viewHolder.viewCheck.isChecked()); 187 188 return convertView; 189 } 190 191 // 色変え処理 192 private void changeBackgroundColor(View view, int position, boolean isChecked) { 193 if (position % 2 == 0) { 194 view.setBackgroundColor(Color.rgb(100, 149, 237)); 195 } else { 196 view.setBackgroundColor(Color.WHITE); 197 } 198 199 if (isChecked) { 200 view.setBackgroundColor(Color.GREEN); 201 } 202 } 203 204 // Viewを保持するクラス 205 private class ViewHolder { 206 CheckBox viewCheck; 207 TextView viewTime; 208 TextView viewCount; 209 TextView viewComment; 210 } 211 } 212 213 // Timerで呼び出すタスクのクラス 214 public class MainTimerTask extends TimerTask { 215 @Override 216 public void run() { 217 clockText.setText((new SimpleDateFormat("HH:mm:ss")).format(new Date())); 218 } 219 } 220} 221

試したこと

  • Logの出力によってCellData内のcheckの状況を見る

Logcat

1 2022-10-25 03:56:35.899 20520-20520/com.example.zaikokanri I/Test: list[0]のCheckedを[true]にしたよ // チェックを押したタイミング 2 2022-10-25 03:56:42.979 20520-20520/com.example.zaikokanri I/Test: list[0]のCheckedを[true]にしたよ // 追加を押したタイミング 3 2022-10-25 03:56:43.011 20520-20520/com.example.zaikokanri I/Test: list[0]のCheckedを[false]にしたよ// 追加を押したタイミング
  • なぜかCheckがtrue→falseとなってしまう

補足情報(FW/ツールのバージョンなど)

Android Studio 3.5
Build #AI-191.8026.42.35.5791312, built on August 9, 2019
JRE: 1.8.0_202-release-1483-b03 amd64
JVM: OpenJDK 64-Bit Server VM by JetBrains s.r.o
Windows 10 10.0

画像

  • 追加押下前

イメージ説明

  • 追加押下後

イメージ説明

以下のような質問にはグッドを送りましょう

  • 質問内容が明確
  • 自分も答えを知りたい
  • 質問者以外のユーザにも役立つ

グッドが多くついた質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

気になる質問をクリップする

クリップした質問は、後からいつでもマイページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

下記のような質問は推奨されていません。

  • 間違っている
  • 質問になっていない投稿
  • スパムや攻撃的な表現を用いた投稿

適切な質問に修正を依頼しましょう。

回答2

0

レイアウトをインフレートした時だけリスナを定義するのでは、問題があります。
getView で convertView が null かどうかによって infrate を制御するのは、ListView が convertView を再利用するからです。
質問の画像を見る限り、まだリストビューがスクロールするほどの件数が無い為に再利用が発生していないようですが、再利用が発生した場合、convertView が null で無い=チェックボックスのリスナが古いまま新しいデータの表示に使われ、チェックボックスの変更は古いデータに対して処理が行われることになってしまいます。

追加毎にログが出るのは、追加毎にリストに setAdapter し全ての(再)表示が行われて getView が呼ばれるため、デフォルト false のチェックボックスに setChecked で true を設定しているデータで OnCheckedChangeListener が呼ばれている為でしょう。
それだけなら常に true と出るはずですが・・・なぜ false になるのかは再現出来ていません。


java

1import android.graphics.Color; 2import android.os.*; 3import android.util.Log; 4import android.view.*; 5import android.widget.*; 6 7import androidx.annotation.NonNull; 8import androidx.appcompat.app.AppCompatActivity; 9import androidx.lifecycle.*; 10 11import java.text.*; 12import java.util.*; 13 14public class MainActivity extends AppCompatActivity { 15 @Override 16 protected void onCreate(Bundle savedInstanceState) { 17 super.onCreate(savedInstanceState); 18 setContentView(R.layout.activity_main); 19 20 getSupportActionBar().setTitle(R.string.app_name); 21 22 ListView listView = findViewById(R.id.list_view); 23 ListViewAdapter adapter = new ListViewAdapter(); 24 listView.setAdapter(adapter); 25 26 NowTimer nowTimer = new NowTimer(100); 27 getLifecycle().addObserver(nowTimer); 28 29 Counter counter = new Counter(0, 9999); 30 31 EditText commentText = findViewById(R.id.comment_text); 32 33 Button addButton = findViewById(R.id.add_button); 34 addButton.setOnClickListener(v -> { 35 CellData cellData = new CellData(nowTimer.getDate(), counter.getCount(), commentText.getText().toString()); 36 adapter.add(cellData); 37 }); 38 } 39 40 // データを保持するクラス 41 private static class CellData { 42 boolean check = false; 43 Date time; 44 int count; 45 String comment; 46 47 CellData(Date time, int count, String comment) { 48 this.time = time; 49 this.count = count; 50 this.comment = comment; 51 } 52 } 53 54 // カスタムアダプタークラス 55 private class ListViewAdapter extends BaseAdapter { 56 private final SimpleDateFormat dateFormat = new SimpleDateFormat("HH:mm:ss"); 57 private final int[] ROW_BG_COLORS = { Color.rgb(240,240,240), Color.WHITE }; 58 59 private List<CellData> cellDataList = new ArrayList<>(); 60 61 void add(CellData cellData) { 62 cellDataList.add(cellData); 63 notifyDataSetChanged(); 64 } 65 66 @Override 67 public int getCount() { 68 return cellDataList.size(); 69 } 70 @Override 71 public Object getItem(int position) { 72 return cellDataList.get(position); 73 } 74 @Override 75 public long getItemId(int position) { 76 return position; 77 } 78 @Override 79 public @NonNull View getView(int position, View convertView, @NonNull ViewGroup parent) { 80 if(convertView == null) { 81 convertView = LayoutInflater.from(parent.getContext()).inflate(R.layout.list, parent, false); 82 convertView.setTag(new ViewHolder(convertView)); 83 } 84 85 CellData cellDataItem = cellDataList.get(position); 86 ViewHolder vh = (ViewHolder)convertView.getTag(); 87 88 vh.viewCheck.setOnCheckedChangeListener(null); //次の setChecked で古いリスナが実行されないように、先に消す. 89 vh.viewCheck.setChecked(cellDataItem.check); 90 vh.viewCheck.setOnCheckedChangeListener((buttonView, isChecked) -> { 91 cellDataItem.check = isChecked; 92 Log.i("Test", "cellDataList["+position+"]のcheckに["+isChecked+"]を入れました"); 93 notifyDataSetChanged(); //データが変わったのでリストに再表示を要求 94 }); 95 vh.viewTime.setText(dateFormat.format(cellDataItem.time)); 96 vh.viewCount.setText("" + cellDataItem.count); 97 vh.viewComment.setText(cellDataItem.comment); 98 convertView.setBackgroundColor(cellDataItem.check ? Color.GREEN : ROW_BG_COLORS[position%2]); 99 100 return convertView; 101 } 102 103 // Viewを保持するクラス 104 private class ViewHolder { 105 final CheckBox viewCheck; 106 final TextView viewTime; 107 final TextView viewCount; 108 final TextView viewComment; 109 ViewHolder(View itemView) { 110 viewCheck = itemView.findViewById(R.id.listCheckBox); 111 viewTime = itemView.findViewById(R.id.listTime); 112 viewCount = itemView.findViewById(R.id.listCount); 113 viewComment = itemView.findViewById(R.id.listComment); 114 } 115 } 116 } 117 118 private class NowTimer extends TimerTask implements DefaultLifecycleObserver { 119 private SimpleDateFormat dateFormat = new SimpleDateFormat("HH:mm:ss"); 120 private TextView clockText; 121 private Handler handler; 122 private Timer timer; 123 private long period; 124 private Date now; 125 126 NowTimer(long period) { 127 this.period = period; 128 clockText = findViewById(R.id.clock_text); 129 handler = new Handler(getMainLooper()); 130 } 131 132 Date getDate() { 133 return now; 134 } 135 136 @Override 137 public void run() { 138 now = new Date(); 139 handler.post(() -> clockText.setText(dateFormat.format(now))); 140 } 141 @Override 142 public void onStart(@NonNull LifecycleOwner owner) { 143 DefaultLifecycleObserver.super.onStart(owner); 144 timer = new Timer(); 145 timer.schedule(this, 0, period); 146 } 147 @Override 148 public void onStop(@NonNull LifecycleOwner owner) { 149 DefaultLifecycleObserver.super.onStop(owner); 150 timer.cancel(); 151 timer = null; 152 } 153 } 154 155 private class Counter { 156 private DecimalFormat df = new DecimalFormat("#,###"); 157 private TextView countText; 158 private int count; 159 160 Counter(int min, int max) { 161 countText = findViewById(R.id.count_text); 162 setCount(min); 163 164 Button plusButton = findViewById(R.id.plus_button); 165 plusButton.setOnClickListener(v -> setCount(Math.min(count+1, max))); 166 167 Button minusButton = findViewById(R.id.minus_button); 168 minusButton.setOnClickListener(v -> setCount(Math.max(count-1, min))); 169 } 170 171 void setCount(int count) { 172 this.count = count; 173 countText.setText(df.format(count)); 174 } 175 int getCount() { 176 return count; 177 } 178 } 179}

投稿2022/10/28 11:16

編集2022/10/28 17:20
jimbe

総合スコア10817

良いと思った回答にはグッドを送りましょう。
グッドが多くついた回答ほどページの上位に表示されるので、他の人が素晴らしい回答を見つけやすくなります。

下記のような回答は推奨されていません。

  • 間違っている回答
  • 質問の回答になっていない投稿
  • スパムや攻撃的な表現を用いた投稿

このような回答には修正を依頼しましょう。

0

ベストアンサー

解決しました。
onChekedChangedが複数回呼び出されるのが原因だったようです。
参考サイト

Java

1 @Override 2public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { 3 if(buttonView.isPressed()) { 4 // リストデータを変更 5 final CellData buf = cellDataList.get(position); 6 buf.check = isChecked; 7 cellDataList.set(position, buf); 8 9 // 背景色を変更 10 final View parentView = (View) buttonView.getParent(); 11 changeBackgroundColor(parentView, position, isChecked); 12 } 13}

投稿2022/10/28 07:47

退会済みユーザー

退会済みユーザー

総合スコア0

良いと思った回答にはグッドを送りましょう。
グッドが多くついた回答ほどページの上位に表示されるので、他の人が素晴らしい回答を見つけやすくなります。

下記のような回答は推奨されていません。

  • 間違っている回答
  • 質問の回答になっていない投稿
  • スパムや攻撃的な表現を用いた投稿

このような回答には修正を依頼しましょう。

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
86.02%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問

同じタグがついた質問を見る

Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

Android

Androidは、Google社が開発したスマートフォンやタブレットなど携帯端末向けのプラットフォームです。 カーネル・ミドルウェア・ユーザーインターフェイス・ウェブブラウザ・電話帳などのアプリケーションやソフトウェアをひとつにまとめて構成。 カーネル・ライブラリ・ランタイムはほとんどがC言語/C++、アプリケーションなどはJavaSEのサブセットとAndroid環境で書かれています。

Android Studio

Android Studioは、 Google社によって開発された、 Androidのネイティブアプリケーション開発に特化した統合開発ツールです。