【问题标题】:RxJava: getting "Only the original thread that created a view hierarchy can touch its views" even after subscribing on main threadRxJava:即使在主线程上订阅后,“只有创建视图层次结构的原始线程才能触摸其视图”
【发布时间】:2019-09-27 06:47:56
【问题描述】:

我在自动完成文本视图上使用扩展功能来使用去抖动策略并在主线程上订阅。

 binding.autoCompleteTextView2.addRxTextWatcher()
         .observeOn(AndroidSchedulers.mainThread())
         .subscribeOn(AndroidSchedulers.mainThread())
         .debounce(400, TimeUnit.MILLISECONDS)
         .subscribe {
            if (!TextUtils.isEmpty(it)) {
                        viewModel.searchTeacher(viewModel.meditationDetails?.schoolId,it)
                        binding?.etEmailOfTeacher?.visible()   //Crash at this point
                        binding?.tvEmailOfYourTeacher?.visible()
                }
       }

扩展功能:-

fun EditText.addRxTextWatcher(): Observable<String?> {
val flowable = Observable.create<String?> {
    addTextChangedListener(object : TextWatcher {
        override fun afterTextChanged(s: Editable?) {
        }

        override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
            it.onNext(s?.toString())
        }

        override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
        }
    })
}

当我尝试更新“只有创建视图层次结构的原始线程可以触及其视图”的视图可见性时,我遇到了崩溃。但我已经订阅并观察了 mainThread 。我在这里做错了什么?

完整的日志:

2019-09-27 11:51:06.878 9490-9575/com.example.example E/ACRA: ACRA caught a CalledFromWrongThreadException for com.example.example
    android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
        at android.view.ViewRootImpl.checkThread(ViewRootImpl.java:7959)
        at android.view.ViewRootImpl.focusableViewAvailable(ViewRootImpl.java:3866)
        at android.view.ViewGroup.focusableViewAvailable(ViewGroup.java:917)
        at android.view.ViewGroup.focusableViewAvailable(ViewGroup.java:917)
        at android.view.ViewGroup.focusableViewAvailable(ViewGroup.java:917)
        at android.view.ViewGroup.focusableViewAvailable(ViewGroup.java:917)
        at android.view.ViewGroup.focusableViewAvailable(ViewGroup.java:917)
        at android.view.ViewGroup.focusableViewAvailable(ViewGroup.java:917)
        at android.view.ViewGroup.focusableViewAvailable(ViewGroup.java:917)
        at android.view.ViewGroup.focusableViewAvailable(ViewGroup.java:917)
        at android.view.ViewGroup.focusableViewAvailable(ViewGroup.java:917)
        at android.view.ViewGroup.focusableViewAvailable(ViewGroup.java:917)
        at android.view.View.setFlags(View.java:14121)
        at android.view.View.setVisibility(View.java:10007)
        at in.eightfolds.utils.ExtentionFunctionsKt.visible(ExtentionFunctions.kt:345)
        at com.example.example.fragment.OnBordingCreateMeditationAdditionalDetailsFragment$setAutoCompleteTextView2$2.accept(OnBordingCreateMeditationAdditionalDetailsFragment.kt:283)
        at com.example.example.fragment.OnBordingCreateMeditationAdditionalDetailsFragment$setAutoCompleteTextView2$2.accept(OnBordingCreateMeditationAdditionalDetailsFragment.kt:38)
        at io.reactivex.internal.observers.LambdaObserver.onNext(LambdaObserver.java:59)
        at io.reactivex.observers.SerializedObserver.onNext(SerializedObserver.java:111)
        at io.reactivex.internal.operators.observable.ObservableDebounceTimed$DebounceTimedObserver.emit(ObservableDebounceTimed.java:142)
        at io.reactivex.internal.operators.observable.ObservableDebounceTimed$DebounceEmitter.run(ObservableDebounceTimed.java:167)
        at io.reactivex.internal.schedulers.ScheduledRunnable.run(ScheduledRunnable.java:59)
        at io.reactivex.internal.schedulers.ScheduledRunnable.call(ScheduledRunnable.java:51)
        at java.util.concurrent.FutureTask.run(FutureTask.java:266)
        at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:301)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
        at java.lang.Thread.run(Thread.java:764)

如果我在 activity?.runOnUiThread { } 中写下可见性,那么它工作正常。那么为什么即使我订阅了 mainthread 也会出现异常?

【问题讨论】:

  • 扩展功能的代码好像不完整,请补充完整代码

标签: android rx-java2


【解决方案1】:

debounce 运算符将订阅计算调度程序。像这样重新排序你的函数:

binding.autoCompleteTextView2.addRxTextWatcher() <-- text watch is on the main thread
         .debounce(400, TimeUnit.MILLISECONDS) <-- debounced throw the result on Computation Scheduler
         .observeOn(AndroidSchedulers.mainThread()) <-- ObserveOn throw the result on MainThread
         .subscribe {
            if (!TextUtils.isEmpty(it)) {
                        viewModel.searchTeacher(viewModel.meditationDetails?.schoolId,it)
                        binding?.etEmailOfTeacher?.visible()   //Crash at this point
                        binding?.tvEmailOfYourTeacher?.visible()
                }
       }

参考:RxJava Debounce doc

debounce(long, TimeUnit) 默认在计算调度器上

奖励:您可以在每次操作后使用运算符doOnNext 并记录使用Thread.currentThread().getName() 的线程

例如:

...
.debounce(...)
.doOnNext{ Log.d(TAG, "Debounce on: " +  Thread.currentThread().getName()) } <-- This will show RxComputationScheduler-N
.observeOn(AndroidSchedulers.mainThread())
.doOnNext{ Log.d(TAG, "Debounce on: " +  Thread.currentThread().getName()) } <-- This will show main
...

【讨论】:

  • 看起来您只是重新排序了 subscribeOn 运算符,这不会有任何区别。根据docsAs shown in this illustration, the SubscribeOn operator designates which thread the Observable will begin operating on, no matter at what point in the chain of operators that operator is called. ObserveOn, on the other hand, affects the thread that the Observable will use below where that operator appears.
  • @Gustavo 真丢人 ^^
【解决方案2】:

@xiaomi 关于debounce 默认在计算调度程序上运行是正确的,但为了解决您的问题,您必须在debounce 之后使用observeOn 运算符切换回主线程:

binding.autoCompleteTextView2.addRxTextWatcher()
         .debounce(400, TimeUnit.MILLISECONDS) // debounce will operate on computation scheduler
         .observeOn(AndroidSchedulers.mainThread()) // change all the operators below to operate on main thread
         .subscribe {
                    // code here will be executed on main thread
                }
       }

来自docs

ObserveOn,影响 Observable 将在该运算符出现的下方使用的线程。

【讨论】:

    猜你喜欢
    • 2016-01-17
    • 1970-01-01
    • 2015-05-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多