I have essentially the memory leak described here as detected by LeakCanary.
I am trying to solve this by using the "Plumber's Fix" in the above post which flushes the message queue with an empty message. The provided code sample flush message queue every time it becomes idle. I only need to flush the queue once, after my dialog gets dismissed:
public class ExampleDialogFragment extends AppCompatDialogFragment {
public static ExampleDialogFragment newInstance() {
return new ExampleDialogFragment();
}
@NonNull
@Override
public Dialog onCreateDialog(final Bundle savedInstanceState) {
return new AlertDialog.Builder(getContext())
.setPositiveButton(android.R.string.ok, (dialog, which) -> onClicked())
.create();
}
private void onClicked() {
if (getTargetFragment() instanceof Callbacks) {
((Callbacks) getTargetFragment()).onButtonClicked();
flushStackLocalLeaks();
}
}
private static void flushStackLocalLeaks() {
final Handler handler = new Handler(Looper.myLooper());
handler.post(() -> Looper.myQueue().addIdleHandler(() -> {
Timber.d("Flushing on thread %s", Thread.currentThread().getName());
handler.sendMessageDelayed(handler.obtainMessage(), 1000);
return false; // we only want to flush once, not *every* 1000 mSec
}));
}
public interface Callbacks {
void onButtonClicked();
}
}
The problem I'm facing is that in the LeakCanary report, the HandlerThread at the root of the leak is never the thread I expect. Sometimes it's a ConnectivityThread
, sometimes it's a HandlerThread
, where mName = "queued-work-looper"
, other it's a HandlerThread
used by my analytics library. In none of these cases is it the main thread. I would expect the message to be leaking from the main thread. So
- why is this leak happening on a HandlerThread/ConnectivityThread other than the main thread?
- how do I know which HandlerThread needs flushing?