🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
Realm

RealmとはSQLiteやCore Dataに代わるモバイルデータベースです。iOSとAndroidの両方でサポートされています。

Java

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

Android

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

checkbox

checkboxは、GUIのエレメントです。また、HTML<input>タグのtype属性で扱われる値を指します。

Android Studio

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

Q&A

解決済

1回答

2899閲覧

Java チェックボックスの値の変更をデータベースに保存したい

kashikoma

総合スコア8

Realm

RealmとはSQLiteやCore Dataに代わるモバイルデータベースです。iOSとAndroidの両方でサポートされています。

Java

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

Android

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

checkbox

checkboxは、GUIのエレメントです。また、HTML<input>タグのtype属性で扱われる値を指します。

Android Studio

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

0グッド

0クリップ

投稿2019/11/02 12:39

登録したタスクを一覧表示するチェックリスト画面をRecyclerViewで作っています。
データベースはRealmを使っています。

現時点ではチェックを付けてもフラグメントの移動やアプリの再起動で消えてしまったり、新しいタスクがリストに追加されるとずれたりしてしまい、チェックボックスの値は全く保存されません。
なので、チェックボックスの値の変更を、データベースに保存・更新できるようにしたいです。

リスト画面のFragment.javaに下のコードを追加したらリスト画面を開いたとたんに落ちてしまうようになりました。

private CheckBox cb; //チェックボックス cb = view.findViewById(R.id.checkTask); cb.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { @Override public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { final Task task = new Task(); // Taskテーブルをインスタンス化 if(isChecked) { task.setCheck(true); } else { task.setCheck(false); } realm.executeTransactionAsync(new Realm.Transaction() { @Override public void execute(Realm bgRealm) { bgRealm.copyToRealmOrUpdate(task); } }); } });

はじめはonCheckedChangedの中身がいけないのかと思い、
下記のように中を空にしてやってみましたがやはり同様に落ちてしまいます。

private CheckBox cb; //チェックボックス cb = view.findViewById(R.id.checkTask); cb.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { @Override public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { } });

・リスト画面 TaskListFragment.java (チェックボックスの処理を含む全体のコード)

Java

1public class TaskListFragment extends Fragment { 2 private RecyclerView mRecyclerView; 3 private TaskAdapter adapter; 4 private Realm realm; 5 private FloatingActionButton fab; 6 7 private CheckBox cb; 8 9 @Override 10 public View onCreateView(final LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 11 View view = inflater.inflate(R.layout.fragment_task_list, container, false); 12 13 //新規作成ボタン 14 fab = view.findViewById(R.id.newTask); 15 fab.setOnClickListener(new View.OnClickListener() { 16 @Override 17 public void onClick(View view) { 18 Intent intent = new Intent(getActivity(), com.j16390mf.memo.EditTask.class); 19 startActivity(intent); 20 } 21 }); 22 23 realm = Realm.getDefaultInstance(); 24 final RealmResults<Task> result = realm.where(Task.class).findAll().sort("id", Sort.DESCENDING); 25 adapter = new TaskAdapter(result); 26 27 mRecyclerView = view.findViewById(R.id.tasklist); 28 mRecyclerView.setLayoutManager(new LinearLayoutManager(getContext())); 29 mRecyclerView.setAdapter(adapter); 30 mRecyclerView.setHasFixedSize(true); 31 mRecyclerView.addItemDecoration(new DividerItemDecoration(getContext(), DividerItemDecoration.VERTICAL)); 32 33 //チェックボックス 34 cb = view.findViewById(R.id.checkTask); 35 cb.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { 36 @Override 37 public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { 38 final Task task = new Task(); // Taskテーブルをインスタンス化 39 if(isChecked) { 40 task.setCheck(true); 41 } else { 42 task.setCheck(false); 43 } 44 realm.executeTransactionAsync(new Realm.Transaction() { 45 @Override 46 public void execute(Realm bgRealm) { 47 bgRealm.copyToRealmOrUpdate(task); 48 } 49 }); 50 } 51 }); 52 53 return view; 54 } 55 56 @Override 57 public void onDestroy() { 58 super.onDestroy(); 59 mRecyclerView.setAdapter(null); 60 realm.close(); 61 } 62}

自分で気になっているところは、
チェックボックスのViewがきちんと取得できているのかという点です。
cb = view.findViewById(R.id.checkTask);
checkTask というIDのViewは、リスト1行分のレイアウトの中にあります。
それをAdapter経由でリスト画面に表示させています。たぶん
リスト1行分のレイアウトは、リスト画面でインフレートしてるわけじゃないので、checkTaskが取得できてるのかよく分かりません。
アプリが落ちてしまう原因とは関係ないかもしれませんが。
図の説明で逆に分かりづらかったら申し訳ないです。
イメージ説明
・追加したチェックボックスの処理のコードのどこがだめっぽいか
・チェックボックスのViewを含むレイアウトはリスト画面でインフレートされてないが、ちゃんと取得できてるのかどうか

ご回答お待ちしております。


・listitem_tasklist.xml RecyclerViewのリスト1行分のレイアウト

<?xml version="1.0" encoding="utf-8"?> <android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:paddingStart="8dp" android:paddingEnd="8dp" xmlns:app="http://schemas.android.com/apk/res-auto"> <CheckBox android:id="@+id/checkTask" android:layout_width="wrap_content" android:layout_height="wrap_content" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintTop_toTopOf="parent" app:layout_constraintBottom_toBottomOf="parent" /> <TextView android:id="@+id/taskTitle" android:layout_width="wrap_content" android:layout_height="wrap_content" app:layout_constraintLeft_toRightOf="@id/checkTask" app:layout_constraintTop_toTopOf="parent" app:layout_constraintBottom_toBottomOf="parent" android:text="@string/taskTitle" android:textSize="20sp"/> <TextView android:id="@+id/taskId" android:layout_width="wrap_content" android:layout_height="wrap_content" app:layout_constraintLeft_toLeftOf="@id/taskTitle" app:layout_constraintTop_toBottomOf="@id/taskTitle" android:text="@string/taskId" android:textSize="12sp"/> <TextView android:id="@+id/closingDate" android:layout_width="wrap_content" android:layout_height="wrap_content" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toBottomOf="@id/taskTitle" android:text="@string/closingDate" android:textSize="12sp"/> </android.support.constraint.ConstraintLayout>

・TaskAdapter.java RecyclerViewのアダプタ

public class TaskAdapter extends RealmRecyclerViewAdapter<Task, TaskAdapter.TaskViewHolder> { private OrderedRealmCollection<Task> tDataset; TaskAdapter(OrderedRealmCollection<Task> taskDataset) { super(taskDataset, true); this.tDataset = taskDataset; setHasStableIds(true); } @Override public TaskViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.listitem_tasklist, parent, false); return new TaskViewHolder(view); } @Override public void onBindViewHolder(TaskViewHolder holder, int position) { final Task obj = getItem(position); holder.name.setText(obj.getName()); holder.check.setChecked(obj.getCheck()); holder.id.setText(obj.getId()); } @Override public int getItemCount() { return tDataset.size(); } static class TaskViewHolder extends RecyclerView.ViewHolder { TextView name; CheckBox check; TextView id; TaskViewHolder(View view) { super(view); name = view.findViewById(R.id.taskTitle); check = view.findViewById(R.id.checkTask); id = view.findViewById(R.id.taskId); } } }

