FusedLocationProviderClient.removeLocationUpdates всегда возвращает ошибку

8

У меня есть activity, который расширяет базу class, называемую LocationAwareActivity, все это LocationAwareActivity activity делает, создает клиент службы местоположения

LocationServices.getFusedLocationProviderClient и listens до обновления местоположения.

Источник для этого действия здесь https://github.com/snijsure/MultiActivity/blob/master/app/src/main/java/com/example/subodhnijsure/multiactivity/LocationAwareActivity.java

И когда действие уничтожается, он вызывает removeLocationUpdates. Я нахожусь

  • removeLocationUpdate возвращает задачу, которая всегда возвращает не-успешно
  • Больше о том, что действия местоположения не удаляются, activity не получает сбор мусора.

Изображение 68070 - Поэтому, если я начинаю любую деятельность, которая наследует от LocationAwareActivity, что активность всегда остается на куче.

Итак, вопрос в том, что является правильным способом прекратить получение обновлений местоположения, тем самым позволяя activity собирать мусор.

Здесь можно получить доступ ко всему источнику для этого проекта - https://github.com/snijsure/MultiActivity

Теги:
android-location

4 ответа

3

Изучив код в репозитории, я обнаружил некоторые проблемы в вашем дизайне, которые могут привести к утечке вашего Activity.

1) Вы используете два разных LocationCallbacks. Один в начале и один в методе остановки, но вы должны фактически использовать то же самое. Таким образом, один экземпляр экземпляра будет достаточным и приведет, вероятно, к успешному результату вашего Task при удалении LocationCallback.

2) Поскольку вы создаете экземпляр LocationCallback дважды с помощью Anonymous Class, вы сохраняете нестатические ссылки для внутреннего класса, даже если вы закончите класс, который вызывает ваш Memory Leak. Вы можете прочитать об этом здесь.

3) IMHO лучше использовать отдельный класс менеджера для обработки ваших запросов местоположения, чем абстрагировать Activity.

Здесь сказано, что я...

Решение

GpsManager.java

public class GpsManager extends LocationCallback {

    private FusedLocationProviderClient client;
    private Callback callback;

    public interface Callback {
        void onLocationResult(LocationResult locationResult);
    }

    public boolean start(Context context, Callback callback) {
        this.callback = callback;
        client = LocationServices.getFusedLocationProviderClient(context);
        if (!checkLocationPermission(context)) return false;
        client.requestLocationUpdates(getLocationRequest(), this, null);
        return true;
    }

    public void stop() {
        client.removeLocationUpdates(this);
    }

    @Override
    public void onLocationResult(LocationResult locationResult) {
        callback.onLocationResult(locationResult);
    }

    private boolean checkLocationPermission(Context context) {
        int permissionCheck = ContextCompat.checkSelfPermission(
                context, android.Manifest.permission.ACCESS_FINE_LOCATION);
        return permissionCheck == PackageManager.PERMISSION_GRANTED;
    }

    private LocationRequest getLocationRequest() {
        return LocationRequest.create()
                .setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY)
                .setInterval(30_000L)
                .setFastestInterval(20_000L);
    }
}

и назвав это из вашего Activity следующим образом

YourActivity.java

public class MapsActivity extends AppCompatActivity implements GpsManager.Callback  {

    private static final int PERMISSION_REQUEST_FINE_LOCATION = 1;
    private GpsManager mGpsManager;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        ...
        mGpsManager = new GpsManager(getApplicationContext(), this);

        // check if user gave permissions, otherwise ask via dialog
        if (!checkPermission()) {
            getLocationPermissions();
            return;
        }

