如何使用FUSED LOCATION API优化电池 - Android

时间:2016-12-19 18:31:10

标签: android android-intent gps android-location android-fusedlocation

您好我正面临android下的位置API问题/问题

  • 电池消耗高达30% - 40%,导致大量电池耗尽。

  • 状态栏中的位置图标始终为ON,即使应用已关闭且应用程序已卸载,它也会自动关闭。

要求:

  • 打开应用时需要用户位置。
  • 即使未根据距离打开应用程序或未使用应用程序,我也需要有用户位置 - 需要在后台使用用户位置。

方法:

  1. 使用GPS

  2. API使用具有待定意图的FUSED LOCATION API。

  3. LocationManager - 检查GPS开/关的状态。

  4. 代码walkthru:

    1. 在OnCreate中获取位置管理器实例 - 获取位置管理器的实例。

    2. 检查是启用GPS还是网络状态可用,否则显示对话框以启用位置:代码: -

      // get GPS state.
          locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
      
      
          if (isGPSLocationEnabled(locationManager)) {
              buildGooleLocationApiClient();
          } else if (isNetworkLocationEnabled(locationManager)) {
              buildGooleLocationApiClient();
          } else {
              showAlert();
          }
      
    3. goolgeLocationAPiClient的代码:在这个方法中,我正在检查android版本,请求权限和启用服务

      private void buildGooleLocationApiClient() {
      
              if (Build.VERSION.SDK_INT >= 23) {
      
                  int isFineLocationPermission = ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION);
                  int isCoarseLocationPermission = ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION);
      
                  if (isFineLocationPermission == PackageManager.PERMISSION_DENIED || isCoarseLocationPermission == PackageManager.PERMISSION_DENIED) {
                      requestPermission();
                  } else {
                      checkGoogleLocationApiClient();
                  }
      
              } else {
                  checkGoogleLocationApiClient();
              }
          }
      

      构建GoogleAPI客户端:

      private void checkGoogleLocationApiClient() {
              try {
                  if (mGoogleApiClient != null) {
                      if (mGoogleApiClient.isConnected()) {
                          getMyLocationCampaigns();
                      } else {
                          mGoogleApiClient.connect();
                      }
                  } else {
                      buildGoogleApiClient();
                  }
              } catch (Exception e) {
                  e.printStackTrace();
              }
          }
      
          private void getMyLocationCampaigns() {
              if (mCurrentLocation != null) {
                  getData(mCurrentLocation.getLatitude()+"",mCurrentLocation.getLongitude()+"");
              } else {
                  try {
                      mCurrentLocation = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
                      getData(mCurrentLocation.getLatitude()+"",mCurrentLocation.getLongitude()+"");
                  } catch (SecurityException ex) {
                      ex.printStackTrace();
                      getData("","");
                  }
              }
          }
      
      private synchronized void buildGoogleApiClient() {
              try {
                  Log.i(TAG, "activity Building GoogleApiClient===");
                  mGoogleApiClient = new GoogleApiClient.Builder(this)
                          .addConnectionCallbacks(this)
                          .addOnConnectionFailedListener(this)
                          .addApi(LocationServices.API)
                          .build();
      
                  createLocationRequest();
              } catch (Exception e) {
                  e.printStackTrace();
                  getData("","");
              }
          }
      
      
          private void createLocationRequest() {
              mLocationRequest = new LocationRequest();
              mLocationRequest.setInterval(60 * 60 * 1000);
              mLocationRequest.setFastestInterval(60 * 1000);
              mLocationRequest.setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY);
              mLocationRequest.setSmallestDisplacement(100);
      
              connectGoogleApiClient();
          }
      
      
      private void connectGoogleApiClient() {
              if (mGoogleApiClient != null) {
                  if (!mGoogleApiClient.isConnected())
                      mGoogleApiClient.connect();
              }
          }
      
      
      @Override
          public void onLocationChanged(Location location) {
              mCurrentLocation = location;
          }
      
          @Override
          public void onConnected(@Nullable Bundle bundle) {
      
              if (mCurrentLocation == null) {
                  try {
                      mCurrentLocation = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
                      if (mCurrentLocation != null) {
      // MyAPICALL                    getData(mCurrentLocation.getLatitude()+"",mCurrentLocation.getLongitude()+"");
                      } else {
                          LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient,mLocationRequest, this);
                          mCurrentLocation = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
                          if (mCurrentLocation == null) {
                              if (locationManager != null) {
                                  String provider = Utils.getUserLastLocation(locationManager);
                                  if (provider != null) {
                                      try {
                                          Location location = locationManager.getLastKnownLocation(provider);
                                          if (location != null) {
                                              getData(location.getLatitude() + "", location.getLongitude() + "");
                                          } else {
                                              getData("", "");
                                          }
                                      } catch (SecurityException e) {
                                          e.printStackTrace();
                                      }
                                  }
                              }
                          } else {
                              getData(mCurrentLocation.getLatitude()+"",mCurrentLocation.getLongitude()+"");
                          }
                      }
                  } catch (SecurityException ex) {
                      ex.printStackTrace();
                  } catch (Exception e) {
                      e.printStackTrace();
                      getData("","");
                  }
              }
          }
      

      具有待定意图的背景中的getlocation方法

      private void startLocationUpdates() {
              try {
      
      
                  Intent receiverIntentService = new Intent(this, LocationIntentService.class);
                  PendingIntent pendingIntent = PendingIntent.getService(this, 1, receiverIntentService, 0);
      
                  if (mGoogleApiClient != null) {
                      if (mGoogleApiClient.isConnected()) {
                          LocationServices.FusedLocationApi.requestLocationUpdates(
                                  mGoogleApiClient, mLocationRequest, pendingIntent);
                      }
      
                  }
              } catch (SecurityException se) {
                  se.printStackTrace();
              }
          }
      

      BroadCastReceiver:如果设备重新启动:

      public class LocationBroadcastReceiver extends BroadcastReceiver implements
              GoogleApiClient.ConnectionCallbacks,GoogleApiClient.OnConnectionFailedListener, LocationListener {
      
      
          Context context;
          protected GoogleApiClient mGoogleApiClient;
          protected LocationRequest mLocationRequest;
          protected Location mCurrentLocation;
          public static Boolean mRequestingLocationUpdates = false;
      
          SharedPreferences checkUserStatus;
      
          public LocationBroadcastReceiver() {
          }
      
          @Override
          public void onReceive(Context context, Intent intent) {
              // TODO: This method is called when the BroadcastReceiver is receiving
              // an Intent broadcast.
              try {
                  this.context = context;
      
                  checkUserStatus = context.getSharedPreferences(Params.LOGIN_DETAILS_PREFERENCE, 0);
                  String isUserLogedIn = checkUserStatus.getString(Params.TOKEN,"");
      
      // if user is still logged in then only trigger background service
                  if (!isUserLogedIn.equals("")) {
                      buildGoogleApiClient();
                      if (mGoogleApiClient != null) {
                          if (mGoogleApiClient.isConnected() && mRequestingLocationUpdates) {
                              startLocationUpdates();
                          } else {
                              buildGoogleApiClient();
                          }
                      } else {
                          buildGoogleApiClient();
                      }
                  }
      
              } catch (Exception e) {
                  e.printStackTrace();
              }
          }
      
      
          @Override
          public void onConnected(Bundle bundle) {
              startLocationUpdates();
          }
      
          @Override
          public void onConnectionSuspended(int i) {
              mGoogleApiClient.connect();
          }
      
      
          @Override
          public void onConnectionFailed(ConnectionResult connectionResult) {
              Log.i("Broadcast receiver", "Connection failed: ConnectionResult.getErrorCode() = " + connectionResult.getErrorCode());
          }
      
      
          @Override
          public void onLocationChanged(Location location) {
              mCurrentLocation = location;
          }
      
      
          protected synchronized void buildGoogleApiClient() {
              mGoogleApiClient = new GoogleApiClient.Builder(context)
                      .addConnectionCallbacks(this)
                      .addOnConnectionFailedListener(this)
                      .addApi(LocationServices.API)
                      .build();
      
              createLocationRequest();
          }
      
      
      
          protected void createLocationRequest() {
              mLocationRequest = new LocationRequest();
              mLocationRequest.setInterval(60 * 60 * 1000);
              mLocationRequest.setFastestInterval(60 * 1000);
              mLocationRequest.setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY);
              mLocationRequest.setSmallestDisplacement(100);
      
          }
      
          protected void startLocationUpdates() {
              try {
      
      
                  Intent receiverIntentService = new Intent(context,LocationIntentService.class);
                  PendingIntent pendingIntent = PendingIntent.getService(context,1,receiverIntentService,0);
      
                  LocationServices.FusedLocationApi.requestLocationUpdates(
                          mGoogleApiClient, mLocationRequest, pendingIntent);
      
      
              }catch (SecurityException se) {
                  se.printStackTrace();
              } catch (Exception e) {
                  e.printStackTrace();
              }
          }
      }
      

      我的意向服务类:获取用户更新的位置并进行API调用

      public class LocationIntentService extends IntentService {
      
          Context context;
          Bitmap myBitmap;
      
          URL url;
      
          SharedPreferences.Editor mMyLastLocationHolder;
          SharedPreferences mMyLastLocation;
      
          SharedPreferences checkUserStatus;
      
      
          public LocationIntentService() {
              super("LocationIntentService");
          }
      
          @Override
          protected void onHandleIntent(Intent intent) {
      
              if (intent != null) {
                  Bundle bundle = intent.getExtras();
                  if (bundle != null) {
                      Location location = bundle.getParcelable("com.google.android.location.LOCATION");
                      if (location != null) {
                          context = getApplicationContext();
      // API call to server
                          updateAPI(location.getLatitude()+"",location.getLongitude()+"");
      
                          Log.v("TAG LOCATION ", " ==== " + location.getLatitude() + " - " + location.getLongitude() + " ==== ");
                          Log.v("TAG LOCATION ", " ==== calling my-campaigns near me ========");
                      }
                  }
              }
      
          }
      
      
      
      
          /**
           * Handle action Foo in the provided background thread with the provided
           * parameters.
           */
          private void handleActionFoo(String param1, String param2) {
              // TODO: Handle action Foo
              throw new UnsupportedOperationException("Not yet implemented");
          }
      
          /**
           * Handle action Baz in the provided background thread with the provided
           * parameters.
           */
          private void handleActionBaz(String param1, String param2) {
              // TODO: Handle action Baz
              throw new UnsupportedOperationException("Not yet implemented");
          }
      
      
      
      }
      

