Git Product home page Git Product logo

Comments (54)

byencho avatar byencho commented on July 24, 2024 25

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.

HOLDfoot avatar HOLDfoot commented on July 24, 2024 11

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.

thuytrinh avatar thuytrinh commented on July 24, 2024 8

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.

fernandospr avatar fernandospr commented on July 24, 2024 7

@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.

stanmots avatar stanmots commented on July 24, 2024 6

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.

youfacepalm avatar youfacepalm commented on July 24, 2024 3

@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.

sealskej avatar sealskej commented on July 24, 2024 3

Passing application context to GoogleApiClient.Builder should solve the leak.

mGoogleApiClient = new GoogleApiClient.Builder(getContext().getApplicationContext())

from location-samples.

bubenheimer avatar bubenheimer commented on July 24, 2024 3

Confirmed fixed in 20.0.0. Good news, but did this really have to take 7 years and 12 major releases?

from location-samples.

Winghin2517 avatar Winghin2517 commented on July 24, 2024 1

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.

droidster avatar droidster commented on July 24, 2024 1

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.

rajeevinimekumar008 avatar rajeevinimekumar008 commented on July 24, 2024 1

We were able to solved it by @byencho approach combined with @sealskej approach.
Also unregister callbacks after removeLocationUpdates
thanks ...

from location-samples.

n-abdelmaksoud avatar n-abdelmaksoud commented on July 24, 2024 1

I tried using WeakReference but still leaking, very disappointed πŸ˜”

from location-samples.

sidhuparas avatar sidhuparas commented on July 24, 2024 1

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.

shailen avatar shailen commented on July 24, 2024

Thanks, this is invaluable feedback. Taking a look.

from location-samples.

youfacepalm avatar youfacepalm commented on July 24, 2024

Hey @shailen, any updates on the issue?

from location-samples.

shailen avatar shailen commented on July 24, 2024

@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.

youfacepalm avatar youfacepalm commented on July 24, 2024

Hey @shailen if you have any updates can you please share it?

from location-samples.

shailen avatar shailen commented on July 24, 2024

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.

APBrown avatar APBrown commented on July 24, 2024

@shailen,

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.

youfacepalm avatar youfacepalm commented on July 24, 2024

@shailen I checked on Google Play Services 8.4.0 as well. The problem still remains!

from location-samples.

thuytrinh avatar thuytrinh commented on July 24, 2024

Any update on this? OOM kept happening as a result in our end :(

from location-samples.

SudaNix avatar SudaNix commented on July 24, 2024

Any updates? We faced a lot of OOM crashes because of this issue.

from location-samples.

shailen avatar shailen commented on July 24, 2024

@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.

xserxses avatar xserxses commented on July 24, 2024

Got same problem. :( any updates?

from location-samples.

pjcs2 avatar pjcs2 commented on July 24, 2024

Same problem here. Please let me know when any updated

from location-samples.

shailen avatar shailen commented on July 24, 2024

Sorry everyone, no definitive updates on when the fix will land. Will update once I know more.

from location-samples.

yayaa avatar yayaa commented on July 24, 2024

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.

Winghin2517 avatar Winghin2517 commented on July 24, 2024

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.

fernandospr avatar fernandospr commented on July 24, 2024

@shailen any updates?
I have also reported the issue here: https://code.google.com/p/android/issues/detail?id=227856

from location-samples.

fernandospr avatar fernandospr commented on July 24, 2024

I have created a project that uses SupportMapFragment and shows the user location using two approaches:

  1. LocationServices.FusedLocationApi.requestLocationUpdates
  2. 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.

carlosjs23 avatar carlosjs23 commented on July 24, 2024

@fernandospr Try to switch your GoogleApiClient instance to automanage, it will fix the leak.

from location-samples.

alejofila avatar alejofila commented on July 24, 2024

@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.

carlosjs23 avatar carlosjs23 commented on July 24, 2024

from location-samples.

alejofila avatar alejofila commented on July 24, 2024

I'm using @byencho approach and is not leaking anymore, @fernandospr try that

from location-samples.

Naibeck avatar Naibeck commented on July 24, 2024

Thanks @thuytrinh removing the callbacks solved for me

from location-samples.

ryanthon avatar ryanthon commented on July 24, 2024

Has this been fixed yet? I'm also experiencing the same issue.

from location-samples.

carlosjs23 avatar carlosjs23 commented on July 24, 2024

@ryanthon no fixes from Google Play S. team, but you can use @byencho approach.

from location-samples.

ryanthon avatar ryanthon commented on July 24, 2024

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.

kaininggu avatar kaininggu commented on July 24, 2024

Thanks @thuytrinh unregister the callbacks solved the problem for me.

from location-samples.

aidanas avatar aidanas commented on July 24, 2024

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.

GEllickson avatar GEllickson commented on July 24, 2024

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.

xserxses avatar xserxses commented on July 24, 2024

@GEllickson yup, I migrated to FusedLocationProviderClient as well. & it is still leaking

from location-samples.

Alkisum avatar Alkisum commented on July 24, 2024

I also have the same leak through LocationCallback using FusedLocationProviderClient.

from location-samples.

refaelsh avatar refaelsh commented on July 24, 2024

Using @sealskej solution worked for Me.

from location-samples.

IrvingRyan avatar IrvingRyan commented on July 24, 2024

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.

 avatar commented on July 24, 2024

gms play service 17.0.0, LocationCallback instance still leaking.
workaround: use WeakReference in LocationCallback.
image

from location-samples.

paulsUsername avatar paulsUsername commented on July 24, 2024

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.

paulsUsername avatar paulsUsername commented on July 24, 2024

I've used weak reference, still leaking:

mFusedLocationClient?.requestLocationUpdates(locationRequest, WeakReference(locationCallback).get(), null)

from location-samples.

paulsUsername avatar paulsUsername commented on July 24, 2024

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.

 avatar commented on July 24, 2024

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.

paulsUsername avatar paulsUsername commented on July 24, 2024

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.

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.

raderto avatar raderto commented on July 24, 2024

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.

ruieduardosoares avatar ruieduardosoares commented on July 24, 2024

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
image

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.

chrisjenx avatar chrisjenx commented on July 24, 2024

Maybe for you still seeing callbackIdMap leaking on latest release

from location-samples.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo 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.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.