【问题标题】:How to optimise battery with FUSED LOCATION API - Android如何使用 FUSED LOCATION API 优化电池 - Android
【发布时间】:2017-05-04 20:55:59
【问题描述】:

您好,我在 android 中遇到以下问题/问题与位置 API 相关

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

  • 状态栏中的位置图标始终处于打开状态,即使在关闭应用和卸载应用时它也会自动关闭。

要求:

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

方法:

  1. 带 GPS

  2. API 使用 FUSED LOCATION API 和未决意图。

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

代码演练:

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

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

    // get GPS state.
        locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
    
    
        if (isGPSLocationEnabled(locationManager)) {
            buildGooleLocationApiClient();
        } else if (isNetworkLocationEnabled(locationManager)) {
            buildGooleLocationApiClient();
        } else {
            showAlert();
        }
    

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

以待定意图在后台获取位置的方法

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



}

【问题讨论】:

  • 我正在使用 FusedLocationApi 做类似的事情(我使用了长时间运行的服务而不是 IntentService),并且我的电池使用量很少(每 3 分钟更新一次位置)。我怀疑您的问题更有可能来自 LocationManager。你能在没有它的情况下尝试破解吗?

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


【解决方案1】:

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

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

  1. GoogleApiClient.ConnectionCallbacks
  2. GoogleApiClient.OnConnectionFailedListener
  3. 位置监听器

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

使用 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的官方文档,我的解决方案就是以此为基础的。

我习惯于在前台启动服务以防止操作系统的意外行为(例如服务被终止)

【讨论】:

  • Matt - 感谢您的回答,但是当您可以将 fusedlocationAPI 与用于该目的的pendingintent 一起使用时,为什么您需要创建一个单独的服务。后台服务消耗更多功率,并且必须在 fusedlocation 自行管理的地方显式处理。我想知道您对给出解决方案的建议的思考过程和原因。
  • 我参考了官方文档developer.android.com/guide/topics/location/strategies.html,它建议使用LocationListener(或实现相应的接口)。我创建一个单独的服务没有具体原因。
【解决方案2】:

这只会更好地解释你的逻辑

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

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

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

多合一作业作业调度程序库:https://github.com/evernote/android-job

P.S:代码会很快更新

【讨论】:

    【解决方案3】:

    文档states

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

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

    1. 我创建了两个位置请求,第一个的优先级为 PRIORITY_HIGH_ACCURACY,间隔为 1 分钟,而第二个的优先级为 PRIORITY_LOW_POWER,内部为 1小时,最小位移1公里
    2. 应用启动时,我使用第一个位置请求(高优先级)来获得更频繁、更准确的位置更新
    3. 当应用进入后台时,我切换到第二个位置请求(低优先级)以消除电池使用量,同时减少位置更新频率
    4. (可选)您还可以在应用启动时获取电池百分比,并根据限制(例如 15%)选择应用在前台时可能要使用的位置请求

    这些步骤帮助我将应用的电池使用量从 >30% 降低到

    【讨论】:

      猜你喜欢
      • 2018-01-15
      • 2016-04-07
      • 2017-05-30
      • 2017-05-02
      • 2015-12-02
      • 2017-05-26
      • 2013-09-14
      • 2016-04-11
      • 2016-07-19
      相关资源
      最近更新 更多