Android 定位服务耗尽电池 - 融合定位 API

Posted

技术标签:

【中文标题】Android 定位服务耗尽电池 - 融合定位 API【英文标题】:Android Location Services draining the Battery - Fused Location API 【发布时间】:2017-05-04 04:23:27 【问题描述】:

我们有一个基于位置的应用程序,我们正在尝试根据用户位置推送一些活动通知。但这似乎会耗尽手机的电池电量,有时会消耗高达 30-35% 的电量。

下面是我们应用中 Location 的实现。

public class DashboardActivity extends BaseActivity implements GoogleApiClient.OnConnectionFailedListener, GoogleApiClient.ConnectionCallbacks,
        LocationListener, ExitConfirmationDialog.OnExitResponseListner 


    private final int HAS_PERMISSION_COARSE_LOCATION = 1;
    private final int HAS_PERMISSION_FINE_LOCATION = 2;


    LocationManager locationManager;

    CustomTextViewDemi mNotificationCount;
    String count = "";
    Menu menu;
    List<CreateFragmentsPojo> fragments;

    boolean isSettingsScreenOpen = false;
    int backPresedCount = 0;


    @Override
    protected void onCreate(Bundle savedInstanceState) 
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_dashboard);

        setTitle("Dashboard");

        setupNavigationView(0);

        fragments = new ArrayList<>();

        Utils.HandleViews(mLayout, false);

        locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);

        if (isGPSLocationEnabled(locationManager)) 
            buildGooleApiClient();
         else if (isNetworkLocationEnabled(locationManager)) 
            buildGooleApiClient();
         else 
            showAlert();
        


    


    private void buildGooleApiClient() 

        buildGoogleApiClient();

        if (Build.VERSION.SDK_INT >= 23) 
            requestPermission();
         else 
            if (mGoogleApiClient != null) 
                if (mGoogleApiClient.isConnected()) 
                    getUserCurrentLocation();
                 else 
                    mGoogleApiClient.connect();
                
             else 
                getDashBoard("", "");
            
        
    


    public void getData(String lat, String lng) 
        if (Utils.isInternetConnection(this)) 
            getCampaignDetails(lat, lng);
         else 
            Utils.HandleViews(progressBar, false);
            Utils.showMessages(this, Params.CHECK_INTERNET_MESSAGE, true);
        
    


    private void getUserCurrentLocation() 

        try 
            Utils.HandleViews(progressBar, true);
            if (mGoogleApiClientAwareness == null) 
                buildGoogleApiAwarenessClient();
            


            Awareness.SnapshotApi.getLocation(mGoogleApiClientAwareness)
                    .setResultCallback(new ResultCallback<LocationResult>() 
                        @Override
                        public void onResult(@NonNull LocationResult locationResult) 
                            if (!locationResult.getStatus().isSuccess()) 
                                Log.e("awareness demo api ", "Could not get location.");

                                if (mGoogleApiClient != null) 
                                    try 
                                        Location mLastLocation = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
                                        if (mLastLocation != null) 
                                            getDashBoard(mLastLocation.getLatitude() + "", mLastLocation.getLongitude() + "");
                                         else 
                                            getDashBoard("", "");
                                        
                                     catch (SecurityException e) 
                                        e.printStackTrace();
                                    
                                 else 

                                    if (locationManager != null) 
                                        String provider = Utils.getUserLastLocation(locationManager);
                                        if (provider != null) 
                                            try 
                                                Location location = locationManager.getLastKnownLocation(provider);
                                                if (location != null) 
                                                    getDashBoard(location.getLatitude() + "", location.getLongitude() + "");
                                                 else 
                                                    getDashBoard("", "");
                                                
                                             catch (SecurityException e) 
                                                e.printStackTrace();
                                            
                                        
                                    
                                
                            
                            try 
                                Location location = locationResult.getLocation();

                                if (location != null) 
                                    getDashBoard(location.getLatitude() + "", location.getLongitude() + "");
                                 else 
                                    getDashBoard("", "");
                                

                             catch (Exception e) 
                                e.printStackTrace();
                            
                        
                    );

         catch (SecurityException se) 
            se.printStackTrace();
        
    



    private void showAlert() 
        final AlertDialog.Builder dialog = new AlertDialog.Builder(this);
        dialog.setTitle("Enable Location")
                .setMessage("Your Locations Settings is set to 'Off'.\nPlease Enable Location to " +
                        "get campaigns at your location.")
                .setPositiveButton("Location Settings", new DialogInterface.OnClickListener() 
                    @Override
                    public void onClick(DialogInterface paramDialogInterface, int paramInt) 
                        isSettingsScreenOpen = true;
                        Intent myIntent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
                        startActivityForResult(myIntent, 201);
                    
                )
                .setNegativeButton("Cancel", new DialogInterface.OnClickListener() 
                    @Override
                    public void onClick(DialogInterface paramDialogInterface, int paramInt) 
                        getUserCurrentLocation();
                    
                );

        dialog.show();
    



    /**
     * Get user permissions for location based updates
     */
    @TargetApi(23)
    private void requestPermission() 
        int HAS_REQUEST_PERMISSION_COARSE_LOCATION = ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION);

        if (HAS_REQUEST_PERMISSION_COARSE_LOCATION
                != PackageManager.PERMISSION_GRANTED) 

            if (ActivityCompat.shouldShowRequestPermissionRationale(this, android.Manifest.permission.WRITE_EXTERNAL_STORAGE)) 

                new AlertDialog.Builder(this)
                        .setTitle("Request Permission")
                        .setMessage("Provide permission to access your location")
                        .setNegativeButton(android.R.string.cancel, null)
                        .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() 
                            @Override
                            public void onClick(DialogInterface dialog, int which) 
                                requestPermissions(new String[]Manifest.permission.ACCESS_COARSE_LOCATION,
                                        HAS_PERMISSION_COARSE_LOCATION);
                            
                        ).create().show();


             else 
                requestPermissions(new String[]Manifest.permission.ACCESS_COARSE_LOCATION,
                        HAS_PERMISSION_COARSE_LOCATION);

            
         else 
            requestFineLocationPermission();
        

    

    @TargetApi(23)
    private void requestFineLocationPermission() 

        int HAS_REQUEST_PERMISSION_FINE_LOCATION = ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION);

        if (HAS_REQUEST_PERMISSION_FINE_LOCATION
                != PackageManager.PERMISSION_GRANTED) 

            if (ActivityCompat.shouldShowRequestPermissionRationale(this, android.Manifest.permission.WRITE_EXTERNAL_STORAGE)) 

                new AlertDialog.Builder(this)
                        .setTitle("Request Permission")
                        .setMessage("Provide permission to access your location")
                        .setNegativeButton(android.R.string.cancel, null)
                        .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() 
                            @Override
                            public void onClick(DialogInterface dialog, int which) 
                                requestPermissions(new String[]Manifest.permission.ACCESS_FINE_LOCATION,
                                        HAS_PERMISSION_FINE_LOCATION);
                            
                        ).create().show();

             else 
                requestPermissions(new String[]Manifest.permission.ACCESS_FINE_LOCATION,
                        HAS_PERMISSION_FINE_LOCATION);


            
         else 
            getUserCurrentLocation();
        
    


    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) 
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        if (requestCode == HAS_PERMISSION_COARSE_LOCATION) 
            if (grantResults.length > 0
                    && grantResults[0] == PackageManager.PERMISSION_GRANTED) 
                requestFineLocationPermission();
            
         else if (requestCode == HAS_PERMISSION_FINE_LOCATION) 
            if (grantResults.length > 0
                    && grantResults[0] == PackageManager.PERMISSION_GRANTED) 
                getUserCurrentLocation();
            
        
    

    /**
     * Call to detect new campaigns near by
     */
    private void getUserLocationBackgroundProcess() 
        try 
            //Utils.getCurrentLocation(this);
            startLocationUpdates();
         catch (Exception e) 
            e.printStackTrace();
        
    


    private boolean isGPSLocationEnabled(LocationManager locationManager) 
        return locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);

    

    private boolean isNetworkLocationEnabled(LocationManager locationManager) 
        return locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
    


    protected synchronized void buildGoogleApiAwarenessClient() 
        try 
            Log.i(TAG, "activity Building GoogleApiClient===");
            mGoogleApiClientAwareness = new GoogleApiClient.Builder(this)
                    .addApi(Awareness.API)
                    .addConnectionCallbacks(this)
                    .addOnConnectionFailedListener(this)
                    .build();

            mGoogleApiClientAwareness.connect();
            //createLocationRequest();
         catch (Exception e) 
            e.printStackTrace();
        
    


    protected synchronized void buildGoogleApiClient() 
        try 
            Log.i(TAG, "activity Building GoogleApiClient===");

            buildGoogleApiAwarenessClient();

            mGoogleApiClient = new GoogleApiClient.Builder(this)
                    .addConnectionCallbacks(this)
                    .addOnConnectionFailedListener(this)
                    .addApi(LocationServices.API)
                    .build();

            createLocationRequest();
         catch (Exception e) 
            e.printStackTrace();
            getUserCurrentLocation();
        
    


    protected void createLocationRequest() 
        mGoogleApiClient.connect();
        mLocationRequest = new LocationRequest();
        mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
        mLocationRequest.setSmallestDisplacement(30);
    


    @Override
    public void onLocationChanged(Location location) 
        mCurrentLocation = location;
    

    @Override
    public void onConnected(@Nullable Bundle bundle) 
        getUserCurrentLocation();
       // startLocationUpdates();
    

    protected void startLocationUpdates() 
        try 
            mRequestingLocationUpdates = true;

            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);
                
                /*else 
                    mGoogleApiClient.connect();
                    LocationServices.FusedLocationApi.requestLocationUpdates(
                            mGoogleApiClient, mLocationRequest, pendingIntent);

                */
             else 
                buildGoogleApiClient();
            
         catch (SecurityException se) 
            se.printStackTrace();
         catch (Exception e) 
            e.printStackTrace();
        
    


    @Override
    protected void onResume() 
        super.onResume();

        try 
            if (isSettingsScreenOpen) 
                isSettingsScreenOpen = false;
                getUserCurrentLocation();
            
         catch (Exception e) 
            e.printStackTrace();
        
    

    @Override
    public void onConnectionSuspended(int i) 

    


    @Override
    public void onConnectionFailed(@NonNull ConnectionResult connectionResult) 

    


    @Override
    protected void onStop() 
        super.onStop();

        if (mGoogleApiClient != null) 
            if (mGoogleApiClient.isConnected())
                mGoogleApiClient.disconnect();
        
    



