【问题标题】:Memory leak with Location update with fusedLocationProvider使用 fusedLocationProvider 进行位置更新的内存泄漏
【发布时间】:2022-01-02 07:01:44
【问题描述】:

大多数常见建议是,因为似乎泄漏来自上下文,所以使用应用程序上下文并将位置调用从活动生命周期中分离出来。我既做了以前的事情,也做了后来的事情。但泄漏仍然存在。这是我使用 viewmodel 的实现,

public class LocationViewModel extends ViewModel {    
    private final MutableLiveData<Location> _locationLive = new MutableLiveData<>();
    public LiveData<Location> locationLive = _locationLive;
    private final static String TAG = "LocationViewModel";
    private final FusedLocationProviderClient mFusedLocationClient;
    private LocationRequest locationRequest;
    private WeakReference<LocationCallback> locationCallback;

    private static final long UPDATE_INTERVAL = 5000, FASTEST_INTERVAL = 3000;

    public LocationViewModel() {
        mFusedLocationClient = LocationServices.getFusedLocationProviderClient(MyApp.getApplication());
        prepareGpsAccess();
    }

    private void prepareGpsAccess() {
        locationRequest = LocationRequest.create();
        locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
        locationRequest.setInterval(UPDATE_INTERVAL); // 10 seconds
        locationRequest.setFastestInterval(FASTEST_INTERVAL); // 5 seconds

        locationCallback = new WeakReference<>(new LocationCallback() {
            @Override
            public void onLocationResult(@NonNull LocationResult locationResult) {
                for (Location location : locationResult.getLocations()) {
                    _locationLive.postValue(location);
                    stopLocationUpdates();
                }
            }
        });
    }

    public void stopLocationUpdates() {
        if (mFusedLocationClient != null && locationCallback.get() != null) {
            try {
                final Task<Void> voidTask = mFusedLocationClient.removeLocationUpdates(locationCallback.get());
                voidTask.addOnCompleteListener(task -> {
                    Log.e(TAG, "StopLocation addOnCompleteListener: " + task.isComplete());
                    if (task.isSuccessful()) {
                        Log.d(TAG, "StopLocation updates successful! ");
                    } else {
                        Log.d(TAG, "StopLocation updates unsuccessful! " + voidTask.toString());
                    }
                });

                voidTask.addOnSuccessListener(aVoid -> Log.e(TAG, "StopLocation addOnSuccessListener: "));
                voidTask.addOnFailureListener(e -> Log.e(TAG, "StopLocation addOnFailureListener: " + e.toString()));
            } catch (SecurityException exp) {
                Log.d(TAG, "StopLocation Security exception while removeLocationUpdates");
            }
        }
    }

    public void getLocation() {
        if (ActivityCompat.checkSelfPermission(MyApp.getApplication(), Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED
                && ActivityCompat.checkSelfPermission(MyApp.getApplication(), Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            return;
        }
        mFusedLocationClient.requestLocationUpdates(locationRequest, locationCallback.get(), Looper.myLooper());
    }
}

这是 LeakCanary 的输出,

1 APPLICATION LEAKS
    
    References underlined with "~~~" are likely causes.
    Learn more at https://squ.re/leaks.
    
    549 bytes retained by leaking objects
    Signature: 567aad2e1a38902d91202892cd70b65cb7df4f3
    ┬───
    │ GC Root: Global variable in native code
    │
    ├─ com.google.android.gms.location.zzam instance
    │    Leaking: UNKNOWN
    │    Retaining 1.5 kB in 31 objects
    │    ↓ zzam.zza
    │           ~~~
    ├─ com.google.android.gms.location.zzx instance
    │    Leaking: UNKNOWN
    │    Retaining 807 B in 23 objects
    │    ↓ zzx.zzc
    │          ~~~
    ├─ com.package.LocationViewModel$1 instance
    │    Leaking: UNKNOWN
    │    Retaining 561 B in 17 objects
    │    Anonymous subclass of com.google.android.gms.location.LocationCallback
    │    ↓ LocationViewModel$1.this$0
    │                          ~~~~~~
    ╰→ com.package.LocationViewModel instance
    ​     Leaking: YES (ObjectWatcher was watching this because com.package.location.LocationViewModel received
    ​     ViewModel#onCleared() callback)
    ​     Retaining 549 B in 16 objects
    ​     key = f23437cd-aafa-4153-866b-2b8961646172
    ​     watchDurationMillis = 14454
    ​     retainedDurationMillis = 9452

我尝试了很多东西,仍然存在这种泄漏。如果您知道避免这种泄漏的另一种方法,请分享。

这里还有一个相关问题,https://github.com/android/location-samples/issues/100

【问题讨论】:

  • 是否可以覆盖onCleared方法,并且在super之前将回调值改为null?

标签: android memory-leaks geolocation google-location-services


【解决方案1】:

所以基本上,在我使用 16.xx 之前,通过更新 google 解决了这个问题。最后我更新到 17.0.0,这个问题就消失了。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-02-20
    • 1970-01-01
    • 1970-01-01
    • 2013-10-13
    • 2010-11-03
    • 2011-10-22
    • 1970-01-01
    相关资源
    最近更新 更多