【问题标题】:Android: Google Maps location with low battery usageAndroid:谷歌地图位置电池使用率低
【发布时间】:2015-03-22 09:34:30
【问题描述】:

我的应用目前正在使用 Google Play Services 的地图

具体说明:

mMap.setMyLocationEnabled(true);

我意识到每次在我的应用中显示地图时:

  • 位置在地图上用蓝点表示
  • 位置图标显示在顶部栏中
  • 如果我进入手机的设置/位置,我的应用被报告为“耗电量大”

但是,我可以看到有些应用使用地图并仍然显示位置蓝点,但位置图标没有出现在顶部栏中,并且它们的电池使用量很低。

我的应用目前授予这两种权限:

  • android.permission.ACCESS_COARSE_LOCATION
  • android.permission.ACCESS_FINE_LOCATION

我的问题是:

如何在电量不足的情况下显示位置蓝点?

是否可以通过代码指定精度/电池使用情况?

更新

其实我意识到这样做的方法是使用GoogleApiClientFusedLocationApi

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

我已经在我的 Activity 中配置了 GoogleApiClient,调用:

  • GoogleApiClient.connect() 活动开始
  • GoogleApiClient.disconnect() 活动结束

onConnected 回调中,我设置了位置更新的标准:1 分钟的最快间隔,低功耗优先:

    private static final LocationRequest REQUEST = LocationRequest.create()
        .setFastestInterval(60000)   // in milliseconds
        .setInterval(180000)         // in milliseconds
        .setPriority(LocationRequest.PRIORITY_LOW_POWER);

    @Override
    public void onConnected(Bundle bundle) {
        LocationServices.FusedLocationApi.requestLocationUpdates(
            mGoogleApiClient,
            REQUEST,
            this);  // LocationListener
    }

我已经测试了 GoogleApiClient 在启动时是否正确连接,但由于某些原因,每当我访问带有嵌入式 MapView 的片段时,我仍然会在设置/位置上为我的应用程序高耗电量屏幕!

似乎 MapView 忽略了这些低功耗标准!

【问题讨论】:

  • 你不需要这两个权限,选择其中一个
  • 我可以看到应用程序请求了这两个权限,并且仍然能够在电池使用量低的情况下显示位置蓝点。我想知道是否有一种方法可以在代码中以编程方式设置准确性。
  • 那你的问题是什么?
  • 我的问题是如何在电池电量不足的情况下仍然显示位置
  • 所以请编辑您的问题

标签: android google-maps google-play-services google-maps-android-api-2 location-services


【解决方案1】:

终于找到解决方案了!!! 感谢特里斯坦的回答!

默认情况下,GoogleMap 使用其位置提供程序,而不是融合位置提供程序。为了使用 Fused Location Provider(它允许您控制位置精度和功耗),您需要使用 GoogleMap.setLocationSource() (documentation) 显式设置地图位置源

我在这里报告了一个示例活动:

import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.common.api.GoogleApiClient.ConnectionCallbacks;
import com.google.android.gms.common.api.GoogleApiClient.OnConnectionFailedListener;
import com.google.android.gms.location.LocationListener;
import com.google.android.gms.location.LocationRequest;
import com.google.android.gms.location.LocationServices;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.GoogleMap.OnMyLocationButtonClickListener;
import com.google.android.gms.maps.LocationSource;
import com.google.android.gms.maps.OnMapReadyCallback;
import com.google.android.gms.maps.SupportMapFragment;

import android.location.Location;
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;


public class MainActivity extends FragmentActivity
    implements
        ConnectionCallbacks,
        OnConnectionFailedListener,
        LocationSource,
        LocationListener,
        OnMyLocationButtonClickListener,
        OnMapReadyCallback {

    private GoogleApiClient mGoogleApiClient;
    private TextView mMessageView;
    private OnLocationChangedListener mMapLocationListener = null;

    // location accuracy settings
    private static final LocationRequest REQUEST = LocationRequest.create()
            .setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY);

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mMessageView = (TextView) findViewById(R.id.message_text);

        SupportMapFragment mapFragment =
                (SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map);
        mapFragment.getMapAsync(this);

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

    }

    @Override
    protected void onResume() {
        super.onResume();
        mGoogleApiClient.connect();
    }

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

    @Override
    public void onMapReady(GoogleMap map) {
        map.setLocationSource(this);
        map.setMyLocationEnabled(true);
        map.setOnMyLocationButtonClickListener(this);
    }

    public void showMyLocation(View view) {
        if (mGoogleApiClient.isConnected()) {
            String msg = "Location = "
                    + LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
            Toast.makeText(getApplicationContext(), msg, Toast.LENGTH_SHORT).show();
        }
    }

    /**
     * Implementation of {@link LocationListener}.
     */
    @Override
    public void onLocationChanged(Location location) {
        mMessageView.setText("Location = " + location);
        if (mMapLocationListener != null) {
            mMapLocationListener.onLocationChanged(location);
        }
    }


    @Override
    public void onConnected(Bundle connectionHint) {
        LocationServices.FusedLocationApi.requestLocationUpdates(
                mGoogleApiClient,
                REQUEST,
                this);  // LocationListener
    }


    @Override
    public void onConnectionSuspended(int cause) {
        // Do nothing
    }

    @Override
    public void onConnectionFailed(ConnectionResult result) {
        // Do nothing
    }

    @Override
    public boolean onMyLocationButtonClick() {
        Toast.makeText(this, "MyLocation button clicked", Toast.LENGTH_SHORT).show();
        // Return false so that we don't consume the event and the default behavior still occurs
        // (the camera animates to the user's current position).
        return false;
    }

    @Override
    public void activate(OnLocationChangedListener onLocationChangedListener) {
        mMapLocationListener = onLocationChangedListener;
    }

    @Override
    public void deactivate() {
        mMapLocationListener = null;
    }
}

