Leak resulting from RxBleClient.scanBleDevices()
See original GitHub issueI’ve been pulling my hair out trying to debug a leak in my app when using RxBleClient.scanBleDevices()
. My subscribe onNext lambda holds a reference to the Activity, however I am unsubscribing when the Activity is destroyed, so I shouldn’t be leaking. The leak’s GC root is a thread, which references com.polidea.rxandroidble.internal.radio.FIFORunnableEntry.emitter
.
Maybe I’m just missing something here? In that case, any insight is greatly appreciated.
I’ve created an example that demonstrates the issue:
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import com.google.common.base.Strings;
import com.polidea.rxandroidble.RxBleClient;
import com.polidea.rxandroidble.scan.ScanSettings;
import com.example.R;
import com.example.MyApplication;
import rx.Observable;
import rx.Subscription;
import timber.log.Timber;
public class DebugLeakActivity extends AppCompatActivity {
RxBleClient bleClient;
Subscription subscription = null;
String someActivityField;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_debug_leak);
// in my app, RxBleClient is provided by dependency injection and has the lifetime of the app.
// simulating here.
bleClient = ((MyApplication)getApplication()).bleClient;
}
@Override
protected void onStart() {
super.onStart();
subscription = scan()
.subscribe(
// reference a field in the activity to create a reference to the Activity from the lambda
deviceString -> someActivityField = deviceString,
throwable -> Timber.e(throwable));
}
@Override
protected void onDestroy() {
if (subscription != null) {
subscription.unsubscribe();
subscription = null;
}
super.onDestroy();
}
public Observable<String> scan() {
ScanSettings scanSettings = new ScanSettings.Builder()
.setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY)
.build();
return bleClient.scanBleDevices(scanSettings)
.doOnUnsubscribe(() -> Timber.d("scanBleDevices() unsubscribed"))
.distinct()
.doOnNext(scanResult -> Timber.d(String.format("Found BLE device: %s, %s", scanResult.getBleDevice().getMacAddress(), Strings.nullToEmpty(scanResult.getBleDevice().getName()))))
.map(rxBleScanResult -> rxBleScanResult.toString());
}
}
Here is the reference chain from LeakCanary:
In com.example:0.20.0-SNAPSHOT:200000.
* com.example.presentation.DebugLeakActivity has leaked:
* GC ROOT thread java.lang.Thread.<Java Local> (named 'Thread-8')
* references com.polidea.rxandroidble.internal.radio.FIFORunnableEntry.emitter
* references rx.internal.operators.OnSubscribeCreate$NoneEmitter.actual
* references rx.internal.operators.OperatorUnsubscribeOn$1.val$subscriber (anonymous subclass of rx.Subscriber)
* references rx.internal.operators.OnSubscribeMap$MapSubscriber.actual
* references rx.internal.operators.OperatorMerge$InnerSubscriber.parent
* references rx.internal.operators.OperatorMerge$MergeSubscriber.child
* references rx.observers.Subscribers$5.val$subscriber (anonymous subclass of rx.Subscriber)
* references rx.observers.Subscribers$5.val$subscriber (anonymous subclass of rx.Subscriber)
* references rx.observers.Subscribers$5.val$subscriber (anonymous subclass of rx.Subscriber)
* references rx.internal.operators.OperatorDistinct$1.val$child (anonymous subclass of rx.Subscriber)
* references rx.internal.operators.OnSubscribeDoOnEach$DoOnEachSubscriber.subscriber
* references rx.internal.operators.OnSubscribeMap$MapSubscriber.actual
* references rx.observers.SafeSubscriber.actual
* references rx.internal.util.ActionSubscriber.onNext
* references com.example.presentation.DebugLeakActivity$$Lambda$1.arg$1 (anonymous implementation of rx.functions.Action1)
* leaks com.example.presentation.DebugLeakActivity instance
I’ve attached the full LeakCanary details for more information: In 2.txt
Issue Analytics
- State:
- Created 6 years ago
- Comments:6 (4 by maintainers)
Top Results From Across the Web
Leak resulting from RxBleClient.scanBleDevices() #288 - GitHub
I've been pulling my hair out trying to debug a leak in my app when using RxBleClient.scanBleDevices() . My subscribe onNext lambda holds...
Read more >android - RxAndroidBle with java 7 - Stack Overflow
I am trying to use RxAndroidBle to scan for devices. All the examples I found seem to use java lambda expression. Do I...
Read more >Bachelorarbeit
In chapter 5, we talk about the results we have achieved during our thesis: ... They are used in gas leakage detecting equipment...
Read more >RxAndroidBLE — your most powerful tool for Bluetooth Low ...
Your entry point to the library is the RxBleClient class. ... scanBleDevices() .subscribe(rxBleScanResult -> { // Process scan result here. }); ...
Read more >bd3242b7cac19704fa66d226f13...
01-20 18:07:18.002 6621 7096 D BluetoothGatt: readRssi() - device: ... lowi_close_record:Scan done in 25297295ms, 11 APs in scan results 01-20 18:07:18.085 ...
Read more >Top Related Medium Post
No results found
Top Related StackOverflow Question
No results found
Troubleshoot Live Code
Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start FreeTop Related Reddit Thread
No results found
Top Related Hackernoon Post
No results found
Top Related Tweet
No results found
Top Related Dev.to Post
No results found
Top Related Hashnode Post
No results found
Top GitHub Comments
Looking at this code snippet:
The
onStart
can be called multiple times before theonDestroy
is finally called.Instead of unsubscribing in the
onDestroy
, override theonStop
instead and unsubscribe there.I think that @streetsofboston comment may pinpoint the cause of the observed leak. Closing for now. If new information will be available—feel free to reopen.