kotlin - RxJava在处理后一直在发射项目,如何正确处理?
问题描述
我试图在 ViewModel 中处理 RxJava 一次性。我很确定在 ViewModel 的 onClear 方法中清除一次性用品是一种很好的做法,因此它不会泄漏 ViewModel 本身。但是,当出现 UnknownHostException 时,就在 dispose 操作发生之前,它会导致 ViewModel 泄漏。我打开了泄漏金丝雀,我说与 onError 相关的东西已经泄漏了。
我发现 UnknownHostException 实际上是在 RxJava 的全局错误处理程序下捕获的,所以为什么这个异常一直引用 onError 回调并导致泄漏,即使我处理了一次性。
用例.kt
abstract class UseCase {
protected var lastDisposable: Disposable? = null
private val compositeDisposable: CompositeDisposable = CompositeDisposable()
fun disposeLast() {
lastDisposable?.let {
if (!it.isDisposed) {
it.dispose()
}
}
}
fun dispose() {
compositeDisposable.clear()
}
fun Disposable.addDisposable() {
compositeDisposable.add(this)
}
class None()
}
FlowableUseCase.kt
abstract class FlowableUseCase<in Params, Model> @Inject constructor(private val flowableRxTransformer: FlowableRxTransformer<Model>) :
UseCase() {
internal abstract fun buildUseCaseFlowable(params: Params): Flowable<Model>
operator fun invoke(
params: Params,
onLoading: () -> Unit = {},
onError: ((error: Throwable) -> Unit) = {},
onSuccess: ((entity: Model) -> Unit) = {},
onFinished: () -> Unit = {}
) {
onLoading()
disposeLast()
lastDisposable = buildUseCaseFlowable(params)
.compose(flowableRxTransformer)
.doAfterTerminate(onFinished)
.subscribe(onSuccess, onError) // leaks happened here
lastDisposable?.addDisposable()
}
}
如果我尝试删除 onError 回调,则不再有错误。所以我很确定它会导致内存泄漏,但这个操作可能会导致 OnErrorNotImplementedException,所以我不想这样做。
任何形式的建议都是可以接受的。提前致谢。
泄漏金丝雀头部转储
┬───
│ GC Root: System class
│
├─ android.provider.FontsContract class
│ Leaking: NO (App↓ is not leaking and a class is never leaking)
│ ↓ static FontsContract.sContext
├─ com.potatocandie.cleanprayertime.App instance
│ Leaking: NO (Application is a singleton)
│ mBase instance of android.app.ContextImpl, not wrapping known Android
│ context
│ ↓ App.componentManager
│ ~~~~~~~~~~~~~~~~
├─ dagger.hilt.android.internal.managers.ApplicationComponentManager instance
│ Leaking: UNKNOWN
│ Retaining 40 bytes in 3 objects
│ ↓ ApplicationComponentManager.component
│ ~~~~~~~~~
├─ com.potatocandie.cleanprayertime.DaggerApp_HiltComponents_SingletonC instance
│ Leaking: UNKNOWN
│ Retaining 7731 bytes in 279 objects
│ ↓ DaggerApp_HiltComponents_SingletonC.okHttpClientBuilder
│ ~~~~~~~~~~~~~~~~~~~
├─ okhttp3.OkHttpClient$Builder instance
│ Leaking: UNKNOWN
│ Retaining 203 bytes in 4 objects
│ ↓ OkHttpClient$Builder.dispatcher
│ ~~~~~~~~~~
├─ okhttp3.Dispatcher instance
│ Leaking: UNKNOWN
│ Retaining 288 bytes in 7 objects
│ ↓ Dispatcher.runningAsyncCalls
│ ~~~~~~~~~~~~~~~~~
├─ java.util.ArrayDeque instance
│ Leaking: UNKNOWN
│ Retaining 84 bytes in 2 objects
│ ↓ ArrayDeque.elements
│ ~~~~~~~~
├─ java.lang.Object[] array
│ Leaking: UNKNOWN
│ Retaining 64 bytes in 1 objects
│ ↓ Object[].[0]
│ ~~~
├─ okhttp3.internal.connection.RealCall$AsyncCall instance
│ Leaking: UNKNOWN
│ Retaining 3815 bytes in 123 objects
│ ↓ RealCall$AsyncCall.responseCallback
│ ~~~~~~~~~~~~~~~~
├─ retrofit2.OkHttpCall$1 instance
│ Leaking: UNKNOWN
│ Retaining 3795 bytes in 122 objects
│ Anonymous class implementing okhttp3.Callback
│ ↓ OkHttpCall$1.val$callback
│ ~~~~~~~~~~~~
├─ retrofit2.adapter.rxjava3.CallEnqueueObservable$CallCallback instance
│ Leaking: UNKNOWN
│ Retaining 3705 bytes in 119 objects
│ ↓ CallEnqueueObservable$CallCallback.observer
│ ~~~~~~~~
├─ retrofit2.adapter.rxjava3.BodyObservable$BodyObserver instance
│ Leaking: UNKNOWN
│ Retaining 3687 bytes in 118 objects
│ ↓ BodyObservable$BodyObserver.observer
│ ~~~~~~~~
├─ io.reactivex.rxjava3.internal.operators.flowable.
│ FlowableFromObservable$SubscriberObserver instance
│ Leaking: UNKNOWN
│ Retaining 3674 bytes in 117 objects
│ ↓ FlowableFromObservable$SubscriberObserver.downstream
│ ~~~~~~~~~~
├─ io.reactivex.rxjava3.internal.operators.flowable.
│ FlowableOnBackpressureLatest$BackpressureLatestSubscriber instance
│ Leaking: UNKNOWN
│ Retaining 3658 bytes in 116 objects
│ ↓ FlowableOnBackpressureLatest$BackpressureLatestSubscriber.downstream
│ ~~~~~~~~~~
├─ io.reactivex.rxjava3.internal.operators.flowable.FlowableMap$MapSubscriber
│ instance
│ Leaking: UNKNOWN
│ Retaining 3596 bytes in 113 objects
│ ↓ FlowableMap$MapSubscriber.downstream
│ ~~~~~~~~~~
├─ io.reactivex.rxjava3.internal.operators.flowable.
│ FlowableDoOnEach$DoOnEachSubscriber instance
│ Leaking: UNKNOWN
│ Retaining 3564 bytes in 112 objects
│ ↓ FlowableDoOnEach$DoOnEachSubscriber.downstream
│ ~~~~~~~~~~
├─ io.reactivex.rxjava3.internal.operators.flowable.
│ FlowableRetryWhen$RetryWhenSubscriber instance
│ Leaking: UNKNOWN
│ Retaining 3400 bytes in 105 objects
│ ↓ FlowableRetryWhen$RetryWhenSubscriber.downstream
│ ~~~~~~~~~~
├─ io.reactivex.rxjava3.subscribers.SerializedSubscriber instance
│ Leaking: UNKNOWN
│ Retaining 2860 bytes in 79 objects
│ ↓ SerializedSubscriber.downstream
│ ~~~~~~~~~~
├─ io.reactivex.rxjava3.internal.operators.flowable.
│ FlowableDoOnEach$DoOnEachSubscriber instance
│ Leaking: UNKNOWN
│ Retaining 2837 bytes in 78 objects
│ ↓ FlowableDoOnEach$DoOnEachSubscriber.downstream
│ ~~~~~~~~~~
├─ io.reactivex.rxjava3.internal.operators.flowable.
│ FlowableFlatMap$InnerSubscriber instance
│ Leaking: UNKNOWN
│ Retaining 2781 bytes in 76 objects
│ ↓ FlowableFlatMap$InnerSubscriber.parent
│ ~~~~~~
├─ io.reactivex.rxjava3.internal.operators.flowable.
│ FlowableFlatMap$MergeSubscriber instance
│ Leaking: UNKNOWN
│ Retaining 2732 bytes in 75 objects
│ ↓ FlowableFlatMap$MergeSubscriber.downstream
│ ~~~~~~~~~~
├─ io.reactivex.rxjava3.internal.operators.flowable.FlowableMap$MapSubscriber
│ instance
│ Leaking: UNKNOWN
│ Retaining 1837 bytes in 58 objects
│ ↓ FlowableMap$MapSubscriber.downstream
│ ~~~~~~~~~~
├─ io.reactivex.rxjava3.internal.operators.flowable.
│ FlowableDoOnEach$DoOnEachSubscriber instance
│ Leaking: UNKNOWN
│ Retaining 1793 bytes in 56 objects
│ ↓ FlowableDoOnEach$DoOnEachSubscriber.onNext
│ ~~~~~~
├─ com.potatocandie.domain.base.FlowableUseCase$invoke$5 instance
│ Leaking: UNKNOWN
│ Retaining 12 bytes in 1 objects
│ Anonymous class implementing io.reactivex.rxjava3.functions.Consumer
│ ↓ FlowableUseCase$invoke$5.this$0
│ ~~~~~~
├─ com.potatocandie.domain.usecases.GetCurrentMonthsPrayerTimesUseCase instance
│ Leaking: UNKNOWN
│ Retaining 45 bytes in 3 objects
│ ↓ GetCurrentMonthsPrayerTimesUseCase.lastDisposable
│ ~~~~~~~~~~~~~~
├─ io.reactivex.rxjava3.internal.subscribers.LambdaSubscriber instance
│ Leaking: UNKNOWN
│ Retaining 800 bytes in 34 objects
│ ↓ LambdaSubscriber.onError
│ ~~~~~~~
├─ com.potatocandie.domain.base.
│ FlowableUseCase$sam$io_reactivex_rxjava3_functions_Consumer$0 instance
│ Leaking: UNKNOWN
│ Retaining 760 bytes in 32 objects
│ Anonymous class implementing io.reactivex.rxjava3.functions.Consumer
│ ↓ FlowableUseCase$sam$io_reactivex_rxjava3_functions_Consumer$0.function
│ ~~~~~~~~
├─ com.potatocandie.cleanprayertime.features.today.
│ PrayerTimesViewModel$getCurrentMonthsPrayerTimes$2 instance
│ Leaking: UNKNOWN
│ Retaining 748 bytes in 31 objects
│ Anonymous subclass of kotlin.jvm.internal.Lambda
│ ↓ PrayerTimesViewModel$getCurrentMonthsPrayerTimes$2.this$0
│ ~~~~~~
╰→ com.potatocandie.cleanprayertime.features.today.PrayerTimesViewModel instance
Leaking: YES (ObjectWatcher was watching this because com.potatocandie.
cleanprayertime.features.today.PrayerTimesViewModel received
ViewModel#onCleared() callback)
Retaining 732 bytes in 30 objects
key = 1a238931-2884-4446-a5c2-66d46390134f
watchDurationMillis = 7824
retainedDurationMillis = 2822
解决方案
推荐阅读
- c - 一个非常简单的进程的内存结构细节是什么,崩溃的细节是什么
- npm - 如何防止节点向控制台发送错误?
- python - 如何按字母+数字顺序按列对表格可视化进行排序?
- python - Discord.py help 如何检测消息是否由特定用户ID发送
- php - 按库存数量显示
- amazon-web-services - Aws S3 或使用 CDN 的服务器存储
- react-native - 使用“无法从不同组件的函数体内更新组件”的身份验证堆栈导航
- reactjs - 如何阻止第三方 Javascript 加载到清理功能中?
- java - Google Invisible reCaptcha 徽章:如何获取 reCaptcha-token
- kubernetes - 如何配置 Kubernetes,使失败的 pod 不回复 ICMP echo-requests?