3 个答案:

答案 0 :(得分:0)

我希望这可以帮助您找到最佳解决方案/方法。

个人更喜欢使用具有特定优先级和间隔的GoogleApiClient和LocationRequest。 编写实现以下接口的服务:

  1. GoogleApiClient.ConnectionCallbacks
  2. GoogleApiClient.OnConnectionFailedListener
  3. LocationListener的

    public class PositionService extends Service implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener, LocationListener {}

  4. 使用GoogleApiClient和LocationRequest类。

    进入 onCreate() 实例化GoogleApiClient对象,LocationRequest对象并使mGoogleApiClient连接。

    public void onCreate() {
        mGoogleApiClient = new GoogleApiClient.Builder(this)
                            .addConnectionCallbacks(this)
                            .addOnConnectionFailedListener(this)
                            .addApi(LocationServices.API)
                            .build();
        mLocationRequest = LocationRequest.create()
                        .setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY)
                     .setInterval(mInterval).setFastestInterval(mFastInterval);
        mGoogleApiClient.connect();
    }
    

    进入 onDestroy() 方法,使mGoogleApiClient断开连接

    @Override
    public void onDestroy() {
        mGoogleApiClient.disconnect();
    }
    

    现在实现接口

    @Override
    public void onLocationChanged(Location location) {
    
        Log.d("NewLocation", location.toString());
    
    }
    
    @Override
    public void onConnected(@Nullable Bundle bundle) throws SecurityException {
        LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, this);
    }
    
    @Override
    public void onConnectionSuspended(int i) {
    
    }
    
    @Override
    public void onConnectionFailed(@NonNull ConnectionResult connectionResult) {
    
    }
    

    现在GoogleApiClient会根据LocationRequest的设置通知您调用 onLocationChanged() 回调的位置

    您的业务逻辑应放在 onLocationChanged() 方法中。只需为LocationRequest选择一个良好的间隔时间和优先级。 (见documentation

    请参阅有关location strategies的官方文档,我的解决方案就是基于此。

    我习惯于在Foreground中启动服务以防止操作系统出现意外行为(例如服务被杀)

答案 1 :(得分:0)

这只会向您解释更好的逻辑

而不是长时间运行的服务或IntentService只需使用Firebase JobDispatcher或任何第三方lib Jobscheduler API,以便将所有位置更新代码移动到Jobscheduler(https://github.com/googlesamples/android-JobScheduler/blob/master/Application/src/main/java/com/example/android/jobscheduler/service/MyJobService.java

根据您的位置更新间隔启动作业,根据您的要求配置或更改作业!与长期运行的服务相比,它确实是一个更好的解决方案!!!(您可以在Activity或片段中使用eventBus或RxBus进行位置更新!!)

提示:每次作业开始时,在作业关闭之前触发位置更新设置一些系统延迟3秒或更长时间,因为有些时候Googleapiclient需要更多时间来更新延迟后更新新的GPS时间您可以使用正在运行的JobService关闭Googleapiclient所有不需要的回调。通过检测用户活动,使用Google Awareness Api或Google Fit API智能地控制作业配置!

一体化Job Jobscheduler Lib:https://github.com/evernote/android-job

P.S:代码将很快更新

答案 2 :(得分:0)

文档link

  

活动应该强烈考虑在何时删除所有位置请求   进入后台(例如在onPause()),或至少交换   要求更大的间隔和更低的质量。

因此,当我遇到类似问题时,我所做的是:

  1. 我创建了两个位置请求,第一个请求优先级为 PRIORITY_HIGH_ACCURACY ,间隔为1分钟,而第二个请求优先级为 PRIORITY_LOW_POWER ,内部为1小时和最小位移1km
  2. 启动应用程序时,我使用第一个位置请求(高优先级)来获得更频繁和准确的位置更新
  3. 当应用程序进入后台时,我会切换到第二个位置请求(低优先级)以消除电池使用情况,同时减少位置更新频率
  4. (可选)您还可以在应用启动时获取电池百分比,并根据限制(例如15%)选择当应用处于前台时您可能想要使用的位置请求
  5. 这些步骤帮助我将应用的电池使用量从> 30%降低到<3%。