Comments (54)
I've had good luck setting the actual listener that is leaking (such as the Activity) in a WeakReference and just forwarding the callback from a wrapper class:
public class WeakLocationListener implements LocationListener {
private final WeakReference<LocationListener> locationListenerRef;
public WeakLocationListener(@NonNull LocationListener locationListener) {
locationListenerRef = new WeakReference<>(locationListener);
}
@Override
public void onLocationChanged(android.location.Location location) {
if (locationListenerRef.get() == null) {
return;
}
locationListenerRef.get().onLocationChanged(location);
}
}
That way the instance of the wrapper class might leak, but the Activity does not.
from location-samples.
With 'com.google.android.gms:play-services:11.0.1'
I also get the problem about LocationCallback. But it can be fixed by WeakReference.
my old code:
LocationCallback mLocationCallback = new LocationCallback() {
@Override
public void onLocationResult(LocationResult locationResult) {
super.onLocationResult(locationResult);
// updateLocation();
}
};
use mLocationCallback:
mFusedLocationClient.requestLocationUpdates(mLocationRequest,
mLocationCallback, Looper.myLooper());
my fix code:
private static class LocationCallbackReference extends LocationCallback {
private WeakReference<LocationCallback> locationCallbackRef;
LocationCallbackReference(LocationCallback locationCallback) {
locationCallbackRef = new WeakReference<LocationCallback>(locationCallback);
}
@Override
public void onLocationResult(LocationResult locationResult) {
super.onLocationResult(locationResult);
if (locationCallbackRef != null && locationCallbackRef.get() != null) {
locationCallbackRef.get().onLocationResult(locationResult);
}
}
}
LocationCallback locationCallback = new LocationCallback() {
@Override
public void onLocationResult(LocationResult locationResult) {
super.onLocationResult(locationResult);
updateLocation();
}
};
mLocationCallback = new LocationCallbackReference(locationCallback);
mFusedLocationClient.requestLocationUpdates(mLocationRequest,
mLocationCallback, Looper.myLooper());
I just wrap the LocationCallback with WeakReference. The 'mFusedLocationClient' is constructed in this way:
mFusedLocationClient = LocationServices.getFusedLocationProviderClient(activity);
rather than "LocationServices.FusedLocationApi".
from location-samples.
In our case, unregister following callbacks would resolve the issue:
googleApiClient.unregisterConnectionCallbacks(this);
googleApiClient.unregisterConnectionFailedListener(this);
this
is the fragment that implements the callbacks.
Also, remove the callback of location request if any:
LocationServices.FusedLocationApi.removeLocationUpdates(googleApiClient, this);
googleApiClient.disconnect();
from location-samples.
@sealskej Using new GoogleApiClient.Builder(getApplicationContext())
still leaks.
@carlosjs23 Using the following still leaks:
mGoogleApiClient = new GoogleApiClient.Builder(this)
.enableAutoManage(this, this)
.addConnectionCallbacks(this)
.addApi(LocationServices.API)
.build();
from location-samples.
In v9.8.0 it is still leaking. Please can someone tell the Google Play Services team about the weak references usage? Maybe this way they will fix this issue much faster.
from location-samples.
@thuytrinh As a workaround I moved the location listener inside a service which will broadcast the location once it is obtained, using an event bus. It still leaks the service but it is better than having the activity leaked with multiple views inside.
Would really appreciate an update on this as this issue was reported more than three months ago!
from location-samples.
Passing application context to GoogleApiClient.Builder
should solve the leak.
mGoogleApiClient = new GoogleApiClient.Builder(getContext().getApplicationContext())
from location-samples.
Confirmed fixed in 20.0.0. Good news, but did this really have to take 7 years and 12 major releases?
from location-samples.
Hello all
I followed yourfacepalm advice and did a workaround this morning:
package com.myapp.service;
import android.Manifest;
import android.app.IntentService;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.location.Location;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.LocalBroadcastManager;
import com.myapp.Constants.Constants;
import com.myapp.Utils.LocationUtil;
import com.myapp.activities.R;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.location.LocationListener;
import com.google.android.gms.location.LocationRequest;
import com.google.android.gms.location.LocationServices;
import com.google.android.gms.location.places.Places;
import timber.log.Timber;
public class LocationIntentService extends IntentService implements
GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener,
LocationListener {
GoogleApiClient mGoogleApiClient;
public LocationIntentService(String name) {
super(name);
}
public LocationIntentService() {
super(LocationIntentService.class.getName());
}
@Override
protected void onHandleIntent(Intent workIntent) {
mGoogleApiClient = new GoogleApiClient.Builder(getApplicationContext())
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.addApi(Places.GEO_DATA_API)
.addApi(Places.PLACE_DETECTION_API)
.build();
mGoogleApiClient.connect();
Timber.e("locationintentservice start");
}
@Override
public void onLocationChanged(Location location) {
Timber.e("location changed");
if (location != null) {
Timber.e("location received");
SharedPreferences sharedPreferences = getSharedPreferences(getString(R.string.user_shared_preferences), Context.MODE_PRIVATE);
LocationUtil.storeLocation(sharedPreferences, location);
Timber.e(String.valueOf(location.getLatitude()) + " Longitude: " +
String.valueOf(location.getLongitude()));
} else {
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
!= PackageManager.PERMISSION_GRANTED &&
ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION)
!= PackageManager.PERMISSION_GRANTED) {
Intent intent = new Intent(Constants.COMMENT_LOC_RESULTS);
LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(intent);
} else {
Location lastLocation = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
SharedPreferences sharedPreferences = getSharedPreferences(getString(R.string.user_shared_preferences), Context.MODE_PRIVATE);
LocationUtil.storeLocation(sharedPreferences, lastLocation);
}
}
if (mGoogleApiClient.isConnected()) {
mGoogleApiClient.unregisterConnectionCallbacks(this);
mGoogleApiClient.unregisterConnectionFailedListener(this);
LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, this);
mGoogleApiClient.disconnect();
}
mGoogleApiClient = null;
}
@Override
public void onConnected(@Nullable Bundle bundle) {
Timber.e("GAC connected");
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
!= PackageManager.PERMISSION_GRANTED
&& ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION)
!= PackageManager.PERMISSION_GRANTED) {
Intent intent = new Intent(Constants.COMMENT_LOC_RESULTS);
LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(intent);
} else {
Timber.e("fetching location");
LocationRequest mLocationRequest = LocationRequest.create();
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
mLocationRequest.setInterval(1000 * 30);
mLocationRequest.setFastestInterval(1000 * 5);
if (ActivityCompat.checkSelfPermission(LocationIntentService.this,
Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED
&& ActivityCompat.checkSelfPermission(LocationIntentService.this,
Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
Intent intent = new Intent(Constants.COMMENT_LOC_RESULTS);
LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(intent);
return;
} else {
Timber.e("connected and access granted");
LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient,
mLocationRequest,
LocationIntentService.this);
}
}
}
@Override
public void onConnectionSuspended(int i) {
Timber.e("GAC suspended");
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
!= PackageManager.PERMISSION_GRANTED
&& ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION)
!= PackageManager.PERMISSION_GRANTED) {
Intent intent = new Intent(Constants.COMMENT_LOC_RESULTS);
LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(intent);
} else {
Location location = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
SharedPreferences sharedPreferences = getSharedPreferences(getString(R.string.user_shared_preferences), Context.MODE_PRIVATE);
LocationUtil.storeLocation(sharedPreferences, location);
}
}
@Override
public void onConnectionFailed(@NonNull ConnectionResult connectionResult) {
Timber.e("GAC failed");
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
!= PackageManager.PERMISSION_GRANTED
&& ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION)
!= PackageManager.PERMISSION_GRANTED) {
Intent intent = new Intent(Constants.COMMENT_LOC_RESULTS);
LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(intent);
} else {
Location location = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
SharedPreferences sharedPreferences = getSharedPreferences(getString(R.string.user_shared_preferences), Context.MODE_PRIVATE);
LocationUtil.storeLocation(sharedPreferences, location);
}
}
}
Try using this service class to get your location information and save the lat and lng into your shareprefs.
The localbroadcastmanager is only there to request for permission in the activity class:
private BroadcastReceiver locationResultsReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
ActivityCompat.requestPermissions(CommentActivity.this,
new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
LocationUtil.MY_PERMISSIONS_REQUEST_ACCESS_FINE_LOCATION);
}
};
The onrequestpermissionresult method in the activity class:
@Override
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
switch (requestCode) {
case LocationUtil.MY_PERMISSIONS_REQUEST_ACCESS_FINE_LOCATION: {
if (grantResults.length > 0) {
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
Intent intent = new Intent(this, LocationIntentService.class);
startService(intent);
} else {
// Should we show an explanation?
if (ActivityCompat.shouldShowRequestPermissionRationale(this,
Manifest.permission.ACCESS_FINE_LOCATION)) {
//Show permission explanation dialog...
AlertDialog.Builder builder = new AlertDialog.Builder(this, R.style.AppCompatAlertDialogStyle);
builder.setTitle(Constants.LOCATION_PERM);
builder.setCancelable(false);
builder.setMessage(Constants.LOCATION_PERM_SUBTEXT);
builder.setPositiveButton(getString(R.string.ok), new AlertDialog.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
ActivityCompat.requestPermissions(CommentActivity.this,
new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
LocationUtil.MY_PERMISSIONS_REQUEST_ACCESS_FINE_LOCATION);
}
});
builder.show();
} else {
AlertDialog.Builder builder = new AlertDialog.Builder(this, R.style.AppCompatAlertDialogStyle);
builder.setTitle(Constants.LOCATION_PERM);
builder.setCancelable(false);
builder.setMessage(Constants.LOCATION_PERM_REREQUEST_SUBTEXT);
builder.setPositiveButton(getString(R.string.settings), new AlertDialog.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
Intent intent = new Intent();
intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
Uri uri = Uri.fromParts("package", CommentActivity.this.getPackageName(), null);
intent.setData(uri);
startActivity(intent);
finish();
}
});
builder.show();
}
}
}
break;
}
LeakCanary will still dump but it will now say NO LEAK FOUND:
04-16 12:13:54.465 8120-15176/com.myapp D/LeakCanary: In com.myapp:1.0:1.
* NO LEAK FOUND.
* Reference Key: 718959be-c178-4237-a24f-8d74972c9cc0
* Device: unknown generic Google Nexus 5 - 5.1.0 - API 22 - 1080x1920 vbox86p
* Android Version: 5.1 API: 22 LeakCanary: 1.3.1
* Durations: watch=5059ms, gc=135ms, heap dump=1186ms, analysis=5174ms
from location-samples.
Hey @shailen any updates on this? It's quite surprising that such a big issue in play services, which is used in many apps, is not fixed after 10 months.
from location-samples.
We were able to solved it by @byencho approach combined with @sealskej approach.
Also unregister callbacks after removeLocationUpdates
thanks ...
from location-samples.
I tried using WeakReference but still leaking, very disappointed π
from location-samples.
Reading an issue from 2015 in 2019 and seeing it's still not fixed and that too by Google, ridiculous! I see everyone suffering here and I am also the victim.
Anyways, I am here to tell how I solved the issue. @sealskej approach worked for me. I am using LocationListener
through a third-party library so all I needed to do was to pass applicationContext
in the library instead of activity context.
from location-samples.
Thanks, this is invaluable feedback. Taking a look.
from location-samples.
Hey @shailen, any updates on the issue?
from location-samples.
@youfacepalm I've passed this on to the eng team and they're taking a look. I'll update this issue when I hear back from them.
from location-samples.
Hey @shailen if you have any updates can you please share it?
from location-samples.
The eng team is aware of the problem and is working on it. I'll update here when there's a fix.
from location-samples.
Just for reference, while using the most recent version of Google Play Services (8.3.0), LeakCanary is still reporting that the MainActivity
is leaking memory.
from location-samples.
@shailen I checked on Google Play Services 8.4.0 as well. The problem still remains!
from location-samples.
Any update on this? OOM kept happening as a result in our end :(
from location-samples.
Any updates? We faced a lot of OOM crashes because of this issue.
from location-samples.
@youfacepalm et al: I have no concrete updates, unfortunately, except to
say that the eng team is looking at this issue.
On Mon, Feb 1, 2016 at 8:21 AM, Thuy Trinh [email protected] wrote:
In our case, unregister following callbacks would resolve the issue:
googleApiClient.unregisterConnectionCallbacks(this); googleApiClient.unregisterConnectionFailedListener(this);
this is the fragment that implements the callbacks.
Also, remove the callback of location request if any:
LocationServices.FusedLocationApi.removeLocationUpdates(googleApiClient, this); googleApiClient.disconnect();
β
Reply to this email directly or view it on GitHub
#26 (comment)
.
from location-samples.
Got same problem. :( any updates?
from location-samples.
Same problem here. Please let me know when any updated
from location-samples.
Sorry everyone, no definitive updates on when the fix will land. Will update once I know more.
from location-samples.
I'm having this issue as well, i tested it with 'com.google.android.gms:play-services-location:8.4.0' but issue is still there.
Even though i tried to release in any way that i can (below), still keeps getting into this.
if (googleApiClient != null) {
googleApiClient.unregisterConnectionCallbacks(this);
googleApiClient.unregisterConnectionFailedListener(this);
if (googleApiClient.isConnected()) {
LocationServices.FusedLocationApi.removeLocationUpdates(googleApiClient, this);
}
googleApiClient.disconnect();
googleApiClient = null;
}
I'll also provide you LeakCanary log so that you can pin point the issue, and hopefully we can get an update soon.
from location-samples.
Same problem here:
04-15 17:58:39.311 9221-9270/com.myapp I/art: hprof: heap dump "/storage/emulated/0/Download/leakcanary/suspected_leak_heapdump.hprof" starting...
04-15 17:58:44.354 9221-10071/com.myapp D/LeakCanary: In com.myapp:1.0:1.
04-15 17:58:44.354 9221-10071/com.myapp D/LeakCanary: * com.myapp.activities.CommentActivity has leaked:
04-15 17:58:44.354 9221-10071/com.myapp D/LeakCanary: * GC ROOT com.google.android.gms.location.internal.zzd$zzb.zzamC
04-15 17:58:44.354 9221-10071/com.myapp D/LeakCanary: * references com.google.android.gms.location.internal.zzd$9.zzaOw (anonymous class extends com.google.android.gms.location.internal.zzd$zza)
04-15 17:58:44.354 9221-10071/com.myapp D/LeakCanary: * leaks com.myapp.activities.CommentActivity instance
04-15 17:58:44.354 9221-10071/com.myapp D/LeakCanary: * Reference Key: 631c670d-cf7f-4061-819d-914cc2d11620
04-15 17:58:44.354 9221-10071/com.myapp D/LeakCanary: * Device: unknown generic Google Nexus 5 - 5.1.0 - API 22 - 1080x1920 vbox86p
04-15 17:58:44.354 9221-10071/com.myapp D/LeakCanary: * Android Version: 5.1 API: 22 LeakCanary: 1.3.1
04-15 17:58:44.354 9221-10071/com.myapp D/LeakCanary: * Durations: watch=5011ms, gc=132ms, heap dump=1049ms, analysis=3963ms
04-15 17:58:44.354 9221-10071/com.myapp D/LeakCanary: * Details:
04-15 17:58:44.354 9221-10071/com.myapp D/LeakCanary: * Instance of com.google.android.gms.location.internal.zzd$zzb
04-15 17:58:44.354 9221-10071/com.myapp D/LeakCanary: | zzamC = com.google.android.gms.location.internal.zzd$9 [id=0x131f8830]
04-15 17:58:44.354 9221-10071/com.myapp D/LeakCanary: | mDescriptor = java.lang.String [id=0x13040b40]
04-15 17:58:44.354 9221-10071/com.myapp D/LeakCanary: | mObject = -704448000
04-15 17:58:44.354 9221-10071/com.myapp D/LeakCanary: | mOwner = com.google.android.gms.location.internal.zzd$zzb [id=0x13202ca0]
04-15 17:58:44.354 9221-10071/com.myapp D/LeakCanary: * Instance of com.google.android.gms.location.internal.zzd$9
04-15 17:58:44.354 9221-10071/com.myapp D/LeakCanary: | zzaOw = com.myapp.activities.CommentActivity [id=0x13d58000]
04-15 17:58:44.354 9221-10071/com.myapp D/LeakCanary: | zzaOx = com.google.android.gms.location.internal.zzd [id=0x12e84a00]
04-15 17:58:44.354 9221-10071/com.myapp D/LeakCanary: | zzaeE = com.google.android.gms.common.api.Api$zzc [id=0x12e84760]
04-15 17:58:44.354 9221-10071/com.myapp D/LeakCanary: | zzagH = java.util.concurrent.atomic.AtomicReference [id=0x131287a0]
04-15 17:58:44.354 9221-10071/com.myapp D/LeakCanary: | zzL = true
04-15 17:58:44.354 9221-10071/com.myapp D/LeakCanary: | zzagI = java.lang.Object [id=0x13128780]
04-15 17:58:44.354 9221-10071/com.myapp D/LeakCanary: | zzagJ = com.google.android.gms.common.api.internal.zzb$zza [id=0x13202c40]
04-15 17:58:44.354 9221-10071/com.myapp D/LeakCanary: | zzagK = java.lang.ref.WeakReference [id=0x13202c60]
04-15 17:58:44.354 9221-10071/com.myapp D/LeakCanary: | zzagL = java.util.ArrayList [id=0x13202b40]
04-15 17:58:44.354 9221-10071/com.myapp D/LeakCanary: | zzagM = null
04-15 17:58:44.354 9221-10071/com.myapp D/LeakCanary: | zzagN = false
04-15 17:58:44.354 9221-10071/com.myapp D/LeakCanary: | zzagO = false
04-15 17:58:44.354 9221-10071/com.myapp D/LeakCanary: | zzagP = false
04-15 17:58:44.354 9221-10071/com.myapp D/LeakCanary: | zzagQ = null
04-15 17:58:44.354 9221-10071/com.myapp D/LeakCanary: | zzagR = null
04-15 17:58:44.354 9221-10071/com.myapp D/LeakCanary: | zzagS = null
04-15 17:58:44.354 9221-10071/com.myapp D/LeakCanary: | zzagy = com.google.android.gms.common.api.Status [id=0x12c26f00]
04-15 17:58:44.354 9221-10071/com.myapp D/LeakCanary: | zzpJ = java.util.concurrent.CountDownLatch [id=0x13128790]
from location-samples.
@shailen any updates?
I have also reported the issue here: https://code.google.com/p/android/issues/detail?id=227856
from location-samples.
I have created a project that uses SupportMapFragment
and shows the user location using two approaches:
LocationServices.FusedLocationApi.requestLocationUpdates
googleMap.setOnMyLocationChangeListener
I've discovered that the second approach does not leak (though it is deprecated). This would be a workaround for some people that just need the user location to show it on a map.
from location-samples.
@fernandospr Try to switch your GoogleApiClient instance to automanage, it will fix the leak.
from location-samples.
@carlosjs23 Hi there Carlos, could you provide a snippet of how to use automanage to access the FusedLocationApi ? I know it should be the same as the other APIs but I'm struggling with it, thanks in advance
from location-samples.
from location-samples.
I'm using @byencho approach and is not leaking anymore, @fernandospr try that
from location-samples.
Thanks @thuytrinh removing the callbacks solved for me
from location-samples.
Has this been fixed yet? I'm also experiencing the same issue.
from location-samples.
@ryanthon no fixes from Google Play S. team, but you can use @byencho approach.
from location-samples.
Just set up @byencho's approach on my project. I noticed that it didn't fix the issue if I only used the weak reference for the LocationListener. It seems like the issue is actually caused by the connection callbacks listeners (ConnectionCallbacks and OnConnectionFailedListener). Once I set up a weak reference for those as well, the leak went away.
from location-samples.
Thanks @thuytrinh unregister the callbacks solved the problem for me.
from location-samples.
Hi all, I've been struggling with the same problem for the the last day or so until I found this post. However in my case it was not enough to pass connection and location listeners as weak references as it LeakCanary was still reporting activity leaked. Which was my anonymous class passed to
LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient,
mLocationCallback).then(new ResultTransform {...} )
to receive callback when the location listener has been removed. So I ended up not attaching this callback at the end. After all those three changes there were no more leaks reported.
Hope this helps anyone in any way.
from location-samples.
Has anyone tried the newer FusedLocationProviderClient instead? I tried the new sample for location updates, added Leak Canary, and again I still see a leak through LocationCallback. Even the onComplete callback for removeLocationUpdates isn't getting called in the sample.
from location-samples.
@GEllickson yup, I migrated to FusedLocationProviderClient as well. & it is still leaking
from location-samples.
I also have the same leak through LocationCallback using FusedLocationProviderClient.
from location-samples.
Using @sealskej solution worked for Me.
from location-samples.
With 'com.google.android.gms:play-services:11.0.1'
I also get the problem about LocationCallback. But it can be fixed by WeakReference.
my old code:LocationCallback mLocationCallback = new LocationCallback() { @Override public void onLocationResult(LocationResult locationResult) { super.onLocationResult(locationResult); // updateLocation(); } };
use mLocationCallback:
mFusedLocationClient.requestLocationUpdates(mLocationRequest, mLocationCallback, Looper.myLooper());
my fix code:
private static class LocationCallbackReference extends LocationCallback { private WeakReference<LocationCallback> locationCallbackRef; LocationCallbackReference(LocationCallback locationCallback) { locationCallbackRef = new WeakReference<LocationCallback>(locationCallback); } @Override public void onLocationResult(LocationResult locationResult) { super.onLocationResult(locationResult); if (locationCallbackRef != null && locationCallbackRef.get() != null) { locationCallbackRef.get().onLocationResult(locationResult); } } } LocationCallback locationCallback = new LocationCallback() { @Override public void onLocationResult(LocationResult locationResult) { super.onLocationResult(locationResult); updateLocation(); } }; mLocationCallback = new LocationCallbackReference(locationCallback); mFusedLocationClient.requestLocationUpdates(mLocationRequest, mLocationCallback, Looper.myLooper());
I just wrap the LocationCallback with WeakReference. The 'mFusedLocationClient' is constructed in this way:
mFusedLocationClient = LocationServices.getFusedLocationProviderClient(activity);
rather than "LocationServices.FusedLocationApi".
Oops!Not work for me!
from location-samples.
gms play service 17.0.0, LocationCallback instance still leaking.
workaround: use WeakReference in LocationCallback.
from location-samples.
Still leaking for me in Leak Canary despite callback being removeLocationUpdates and locationCallback being set to nil. Does anyone have an example in kotlin for WeakReference?
from location-samples.
I've used weak reference, still leaking:
mFusedLocationClient?.requestLocationUpdates(locationRequest, WeakReference(locationCallback).get(), null)
from location-samples.
I have to say, I can't see how this is expected behaviour. It is a silly problem that should be solved by now!
from location-samples.
I've used weak reference, still leaking:
mFusedLocationClient?.requestLocationUpdates(locationRequest, WeakReference(locationCallback).get(), null)
You got wrong with using java WeakReference
, You have to create a LocationCallback subclass which weak reference to your locationCallback
instance, and your locationCallback
itself must be strong referenced by your lifecycle container.
from location-samples.
I've used weak reference, still leaking:
mFusedLocationClient?.requestLocationUpdates(locationRequest, WeakReference(locationCallback).get(), null)
You got wrong with using java
WeakReference
, You have to create a LocationCallback subclass which weak reference to yourlocationCallback
instance, and yourlocationCallback
itself must be strong referenced by your lifecycle container.
You have just won my noble Paul's prize. It comes with no perks but lots of thanks!! Thank you, leak sorted! Maybe I should read more, complain later. Thanks @1001101
from location-samples.
The anonymous class (listener) has an implicit reference to the Activity. This is not Google's code causing the problem. The listener you register needs to be a concretely defined, static class so it won't contain an implicit reference to MainActivity.
Specifically this...
https://github.com/android/location-samples/blob/master/LocationUpdates/app/src/main/java/com/google/android/gms/location/sample/locationupdates/MainActivity.java#L330
from location-samples.
I also have this issue, for quite some time i was digging all the layers that compose my activity + my code
Experimented with a lot of approaches to make sure the listener was not keeping my activity in memory, profiled the app process a lot of times.
I have found an instance in the app heap which has the following fields
As you can see, we have a field called callbackIdMap, which is the one retaining the listeners the code was table to remove from the fusedlocationprovider client, but for some reason the references remain in the callbackIdMap as keys
As the google library code is offuscated, i am unable to know to that class these fields belong to. We have a constant string named LOCATION_PROVIDER_NAME also that has the string value "fused" which is not offuscated but i am unable to find any results by searching by this currently.
The fix would be to remove the listeners from this map when FusedLocationproviderClient.removeLocationUpdates is called, simple as that π
This ticket is open for almost 6 years surprisingly π§
from location-samples.
Maybe for you still seeing callbackIdMap
leaking on latest release
from location-samples.
Related Issues (20)
- Geofencing trigger does not work in Doze state
- Traceback (most recent call last): File "/home/marijn/Android/Sdk/ndk/25.1.8937393/prebuilt/linux-x86_64/bin/ndk-gdb.py", line 951, in <module> main() File "/home/marijn/Android/Sdk/ndk/25.1.8937393/prebuilt/linux-x86_64/bin/ndk-gdb.py", line 882, in main device.shell_nocheck(["run-as", pkg_name, "kill", "-9"] + kill_pids)TypeError: can only concatenate list (not "map") to listThis -gdb.py-gdb.pyis another Python 2 -> Python 3 conversion problem just like #1763: HOT 1
- Data Read
- Root Check
- Api
- Export note
- Spotlight
- Geocode for java HOT 1
- Update to Compose October '22
- Location Updates in the Background no updates are receiving in LocationUpdatesBroadcastReceiver HOT 2
- Sexroom2022 HOT 1
- LocationUpdatesForegroundService/app/src/main/java/com/google/android/gms/location/sample/locationupdatesforegroundservice/LocationUpdatesService.java
- Location update on background is not working. HOT 1
- Backgorund service sample is not working HOT 2
- SleepSampleKotlin doesn't work on Wear OS 3
- OS 13 - Not fetching location in background - Location Updates from Background HOT 2
- LocationUpdatesBackgroundKotlin: Got an exception: java.lang.IllegalArgumentException: com.google.android.gms.location.sample.locationupdatesbackgroundkotlin: Targeting S+ (version 31 and above) requires that one of FLAG_IMMUTABLE or FLAG_MUTABLE be specified when creating a PendingIntent. HOT 1
- Update background location sample to use workmanager
- PendingIntent.FLAG_CANCEL_CURRENT is not giving proper output on API version 31 or higher in Google Sleep API.
- How can I reduce power usage and still GET location updates in a location-based Android application?
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
π Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. πππ
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google β€οΈ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from location-samples.