【问题讨论】:

1.你的BaseActivity 中有什么 2. 我在 Google 示例中没有看到 LocationManager - github.com/googlesamples/android-play-location/blob/master/… 我想知道它是否调用设备 LocationManager 而不是 Google 的 Fused Location API 3. 你在哪里停止位置更新? @MorrisonChang BaseActivity -> 是父活动,它与应用程序的其他活动保持公共参数。我不需要编写多个时间相同的代码,我可以从活动中调用它们。当 GPS 不可用时使用 LocationManager。 【参考方案1】:

代替

mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);

试试这个

mLocationRequest.setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY);

mlocationrequest.setSmallestDisplacement(30); //higher priority

位移参数设置为30米 //如果设备没有移动或跨越该距离,则不会接收到位置更新。

//setInterval as above 1 mins.
mlocationrequest.setInterval(60000); // Update location every 1 minute

mlocationrequest.setFastestInterval(10000);

LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY级精度被认为是100米左右的精度。使用这样的粗略精度通常会消耗更少的功率。

【讨论】:

以上是关于Android 定位服务耗尽电池 - 融合定位 API的主要内容,如果未能解决你的问题,请参考以下文章

iOS 上的标准定位服务电池消耗

Android 调试 -> 电池耗尽

为啥我的 Android 应用程序会耗尽电池电量?

为啥我的 Android 应用程序偶尔会非常快地耗尽电池电量?

在 Android 上调查电池耗尽问题的步骤

如何每 5 秒或当用户移动阈值而不耗尽电池时获得高精度位置?