【讨论】:

  • 有趣的是,这正是 SDK 附带的 google-play-services 示例中的 MyLocationDemo。您只有接口 LocationSource。好东西。
  • 我有一个问题什么时候被叫无效
  • 我将赏金分配给了特里斯坦,但我将这个问题报告为答案,因为它提供了一个完整的工作示例。
【解决方案2】:

您将希望使您的活动(或为此目的更好地成为一个单独的对象)实现LocationSource 接口。

这很简单,您需要存储在activate() 方法中传递的侦听器,并在位置更新时调用它,并在调用deactivate() 时忘记它。有关示例,请参见 this answer,您可能希望将其更新为使用 FusedLocationProvider

完成此设置后,您可以将您的活动作为地图的LocationSource 传递,例如mMap.setLocationSource(this) (documentation)。

这将阻止地图使用其默认的LocationSource,该LocationSource 使用高电量使用定位服务。

【讨论】:

  • 看我的回答,它说默认位置源确实是 FusedLocationProvider 所以没有必要重新设置。
  • 已设置但未设置为LocationRequest.PRIORITY_LOW_POWER
  • 非常感谢特里斯坦,这是正确的答案!!!!你赢了50分赏金!!!!似乎谷歌地图默认使用它自己的位置源,而不是 FusedLocationProvider。因此,如果您想控制准确性,则需要显式设置 FusedLocationProvider。
【解决方案3】:

据说here

FusedLocationProviderApi 提供改进的位置查找和电源使用,并由“我的位置”蓝点使用。

所以地图上的“我的位置”点由FusedLocationProviderApi 提供。当您授予android.permission.ACCESS_FINE_LOCATION 权限时,您允许FusedLocationProviderApi 让您的应用从 GPS 获取数据,这可能会导致电池消耗过多。

所以只添加 android.permission.ACCESS_COARSE_LOCATION 权限到 manifest 和 Android 不应该责怪你电池使用。

【讨论】:

  • 很遗憾,无法删除 android.permission.ACCESS_FINE_LOCATION 权限:stackoverflow.com/questions/17089141/…
  • 默认情况下,地图上的位置点实际上不是由FusedLocationProvider 馈送的。您需要显式设置地图位置源才能从FusedLocationProvider获取数据
【解决方案4】:

您可以通过使用网络提供程序类来做到这一点 您可以使用以下代码 AppLocationService.java // 专门用于获取低电量的当前位置(与nexus 5 ,5.0 中的省电模式相同)

package coreclass;

import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.os.IBinder;

public class AppLocationService extends Service implements LocationListener {

protected LocationManager locationManager;
Location location;

private static final long MIN_DISTANCE_FOR_UPDATE = 10;
private static final long MIN_TIME_FOR_UPDATE = 1000 * 60 * 2;

public AppLocationService(Context context) {
    locationManager = (LocationManager) context
            .getSystemService(LOCATION_SERVICE);
}

public Location getLocation(String provider) {
    if (locationManager.isProviderEnabled(provider)) {
        locationManager.requestLocationUpdates(provider,
                MIN_TIME_FOR_UPDATE, MIN_DISTANCE_FOR_UPDATE, this);
        if (locationManager != null) {
            location = locationManager.getLastKnownLocation(provider);
            return location;
        }
    }
    return null;
}

@Override
public void onLocationChanged(Location location) {
}

@Override
public void onProviderDisabled(String provider) {
}

@Override
public void onProviderEnabled(String provider) {
}

@Override
public void onStatusChanged(String provider, int status, Bundle extras) {
}

@Override
public IBinder onBind(Intent arg0) {
    return null;
}

}

上述类的用法 MainActivity.java

AppLocationService appLocationService;
appLocationService = new AppLocationService(getActivity());
Location nwLocation = appLocationService.getLocation(LocationManager.NETWORK_PROVIDER);
                        if (nwLocation != null) {
                            Lat = nwLocation.getLatitude();
                            Longi = nwLocation.getLongitude();

                        }

通过这种方式,您可以在高使用模式下使用 GPS 模式获取当前位置,之后您可以设置蓝点或任何您想要的东西

希望对大家有所帮助

【讨论】:

  • 这不是问题的答案
  • @你怎么能这么说?有什么你知道的吗?
猜你喜欢
  • 2014-08-07
  • 2012-11-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-03-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多