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

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

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

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

Android Studio

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

Kotlin

Kotlinは、ジェットブレインズ社のアンドリー・ブレスラフ、ドミトリー・ジェメロフが開発した、 静的型付けのオブジェクト指向プログラミング言語です。

Q&A

解決済

1回答

6674閲覧

RecyclerView内ののswitchビューを2回切り替えるとアプリが終了する

kbayashi

総合スコア18

Android

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

Android Studio

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

Kotlin

Kotlinは、ジェットブレインズ社のアンドリー・ブレスラフ、ドミトリー・ジェメロフが開発した、 静的型付けのオブジェクト指向プログラミング言語です。

1グッド

1クリップ

投稿2020/03/12 05:55

編集2020/03/12 11:41

今現在todoアプリを作っています
タスクの完了・未完了を切り替えるためにswitchビューを使って処理しているのですが、同じセルのswitchビューを2回切り替えると、アプリが強制終了してしまいます。Adapter内のrealm.executeTransaction内で二回目に、flgを更新する時にアプリが強制終了していますが、解決方法がわかりません。どなたか助言を頂けないでしょうか。
##発生しているエラーメッセージ
2020-03-12 20:27:59.431 8936-8936/? E/.example.mytas: Unknown bits set in runtime_flags: 0x8000
2020-03-12 20:28:08.039 8936-8936/com.example.mytask A/.example.mytas: java_vm_ext.cc:570] JNI DETECTED ERROR IN APPLICATION: JNI NewLocalRef called with pending exception java.lang.IllegalStateException: Cannot call this method while RecyclerView is computing a layout or scrolling androidx.recyclerview.widget.RecyclerView{ea9d690 VFED..... ......ID 0,909-1080,1584 #7f080108 app:id/task_list}, adapter:com.example.mytask.TaskAdapter@1106b89, layout:androidx.recyclerview.widget.LinearLayoutManager@9b7b78e, context:com.example.mytask.MainActivity@3b61e53
2020-03-12 20:28:08.039 8936-8936/com.example.mytask A/.example.mytas: java_vm_ext.cc:570] at void androidx.recyclerview.widget.RecyclerView.assertNotInLayoutOrScroll(java.lang.String) (RecyclerView.java:3051)
2020-03-12 20:28:08.039 8936-8936/com.example.mytask A/.example.mytas: java_vm_ext.cc:570] at void androidx.recyclerview.widget.RecyclerView$RecyclerViewDataObserver.onItemRangeChanged(int, int, java.lang.Object) (RecyclerView.java:5547)
2020-03-12 20:28:08.039 8936-8936/com.example.mytask A/.example.mytas: java_vm_ext.cc:570] at void androidx.recyclerview.widget.RecyclerView$AdapterDataObservable.notifyItemRangeChanged(int, int, java.lang.Object) (RecyclerView.java:12268)

下が現在作成しているアプリの画面です
イメージ説明

##ソースコード

adapter

