From e805edd360b2bb07520097d715a9f004b6f395ed Mon Sep 17 00:00:00 2001 From: huewu Date: Tue, 21 Jul 2026 14:36:19 +0900 Subject: [PATCH 1/4] Add UI threading violation and context switching snippets * Create ViewThreadingViolationSnippet.kt * Add snippet for switching to Dispatchers.Main in coroutines * Add snippet for View.registerCalledFromWrongThreadListener (API 37) --- .../anr/ViewThreadingViolationSnippet.kt | 49 +++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 misc/src/main/java/com/example/snippets/anr/ViewThreadingViolationSnippet.kt diff --git a/misc/src/main/java/com/example/snippets/anr/ViewThreadingViolationSnippet.kt b/misc/src/main/java/com/example/snippets/anr/ViewThreadingViolationSnippet.kt new file mode 100644 index 000000000..8818711da --- /dev/null +++ b/misc/src/main/java/com/example/snippets/anr/ViewThreadingViolationSnippet.kt @@ -0,0 +1,49 @@ +package com.example.snippets.anr + +import android.view.View +import android.widget.TextView +import androidx.annotation.RequiresApi +import androidx.lifecycle.LifecycleOwner +import androidx.lifecycle.lifecycleScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext + +// Mock/stub classes so the documentation snippets compile cleanly. +interface MyData { + val title: String +} + +interface MyRepository { + suspend fun getData(): MyData +} + +@SuppressWarnings("unused") +object ViewThreadingViolationSnippet { + + fun switchContext( + lifecycleOwner: LifecycleOwner, + myRepository: MyRepository, + myTextView: TextView + ) { + // [START android_view_threading_violation_coroutine_kotlin] + lifecycleOwner.lifecycleScope.launch(Dispatchers.IO) { + val data = myRepository.getData() + withContext(Dispatchers.Main) { // Switch context to Main + myTextView.text = data.title + } + } + // [END android_view_threading_violation_coroutine_kotlin] + } + + @RequiresApi(37) + fun checkViewThreadingViolation() { + // [START android_view_threading_violation_listener_kotlin] + val wrongThreadListener = View.CalledFromWrongThreadListener { + // Handle the issue, e.g. crash if this is a dev build, or log an event + // Unregister the listener to avoid redundant notifications for the same issue + } + View.registerCalledFromWrongThreadListener(wrongThreadListener) + // [END android_view_threading_violation_listener_kotlin] + } +} \ No newline at end of file From b14acd13214182ca3bbfbd7374fff35838bb1b75 Mon Sep 17 00:00:00 2001 From: huewu Date: Tue, 21 Jul 2026 15:12:49 +0900 Subject: [PATCH 2/4] Add UI threading violation and context switching snippets * Create ViewThreadingViolationSnippet.kt * Add snippet for switching to Dispatchers.Main in coroutines * Add snippet for View.registerCalledFromWrongThreadListener (API 37) # Conflicts: # misc/src/main/java/com/example/snippets/anr/ViewThreadingViolationSnippet.kt --- .../snippets/anr/ViewThreadingViolationSnippet.kt | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/misc/src/main/java/com/example/snippets/anr/ViewThreadingViolationSnippet.kt b/misc/src/main/java/com/example/snippets/anr/ViewThreadingViolationSnippet.kt index 8818711da..86f52ca6e 100644 --- a/misc/src/main/java/com/example/snippets/anr/ViewThreadingViolationSnippet.kt +++ b/misc/src/main/java/com/example/snippets/anr/ViewThreadingViolationSnippet.kt @@ -39,11 +39,15 @@ object ViewThreadingViolationSnippet { @RequiresApi(37) fun checkViewThreadingViolation() { // [START android_view_threading_violation_listener_kotlin] - val wrongThreadListener = View.CalledFromWrongThreadListener { - // Handle the issue, e.g. crash if this is a dev build, or log an event - // Unregister the listener to avoid redundant notifications for the same issue + val listener = object : View.CalledFromWrongThreadListener { + override fun onCalledFromWrongThread() { + // Handle the issue, e.g. crash if this is a dev build, or log an event + // e.g. Log.d(TAG, "CalledFromWrongThread: ${Exception().stackTraceToString()}") + // Unregister the listener to avoid redundant notifications for the same issue + View.unregisterCalledFromWrongThreadListener(this) + } } - View.registerCalledFromWrongThreadListener(wrongThreadListener) + View.registerCalledFromWrongThreadListener(listener) // [END android_view_threading_violation_listener_kotlin] } } \ No newline at end of file From 5183cb8989f3cdbb8579af9e0a333addf31bc569 Mon Sep 17 00:00:00 2001 From: huewu <1445837+huewu@users.noreply.github.com> Date: Tue, 21 Jul 2026 06:24:51 +0000 Subject: [PATCH 3/4] Apply Spotless --- .../anr/ViewThreadingViolationSnippet.kt | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/misc/src/main/java/com/example/snippets/anr/ViewThreadingViolationSnippet.kt b/misc/src/main/java/com/example/snippets/anr/ViewThreadingViolationSnippet.kt index 86f52ca6e..e16127945 100644 --- a/misc/src/main/java/com/example/snippets/anr/ViewThreadingViolationSnippet.kt +++ b/misc/src/main/java/com/example/snippets/anr/ViewThreadingViolationSnippet.kt @@ -1,3 +1,19 @@ +/* + * Copyright 2026 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package com.example.snippets.anr import android.view.View @@ -50,4 +66,4 @@ object ViewThreadingViolationSnippet { View.registerCalledFromWrongThreadListener(listener) // [END android_view_threading_violation_listener_kotlin] } -} \ No newline at end of file +} From 0583469d2bbd06cd6aaebaa19c397f464ba86e37 Mon Sep 17 00:00:00 2001 From: Chansuk Yang Date: Tue, 21 Jul 2026 15:25:30 +0900 Subject: [PATCH 4/4] Update misc/src/main/java/com/example/snippets/anr/ViewThreadingViolationSnippet.kt Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> --- .../com/example/snippets/anr/ViewThreadingViolationSnippet.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/misc/src/main/java/com/example/snippets/anr/ViewThreadingViolationSnippet.kt b/misc/src/main/java/com/example/snippets/anr/ViewThreadingViolationSnippet.kt index e16127945..6296b5a4c 100644 --- a/misc/src/main/java/com/example/snippets/anr/ViewThreadingViolationSnippet.kt +++ b/misc/src/main/java/com/example/snippets/anr/ViewThreadingViolationSnippet.kt @@ -34,7 +34,7 @@ interface MyRepository { suspend fun getData(): MyData } -@SuppressWarnings("unused") +@Suppress("unused") object ViewThreadingViolationSnippet { fun switchContext(