FusedLocationProviderClient утечка памяти?

В одном из моих действий я использую FusedLocationProviderClient для получения постоянного обновления местоположения. Мои коды основаны на этом методе: https://developer.android.com/training/location/receive-location-updates

В моем onCreate я настраиваю провайдера и обратные вызовы

// setup fused location provider
mFusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(this);

    // build location request
    mLocationRequest = new LocationRequest();
    mLocationRequest.setInterval(30000);
    mLocationRequest.setFastestInterval(10000);
    mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
    mLocationRequest.setSmallestDisplacement(50);

    // Setup the callback function.
    mLocationCallback = new LocationCallback() {
        @Override
        public void onLocationResult(LocationResult locationResult) {
            if (locationResult == null) {
                return;
            }
            for (Location location : locationResult.getLocations()) {
                // Update UI with location data
                // ...

                mCurrentLocation = location;
            }
        }
    };

В onResume

mFusedLocationProviderClient.requestLocationUpdates(mLocationRequest,
                                mLocationCallback,
                                Looper.myLooper());

В onPause

mFusedLocationProviderClient.removeLocationUpdates(mLocationCallback);

И все же по какой-то причине утечка канарейки все еще указывает на утечку памяти. Утечка канарейка, показанная ниже

Просматривая вокруг переполнения стека, есть сообщения, которые, кажется, предполагают, что утечка связана с сервисом Google Play. Но эти посты говорили о fusedLocationApi, в то время как я использую fusedLocationProviderClient, поэтому я не уверен, что это то же самое, что я использую здесь. Кто-нибудь может подтвердить для меня? Спасибо!

3 ответа

Я исправил утечки, о которых сообщает LeakCanary, передав SoftReference LocationCallback в FusedLocationProvider.

public class LocationCallbackReference extends LocationCallback {

    private final SoftReference<LocationCallback> mLocationCallbackRef;

    public LocationCallbackReference(LocationCallback locationCallback) {
        mLocationCallbackRef = new SoftReference<>(locationCallback);
    }

    @Override
    public void onLocationResult(LocationResult locationResult) {
        super.onLocationResult(locationResult);
        if (mLocationCallbackRef.get() != null) {
            mLocationCallbackRef.get().onLocationResult(locationResult);
        }
    }

    @Override
    public void onLocationAvailability(LocationAvailability locationAvailability) {
        super.onLocationAvailability(locationAvailability);
        if (mLocationCallbackRef.get() != null) {
            mLocationCallbackRef.get().onLocationAvailability(locationAvailability);
        }
    }
}

Надеюсь, это поможет.

Для меня я использовал LocationCallback в качестве внутреннего анонимного объекта (потому что мне нужно обновить / получить доступ к данным включающего класса), а FusedLocationProviderClient вызывал утечку памяти.

Затем я реорганизую внутренний класс до статического(не внутреннего) класса и обновляю данные окружающего класса через живые данные, переданные в статический объект LocationCallback.

import android.app.Activity
import androidx.lifecycle.MutableLiveData
import com.google.android.gms.location.*


class LocationUtility constructor(private val activity: Activity) {


private var mLocationRequest: LocationRequest? = null
private var fusedLocationProviderClient: FusedLocationProviderClient? = null

var currentLocation = MutableLiveData<Pair<Double?, Double?>>()

private var myLocationCallback: MyLocationCallback? = null


init {
    fusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(activity)
    myLocationCallback = MyLocationCallback(currentLocation)
}



// Location call back
private class MyLocationCallback(val liveData: MutableLiveData<Pair<Double?, Double?>>) :
    LocationCallback() {

    override fun onLocationResult(locationResult: LocationResult?) {
        super.onLocationResult(locationResult)

        val latitude = locationResult?.locations?.get(0)?.latitude
        val longitude = locationResult?.locations?.get(0)?.longitude

        val locationInfo = Pair(latitude, longitude)
        liveData.value = locationInfo
    }
}

}

Google недавно решил эту проблему с утечкой памяти в своем последнем выпуске play-services-location:20.0.0. Примечание к выпуску .

Чтобы узнать больше об истории этой утечки памяти, проверьте это и это .

Другие вопросы по тегам