1class TaskAdapter(data: OrderedRealmCollection<Task>, val realm: Realm): 2RealmRecyclerViewAdapter<Task, TaskAdapter.ViewHolder>(data, true){ 3 4 init { 5 setHasStableIds(true) 6 } 7 8 //セルに使用するビューを決める 9 class ViewHolder(cell: View) : RecyclerView.ViewHolder(cell){ 10 val date: TextView = cell.findViewById(R.id.monthText) 11 val title: TextView = cell.findViewById(R.id.textTask) 12 val time: TextView = cell.findViewById(R.id.timeText) 13 val switch: Switch = cell.findViewById(R.id.taskSwich) 14 } 15 16 //セルが必要になるたびに呼び出される 17 override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): TaskAdapter.ViewHolder { 18 val inflater = LayoutInflater.from(parent.context) 19 //セルにビューを適用 20 val view = inflater.inflate(R.layout.task_list, parent, false) 21 22 return ViewHolder(view) 23 24 } 25 26 //指定された位置にデータを表示する必要がある時、呼び出される 27 override fun onBindViewHolder(holder: TaskAdapter.ViewHolder, position: Int) { 28 29 //データを取得 30 val task: Task? = getItem(position) 31 //Viewに値をセット 32 holder.date.text = DateFormat.format("yyyy/MM/dd", task?.date) 33 holder.title.text = task?.title 34 holder.time.text = DateFormat.format("HH:mm", task?.date) 35 if(task?.flg != null) 36 holder.switch.isChecked = task?.flg 37 38 //前の項目があるなら 39 val prevTask: Task? = if (position > 0) getItem(position - 1) else null 40 val df = SimpleDateFormat("yyyy/MM/dd") 41 if(prevTask != null){ 42 //日付が一致するなら日付を消してくっつける 43 if(df.format(prevTask?.date) == df.format(task?.date)){ 44 holder.date.setVisibility(View.GONE); 45 } 46 } 47 48 //swichビューが切り替わった時 49 holder.switch.setOnCheckedChangeListener { compoundButton, isChecked -> 50 51 val paint = holder.title.paint 52 53 //チェックされたら取り消し線を引きflgをtrueに 54 if(isChecked == true){ 55 56 // なぜか再代入しなければ、取り消し線が引かれない 57 holder.title.text = task?.title 58 // 取り消し線を引く 59 paint.flags = holder.title.paintFlags or Paint.STRIKE_THRU_TEXT_FLAG 60 // アンチエイリアスをオンにする 61 paint.isAntiAlias = true 62 63 64 }else if(isChecked == false){ 65 //取り消し線を消す 66 holder.title.text = task?.title 67 paint.flags = holder.title.paintFlags and Paint.STRIKE_THRU_TEXT_FLAG.inv() 68 } 69 70 realm.executeTransaction {db: Realm-> 71 var get_task : Task? 72 get_task = db.where<Task>().equalTo("id", task?.id).findFirst() 73 get_task?.flg = holder.switch.isChecked 74 } 75 76 } 77 } 78 79 override fun getItemId(position: Int): Long { 80 return getItem(position)?.id ?: 0 81 } 82}

MainActibity

1class MainActivity : AppCompatActivity() { 2 private lateinit var realm: Realm 3 private var date: String? = null 4 5 override fun onCreate(savedInstanceState: Bundle?) { 6 super.onCreate(savedInstanceState) 7 setContentView(R.layout.activity_main) 8 setSupportActionBar(toolbar) 9 //インスタンスを取得 10 realm = Realm.getDefaultInstance() 11 task_list.layoutManager = LinearLayoutManager(this) 12 var task = realm.where<Task>().findAll() 13 task = task.sort("date") 14 val adapter = TaskAdapter(task,realm) 15 task_list.adapter = adapter 16 17 //タスク 追加ボタンタップ 18 addTask.setOnClickListener { view -> 19 //日付を編集画面に渡す 20 val nowDate = Date() 21 var format = SimpleDateFormat("HH:mm") 22 val nowTime = format.format(nowDate) 23 //選択されず初期の状態で追加ボタンを押されたら現在日時を渡す 24 if(date == null){ 25 format = SimpleDateFormat("yyyy/MM/dd") 26 date = format.format(nowDate) 27 } 28 val intent = Intent(this, TaskAddActivity::class.java) 29 date += " ${nowTime}" 30 intent.putExtra("DATE",date) 31 startActivity(intent) 32 } 33 //カレンダーの日付が選択された時 34 calendarView.setOnDateChangeListener { 35 calendarView, year, month, day -> 36 //2020/11/11形式で渡す 37 date = "${year}/${month+1}/${day}" 38 39 } 40 } 41 42 override fun onCreateOptionsMenu(menu: Menu): Boolean { 43 // Inflate the menu; this adds items to the action bar if it is present. 44 menuInflater.inflate(R.menu.menu_main, menu) 45 return true 46 } 47 48 override fun onOptionsItemSelected(item: MenuItem): Boolean { 49 // Handle action bar item clicks here. The action bar will 50 // automatically handle clicks on the Home/Up button, so long 51 // as you specify a parent activity in AndroidManifest.xml. 52 return when (item.itemId) { 53 R.id.action_settings -> true 54 else -> super.onOptionsItemSelected(item) 55 } 56 } 57 58 override fun onDestroy() { 59 super.onDestroy() 60 realm.close() 61 } 62}

tasklist

1<?xml version="1.0" encoding="utf-8"?> 2<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 3 xmlns:app="http://schemas.android.com/apk/res-auto" 4 xmlns:tools="http://schemas.android.com/tools" 5 android:layout_width="match_parent" 6 android:layout_height="wrap_content" 7 android:orientation="vertical"> 8 9 <TextView 10 android:id="@+id/monthText" 11 android:layout_width="match_parent" 12 android:layout_height="wrap_content" 13 android:layout_marginLeft="7dp" 14 android:background="@color/glay" 15 android:textSize="15sp" 16 tools:text="3月17日" /> 17 18 <LinearLayout 19 android:layout_width="match_parent" 20 android:layout_height="42dp" 21 android:background="#00FFFFFF" 22 android:orientation="horizontal"> 23 24 <androidx.constraintlayout.widget.ConstraintLayout 25 android:layout_width="wrap_content" 26 android:layout_height="match_parent" 27 android:layout_marginRight="10dp"> 28 29 <TextView 30 android:id="@+id/timeText" 31 android:layout_width="wrap_content" 32 android:layout_height="wrap_content" 33 android:layout_marginStart="8dp" 34 android:textSize="15sp" 35 app:layout_constraintBottom_toBottomOf="parent" 36 app:layout_constraintEnd_toEndOf="parent" 37 app:layout_constraintStart_toStartOf="parent" 38 app:layout_constraintTop_toTopOf="parent" 39 tools:text="01:15 AM" /> 40 41 </androidx.constraintlayout.widget.ConstraintLayout> 42 43 <androidx.constraintlayout.widget.ConstraintLayout 44 android:layout_width="match_parent" 45 android:layout_height="match_parent" 46 app:layout_constraintBottom_toBottomOf="parent" 47 app:layout_constraintTop_toTopOf="parent"> 48 49 <TextView 50 android:id="@+id/textTask" 51 android:layout_width="0dp" 52 android:layout_height="wrap_content" 53 android:layout_marginStart="16dp" 54 android:layout_marginEnd="16dp" 55 android:background="#03A9F4" 56 android:paddingLeft="8dp" 57 android:textColor="@color/design_default_color_background" 58 android:textSize="20sp" 59 app:layout_constraintBottom_toBottomOf="parent" 60 app:layout_constraintEnd_toEndOf="parent" 61 app:layout_constraintStart_toEndOf="@+id/taskSwich" 62 app:layout_constraintTop_toTopOf="parent" 63 tools:text="ご飯" /> 64 65 <Switch 66 android:id="@+id/taskSwich" 67 android:layout_width="wrap_content" 68 android:layout_height="wrap_content" 69 android:layout_marginStart="8dp" 70 app:layout_constraintBottom_toBottomOf="parent" 71 app:layout_constraintStart_toStartOf="parent" 72 app:layout_constraintTop_toTopOf="parent" /> 73 </androidx.constraintlayout.widget.ConstraintLayout> 74 75 </LinearLayout> 76 77</LinearLayout> 78
s.k👍を押しています

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

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

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

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

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

jimbe

2020/03/12 06:43 編集

> アプリが強制終了してしまいます。 その時のログをお調べになられましたでしょうか. realm が怪しく思えます.
kbayashi

2020/03/12 07:10

回答ありがとうございます。 その時のログを見ましたが、ログの内容のどこを見て調べれば良いのかわかりませんでした。
hoshi-takanori

2020/03/12 07:30

ちょっと調べてみたら、Realm.getDefaultInstance() と realm.close() をバランスさせる必要がるようですね。TaskAdapter で Realm.getDefaultInstance() や realm.close() せずに、MainActivity が持っている realm を TaskAdapter に渡して使ったらいい気がします。
kbayashi

2020/03/12 08:18 編集

回答ありがとうございます。 TaskAdapterのコンストラクタでMainで使っているrealmを受け取るようにして動かしてみましたが、やはり2回切り替えると終了します。その後ちゃんとログを良く見た結果、E/.example.mytas: Unknown bits set in runtime_flags: 0x8000というエラーが有りました。
hoshi-takanori

2020/03/12 08:49

修正後のコードを見ましたが、TaskAdapter クラスの onBindViewHolder メソッドの Realm.getDefaultInstance() や realm.close() はそのまま残ってますね。
kbayashi

2020/03/12 09:00

あ、すいません。以後気をつけます。 Realm.getDefaultInstance() や realm.close() を削除しましたがやはり強制終了します。 realm.executeTransaction内の処理をコメント化すれば強制終了はしませんでした。
hoshi-takanori

2020/03/12 09:14

そうなんですね。失礼しました。 Realmの扱いの問題ということははっきりしたと思いますが、私もRealmは詳しくないので、あとは分かりません。
kbayashi

2020/03/12 10:17

もう少し自分でもrealmについて色々調べようと思います。 親身に問題の解決を手伝ってくださりありがとうございました。
kbayashi

2020/03/13 07:10

回答ありがとうございます。 実機テストでしょうかエミュレータでしょうか? エミュレータです。 記事を教えていただき、ありがとうございます。参考にしてみます。
jimbe

2020/03/13 08:50 編集

「落ちること」と「 Unknown bits set in runtime_flags: 0x8000 」と「 realm (の使い方?)」とがどう関係するかは調べておく必要がありそうです. 例えば, realm 部分を全てコメントアウトした場合落ちるのかどうかです. 落ちれば, realm が問題の可能性が大きく, 落ちなければ realm が問題の可能性が無く(or小さく)なります.
kbayashi

2020/03/13 09:10

強制終了は治りました。 親身に考えてくださりありがとうございました。 今回で、ログの見方とデバックの大切さを学びましたので、次からはこの経験を生かしてエラー処理を早めていきたいと思います。
guest

回答1

0

自己解決

デバッグして調べていると、二回目のswichtの切り替えで、
holder.switch.setOnCheckedChangeListener呼び出し、Realmのflgの値を更新->onBindViewHolder呼び出され、holder.switch.isCheckedにフラグを格納->holder.switch.setOnCheckedChangeListener呼び出され、と、無限ループしていました。

https://teratail.com/questions/207237を参考に
holder.switch.setOnCheckedChangeListener(null)
holder.switch.isChecked = task?.flg

リスナーが呼び出されないようにしました。

投稿2020/03/13 09:01

kbayashi

総合スコア18

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問