ReactiveNetwork
ReactiveNetwork copied to clipboard
ConnectivityManager error messages when clearing subscriptions
We're using reactivenetwork-rx2:2.1.0
When switching activities we're seeing some ConnectivityManager related error messages. They don't seem to be causing any actual issues, but would be nice if they were cleared up.
Error messages seem to vary depending on device
eg
D/CCA: onPause
D/ConnectivityManager: unregisterNetworkCallback; CallingUid : 10242, CallingPid : 15126
OR
D/CCA: onPause
E/ConnectivityManager.CallbackHandler: callback not found for RELEASED message
Code sample
@Override
public void onResume() {
Log.d(TAG, "onResume");
super.onResume();
disposables.add(ReactiveNetwork.observeNetworkConnectivity(this)
.filter(ConnectivityPredicate.hasType(ConnectivityManager.TYPE_WIFI))
.subscribeOn(Schedulers.io())
.observeOn(io.reactivex.android.schedulers.AndroidSchedulers.mainThread())
.subscribe((Connectivity it) -> {
Log.d(TAG, "observeNetworkConnectivity - state=" + it.state());
if (it.state() == NetworkInfo.State.CONNECTED) {
startReconnectUnitActivity();
} else {
promptText.setVisibility(View.VISIBLE);
}
}, throwable -> Log.crashLog(TAG, "** onError (observeNetworkConnectivity) **")));
}
@Override
public void onPause() {
Log.d(TAG, "onPause");
super.onPause();
disposables.clear();
}
Hi,
Thanks for reporting this issue.
In the library, I explicitly unregister callback while calling dispose()
method. You can take a look at this line: https://github.com/pwittchen/ReactiveNetwork/blob/RxJava2.x/library/src/main/java/com/github/pwittchen/reactivenetwork/library/rx2/network/observing/strategy/LollipopNetworkObservingStrategy.java#L61.
Is there any particular reason because of which you are using clear()
instead of dispose()
. I think calling dispose()
should solve this problem, but I'll ensure if it's possible to handle clear()
method as well and verify if it makes sense within the library code.
We found issues using disposables.dispose() in onPause() - it means you can then not add more subscriptions via disposables.add in eg onResume(). So our pattern is always to use disposables.clear() in onPause()
Thanks for your quick response by the way.
All working great apart from this one issue.
Ok, I'll check what I can do with use case with clear()
method.
Another idea could be moving your code to the place independent from the Activity Lifecycle. E.g. to instance of the Application or dedicated Android Service. You can monitor network in one place and pass events to the Activity when needed. You can use many techniques for passing events between independent components (e.g. via event bus).
When you use the ReactiveNetwork.observeNetworkConnectivity(context)
if you ever call dispose of that observable it sends an onCancel signal to the origin. The origin unregisters the idleReceiver : BroadcastReceiver
from the context provided. If you call have more than one subscribers to that origin the second dispose tries to send a cancel signal as well. The reference tries to unregister the same idleReceiver
again from the context causing the error. I don't think this is unreasonable way to implement the library. The origin has to know to clean it self up from the context passed to it. So, you should consider protecting yourself from more than one subscriber by wrapping the library and observable provided with your own class that will never send the originator a cancel until App destruction. e.g.
interface NetworkStatusInterface {
val networkStatusObservable: Observable<NetworkState>
}
class NetworkStatusRepos(connectivityObservable: Observable<Connectivity> = ReactiveNetwork.observeNetworkConnectivity(YourApplicationContext),
scheduler: Scheduler = Schedulers.computation()) : NetworkStatusInterface {
private var disposable: Disposable
private val networkStatusSubject = BehaviorSubject.create<NetworkState>()
override val networkStatusObservable: Observable<NetworkState> = networkStatusSubject
init {
disposable = connectivityObservable
.map { connectivity: Connectivity ->
when (connectivity.state()) {
NetworkInfo.State.CONNECTED -> Connected
NetworkInfo.State.CONNECTING -> Connecting
else -> NoInternet
}
}
.subscribeOn(scheduler)
.subscribe({ networkStatusSubject.onNext(it) }, {
Log.e("@@", "NetworkStatusRepos.connectivityObservable: something has gone horribly wrong and you need to resubscribe.")
})
}
}
sealed class NetworkState
object Connected : NetworkState()
object Connecting : NetworkState()
object NoInternet : NetworkState()