・Task.java Taskテーブル

public class Task extends RealmObject { @PrimaryKey private String id; private String name; private boolean check; public String getId() { return id; } public void setId(String id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public boolean getCheck() { return check;} public void setCheck(boolean check) { this.check = check;} }

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

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

・追加したチェックボックスの処理のコードのどこがだめっぽいか

チェックボックスの値を保存していません.
フラグメントに追加したと言われる setOnCheckedChangeListener は, view.findViewById(R.id.checkTask) をしている TaskViewHolder のコンストラクタで行う必要があります.
なのですが, この場合, TaskAdapter.onCreateViewHolder で TaskViewHolder を生成した( setOnCheckedChangeListener を行った)のちに TaskAdapter.onBindViewHolder が呼ばれて setChecked(obj.getCheck()) を実行すると, OnCheckedChangeListener が呼ばれてしまいます.
ですので, コンストラクタでは行わず, setChecked(obj.getCheck()) の直前にリスナを削除し, setChecked(obj.getCheck()) の後に改めて リスナを登録するようにすると良いかと思います.

holder.name.setText(obj.getName()); holder.check.setOnCheckedChangeListener(null); holder.check.setChecked(obj.getCheck()); holder.check.setOnCheckedChangeListener(/*省略*/); holder.id.setText(obj.getId());

・チェックボックスのViewを含むレイアウトはリスト画面でインフレートされてないが、ちゃんと取得できてるのかどうか

インフレートして得た view からでなければ findViewById では取得出来ていないと思います.

投稿2019/11/02 13:13

jimbe

総合スコア13202

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

kashikoma

2019/11/04 12:54

アドバイスの通りやってみたらチェックの値が保存できるようになりました! チェックをつけたところのタスク名が消えてしまうのが気になりますが、今回の質問とは関係ないところだと思うので自己解決できなければまた質問したいと思います。 リスト画面のFragmentではなくTaskAdapterの方に記述するのですね。 リスナーの削除や再登録などは自分で調べていても多分辿り着けなかったと思うのでとても参考になりました。 回答ありがとうございました。
jimbe

2019/11/04 15:26

RecyclerView (や類似の ListView) でのチェックボックスの値に関しましては, FAQ 的に多数見受けられます. それはこの View での行のレイアウトの使い方が, Activity でのレイアウトのような固定的(一度作れば変更の値もずっと保持している)では無いので, 常に値を保存しなければならないことに気が付き難いからと思います. RecyclerView の行レイアウトは, 表示に必要な行数分のみ生成されます. つまり onCreateViewHolder は表示に必要な行数分のみ呼ばれ, 以降は, スクロール等で消えた行のレイアウトが次に新しい行を表示するときに使い回されて onBindViewHolder のみが呼ばれます. つまり, チェックを付けた行が画面から消えると, 次に表示する行に使い回されてチェックボックスが再設定されてしまうので, 先の行でチェックを付けたという情報は消えてしまいます. ですので, チェックを保存する場合, レイアウトが該当行を表示している間, つまり onBindViewHolder が呼ばれてから使い回されるまでの間に行う必要がありますので, 結局 onBindViewHolder でリスナを設定するのが妥当ということになります.
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.36%

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

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

質問する

関連した質問