【问题标题】:FusedLocationProviderClient.removeLocationUpdates always returns failureFusedLocationProviderClient.removeLocationUpdates 总是返回失败
【发布时间】:2018-05-22 08:01:56
【问题描述】:

我有一个activity,它扩展了一个名为LocationAwareActivity 的基础class,所有这些LocationAwareActivity activity 所做的就是创建一个定位服务客户端

LocationServices.getFusedLocationProviderClientlistens 到 位置更新。

此活动的来源在这里 https://github.com/snijsure/MultiActivity/blob/master/app/src/main/java/com/example/subodhnijsure/multiactivity/LocationAwareActivity.java

当活动被销毁时,它会调用 removeLocationUpdates 。我发现的是

  • removeLocationUpdate 返回一个总是返回不成功的任务
  • 更令人担忧的是,由于位置活动没有被删除,activity 没有被垃圾收集。

- 因此,如果我启动继承自 LocationAwareActivity 的任何活动,该活动始终保持在堆上。

所以问题是停止接收位置更新从而允许activity 被垃圾收集的正确方法是什么。

可以在此处访问该项目的全部源代码 - https://github.com/snijsure/MultiActivity

【问题讨论】:

  • 尝试在 removeLocationUpdates 上实现 OnCompletelistener。

标签: java android android-location


【解决方案1】:

removeLocationUpdates中你应该传递locationCallback,当前的实现是错误的。

不过,其他地方仍有可能发生内存泄漏。您应该尝试在您的应用程序中集成Leakcanary,它可以为您提供参考树,并会告诉您哪个字段或侦听器导致此内存泄漏。 可以参考one of my only blog post here

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");
            }
        }
    }

【讨论】:

    【解决方案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() )中删除,因为它停止一次,我们为什么要多次调用。

    希望对你有所帮助。

    【讨论】:

      【解决方案3】:

      通过查看存储库中的代码,我发现了您设计中的一些问题,这些问题可能会导致您的Activity 泄露。

      1) 您正在使用两个不同的LocationCallbacks。一个在 start 方法中,一个在 stop 方法中,但您实际上应该使用相同的方法。因此,一次实例化就足够了,并且在删除 LocationCallback 时可能还会导致 Task 的成功结果。

      2) 由于您使用Anonymous Class 实例化了两次LocationCallback,因此即使您完成了包含类,您也会保留内部类的非静态引用,这会导致您的Memory Leak。你可以阅读更多关于这个here的信息。

      3) 恕我直言,最好使用单独的管理器类来处理您的位置请求,而不是抽象 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;
          }
      }
      

      这只是一个猜测,因为我没有尝试您的代码,但无论如何该解决方案应该对您有所帮助。如果我错了,请纠正我;)

      【讨论】:

        【解决方案4】:

        Task 对象返回 false 的原因在于您的 stopLocationUpdates 方法中,您再次创建了一个本地 **LocationCallback** 引用,然后将此引用用作 locationProviderClient.removeLocationUpdates(cL); 中的参数 您的本地 LocationCallBack 永远不会出现在 locationProviderClient 中

        所以你要做的是,你必须传递你在 startLocationUpdates 方法中实例化的同一个全局对象,而不是创建另一个 LocationCallBack 对象

        你的代码应该是这样的

        final Task<Void> voidTask = locationProviderClient.removeLocationUpdates(locationCallback);
        

        【讨论】:

        • 不,这没有任何区别,即使调用locationProviderClient.removeLocationUpdates(locationCallback); removeLocationUpdates 继续返回失败并且活动继续泄漏。
        猜你喜欢
        • 2021-12-27
        • 1970-01-01
        • 1970-01-01
        • 2016-02-07
        • 1970-01-01
        • 2021-11-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多