        mGpsManager.start();
        ...
    }

    @Override
    protected void onStop() {
        super.onStop();
        mGpsManager.stop();
    }

    @Override
    public void onLocationResult(LocationResult locationResult) {
        // do something with the locationResult
    }

    // CHECK PERMISSIONS PART

    private boolean checkPermission() {
        return isGranted(ActivityCompat.checkSelfPermission(this, ACCESS_FINE_LOCATION)) &&
                isGranted(ActivityCompat.checkSelfPermission(this, ACCESS_COARSE_LOCATION));
    }

    @TargetApi(Build.VERSION_CODES.M)
    private void getLocationPermissions() {
        requestPermissions(new String[] {Manifest.permission.ACCESS_FINE_LOCATION},
                PERMISSION_REQUEST_FINE_LOCATION);
    }

    @Override
    public void onRequestPermissionsResult(int code, @Nullable String permissions[], @Nullable int[] results) {
        switch (code) {
            case PERMISSION_REQUEST_FINE_LOCATION:
                if (isPermissionGranted(results)) {
                    getLocationRequest();
                }
        }
    }

    private boolean isPermissionGranted(int[] results) {
        return results != null && results.length > 0 && isGranted(results[0]);
    }

    private boolean isGranted(int permission) {
        return permission == PackageManager.PERMISSION_GRANTED;
    }
}

Это просто предположение, потому что я не пробовал ваш код, но решение должно помочь вам в любом случае. Пожалуйста, поправьте меня, если я ошибаюсь;)

3

В removeLocationUpdates вам следует передать locationCallback, текущая реализация неверна.

Тем не менее, есть вероятность утечки памяти где-то в другом месте. Вы должны попробовать интегрировать Leakcanary в свое приложение, и оно может дать вам дерево ссылок и сообщит вам, какое поле или слушатель вызывает утечку памяти, Вы можете сослаться на один из моих сообщений только в блоге

public void stopLocationUpdates() {
        if (locationProviderClient != null) {
            try {
                final Task<Void> voidTask = locationProviderClient.removeLocationUpdates(locationCallback);
                if (voidTask.isSuccessful()) {
                    Log.d(TAG,"StopLocation updates successful! ");
                } else {
                    Log.d(TAG,"StopLocation updates unsuccessful! " + voidTask.toString());
                }
            }
            catch (SecurityException exp) {
                Log.d(TAG, " Security exception while removeLocationUpdates");
            }
        }
    }
3

Причина, по которой объект Task возвращает false, находится в вашем методе stopLocationUpdates, вы снова создаете локальную ссылку **LocationCallback**, а затем используя эту ссылку в качестве аргумента в locationProviderClient.removeLocationUpdates(cL); где локальная LocationCallBack никогда не присутствует в locationProviderClient

Так что вам нужно сделать, вместо того, чтобы создавать другой объект LocationCallBack, вы должны передать тот же глобальный объект, который вы создаете в своем методе startLocationUpdates

ваш код должен выглядеть следующим образом

inal Task<Void> voidTask = locationProviderClient.removeLocationUpdates(locationCallback);
  • 0
    Нет, это не имеет никакого значения, даже если кто-то вызывает locationProviderClient.removeLocationUpdates(locationCallback); removeLocationUpdates продолжает возвращать ошибку, а действия продолжают протекать.
2

Привет @Subodh Nijsure Пожалуйста, проверьте код ниже и вставьте его в свой код и после его проверки:

final Task<Void> voidTask = locationProviderClient.removeLocationUpdates(locationCallback);
                voidTask.addOnCompleteListener(new OnCompleteListener<Void>() {
                    @Override
                    public void onComplete(@NonNull Task<Void> task) {
                        Log.e(TAG, "addOnCompleteListener: "+task.isComplete());
                    }
                });

                voidTask.addOnSuccessListener(new OnSuccessListener<Void>() {
                    @Override
                    public void onSuccess(Void aVoid) {
                        Log.e(TAG, "addOnSuccessListener: " );
                    }
                });

                voidTask.addOnFailureListener(new OnFailureListener() {
                    @Override
                    public void onFailure(@NonNull Exception e) {
                        Log.e(TAG, "addOnFailureListener: ");
                    }
                });

Я думаю, что voidTask.isSuccessful() этот метод не работает, когда вы помещаете этот слушатель в то время, когда он работает нормально, и я также вижу в памяти, что он освобождает всю память, когда приходит к предыдущему действию.

И когда вы перенаправляетесь на какое-либо действие, пожалуйста, stopLocationUpdates() вызывается один раз в onPause() и удаляется из другого метода, например onDestroy(), onStop(), потому что он останавливается один раз, поэтому почему мы должны вызовите несколько раз.

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

Ещё вопросы

Сообщество Overcoder
Наверх
Меню