Android:Google 低电量情况下的地图位置
Android: Google Maps location with low battery usage
我的应用目前正在使用 Google Play Services
的地图
具体说明:
mMap.setMyLocationEnabled(true);
我每次在我的应用程序中显示地图时都意识到:
- 位置在地图上用蓝点表示
- 顶部栏中显示位置图标
- 如果我进入 phone 的 Settings/Location,我的应用会被报告为 "High battery use"
但是,我可以看到有些应用程序使用地图并仍然显示位置蓝点,但位置图标没有出现在顶部栏中并且它们的电池使用率很低。
我的应用目前授予这两种权限:
android.permission.ACCESS_COARSE_LOCATION
android.permission.ACCESS_FINE_LOCATION
我的问题是:
如何在低电量时显示位置蓝点?
是否可以通过代码指定 accuracy/battery 用法?
更新
实际上我意识到这样做的方法是使用 GoogleApiClient
的 FusedLocationApi
mGoogleApiClient = new GoogleApiClient.Builder(context)
.addApi(LocationServices.API)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.build();
我已经在 Activity 中配置了 GoogleApiClient,调用:
GoogleApiClient.connect()
在 Activity 的开头
GoogleApiClient.disconnect()
在 Activity 的停靠点
在 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 的片段时,我的应用程序仍然高电量使用在 Settings/Location 屏幕上!
MapView 似乎忽略了这些低功耗标准!
您可以使用网络提供商 classes
您可以使用以下代码
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;
}
}
上面的用法class
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模式获取当前位置,之后你可以设置蓝点或任何你想要的
希望对大家有帮助
据说 here
FusedLocationProviderApi provides improved location finding and power usage and is used by the "My Location" blue dot.
所以 "My Location" 地图上的点是由 FusedLocationProviderApi
提供的。当您授予权限 android.permission.ACCESS_FINE_LOCATION
时,您允许 FusedLocationProviderApi
您的应用从 GPS 获取数据,这可能会导致电池使用率过高。
所以只添加 android.permission.ACCESS_COARSE_LOCATION
权限来显示并且 Android 不应该因为电池使用而责怪你。
您需要让您的 activity(或为此目的更好的单独对象)实现 LocationSource
接口。
很简单,您需要存储传入 activate()
方法的侦听器,并在位置更新时调用它,而在调用 deactivate()
时忘记它。有关示例,请参阅 this answer,您可能希望将其更新为使用 FusedLocationProvider
。
完成此设置后,您可以将 activity 作为地图的 LocationSource
传递,例如 mMap.setLocationSource(this)
(documentation).
这将阻止地图使用其默认设置 LocationSource
,后者使用高电量使用定位服务。
终于找到了解决方案!!!
感谢特里斯坦的回答!
默认情况下,GoogleMap 使用其本地位置提供程序,而不是融合位置提供程序。为了使用 Fused Location Provider(允许您控制位置精度和功耗),您需要使用 GoogleMap.setLocationSource()
(documentation)
明确设置地图位置源
我在这里报告了一个示例 activity 来做到这一点:
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;
}
}
我的应用目前正在使用 Google Play Services
具体说明:
mMap.setMyLocationEnabled(true);
我每次在我的应用程序中显示地图时都意识到:
- 位置在地图上用蓝点表示
- 顶部栏中显示位置图标
- 如果我进入 phone 的 Settings/Location,我的应用会被报告为 "High battery use"
但是,我可以看到有些应用程序使用地图并仍然显示位置蓝点,但位置图标没有出现在顶部栏中并且它们的电池使用率很低。
我的应用目前授予这两种权限:
android.permission.ACCESS_COARSE_LOCATION
android.permission.ACCESS_FINE_LOCATION
我的问题是:
如何在低电量时显示位置蓝点?
是否可以通过代码指定 accuracy/battery 用法?
更新
实际上我意识到这样做的方法是使用 GoogleApiClient
的 FusedLocationApi
mGoogleApiClient = new GoogleApiClient.Builder(context)
.addApi(LocationServices.API)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.build();
我已经在 Activity 中配置了 GoogleApiClient,调用:
GoogleApiClient.connect()
在 Activity 的开头GoogleApiClient.disconnect()
在 Activity 的停靠点
在 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 的片段时,我的应用程序仍然高电量使用在 Settings/Location 屏幕上!
MapView 似乎忽略了这些低功耗标准!
您可以使用网络提供商 classes 您可以使用以下代码 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;
}
}
上面的用法class 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模式获取当前位置,之后你可以设置蓝点或任何你想要的
希望对大家有帮助
据说 here
FusedLocationProviderApi provides improved location finding and power usage and is used by the "My Location" blue dot.
所以 "My Location" 地图上的点是由 FusedLocationProviderApi
提供的。当您授予权限 android.permission.ACCESS_FINE_LOCATION
时,您允许 FusedLocationProviderApi
您的应用从 GPS 获取数据,这可能会导致电池使用率过高。
所以只添加 android.permission.ACCESS_COARSE_LOCATION
权限来显示并且 Android 不应该因为电池使用而责怪你。
您需要让您的 activity(或为此目的更好的单独对象)实现 LocationSource
接口。
很简单,您需要存储传入 activate()
方法的侦听器,并在位置更新时调用它,而在调用 deactivate()
时忘记它。有关示例,请参阅 this answer,您可能希望将其更新为使用 FusedLocationProvider
。
完成此设置后,您可以将 activity 作为地图的 LocationSource
传递,例如 mMap.setLocationSource(this)
(documentation).
这将阻止地图使用其默认设置 LocationSource
,后者使用高电量使用定位服务。
终于找到了解决方案!!! 感谢特里斯坦的回答!
默认情况下,GoogleMap 使用其本地位置提供程序,而不是融合位置提供程序。为了使用 Fused Location Provider(允许您控制位置精度和功耗),您需要使用 GoogleMap.setLocationSource()
(documentation)
我在这里报告了一个示例 activity 来做到这一点:
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;
}
}