使用Google Play服务的Android定位
欢迎使用Google Play服务示例访问Android位置。
今天,我们将学习如何通过示例应用程序使用Google Play服务API来检索您的移动位置。
Android Location API概述
在上一教程中,我们使用了Android的API(自Android的API 1开始提供)来检索用户的位置。
那么为什么需要引入Google Play定位服务? Google为什么没有增强Android的Location API?与默认的Android Location API相比,Google Play定位服务有哪些优势?让我们讨论这些问题以获得清晰的想法。
需要引入Google Play定位服务
作为Google Play服务的一部分的Google Location Services API提供了更强大的高级框架,该框架可自动执行诸如位置提供商选择和电源管理之类的任务。
此外,它提供了新功能,例如Android Framework的Location API中未提供的用户活动检测。
目前,Google提供了5种用户状态,分别是"车内","骑行","步行","静止"和"倾斜",它们足以检测用户的活动并根据用户的状态提供正确的内容。
它提供的另一个功能是Geofencing API,用于通知用户进入或者离开特定区域。
上述优势清楚地说明了为什么Google推荐使用Google Location Services API(也称为FusedLocationProviderApi)来获取用户位置。
它可以根据我们的需求提供最佳的准确性。
Google为什么没有增强Android的Location API?
从技术角度来看,由于Android具有智能手机制造商掌握的独立更新推出功能,因此Google并未改进Android的Location API。
Google对它的控制较少,因此决定改用新的API。
有几个重要的类可用于获取位置:
LocationRequest:一个数据对象,其中包含对FusedLocationProviderApi的请求的服务质量参数。
LocationRequest对象用于从FusedLocationProviderApi请求位置更新的服务质量。FusedLocationProviderApi:与融合的位置提供程序进行交互的主要入口点。
这些方法必须与GoogleApiClient客户端结合使用,我们将在稍后介绍。com.google.android.gms.location.LocationListener:位置更改后,LocationListener接口用于从FusedLocationProviderApi接收通知。
如果使用" requestLocationUpdates(GoogleApiClient,LocationRequest,LocationListener)"或者" requestLocationUpdates(GoogleApiClient,LocationRequest,LocationListener,Looper)"方法向位置客户端注册了LocationListener,则调用onLocationChanged方法。
要使用Google Play的位置服务API,我们需要先调用GoogleAPIClient。
GoogleAPIClient
GoogleAPIClient允许我们使用一个调用来调用多个Google API。
以下是使用两个API调用GoogleAPIClient的示例代码段:Location Services和Drive API。
GoogleApiClient mGoogleApiClient = new GoogleApiClient.Builder(this)
.addApi(LocationServices.API)
.addApi(Drive.API)
.addScope(Drive.SCOPE_FILE)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this).build();
mGoogleApiClient.connect();
为addConnectionCallbacks和addOnConnectionFailedListener实现了GoogleApiClient.ConnectionCallbacks和GoogleApiClient.OnConnectionFailedListener。
建立与所有API的连接后,将调用属于GoogleApiClient.ConnectionCallbacks接口的onConnected()方法。
连接失败时,将调用属于GoogleApiClient.OnConnectionFailedListener接口的onConnectionFailed()。
代码
在build.gradle文件中添加以下依赖项。
compile'com.google.android.gms:play-services:9.8.0
在AndroidManifest.xml文件中添加以下权限。
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"
下面给出activity_main.xml。
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="https://schemas.android.com/apk/res/android"
xmlns:tools="https://schemas.android.com/tools"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.theitroad.fusedlocationprovider.MainActivity">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Current Location"
android:textAppearance="@style/TextAppearance.AppCompat.Display1"
android:layout_centerVertical="true"
android:id="@+id/current_location"
android:layout_centerHorizontal="true"
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:textSize="18sp"
android:id="@+id/latLng"
android:layout_below="@+id/current_location"
</RelativeLayout>
MainAcitivity.java在下面给出。
public class MainActivity extends AppCompatActivity implements GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener, LocationListener {
Location mLocation;
TextView latLng;
GoogleApiClient mGoogleApiClient;
private static final int PLAY_SERVICES_RESOLUTION_REQUEST = 9000;
private LocationRequest mLocationRequest;
private long UPDATE_INTERVAL = 15000; /* 15 secs */
private long FASTEST_INTERVAL = 5000; /* 5 secs */
private ArrayList permissionsToRequest;
private ArrayList permissionsRejected = new ArrayList();
private ArrayList permissions = new ArrayList();
private final static int ALL_PERMISSIONS_RESULT = 101;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
latLng = (TextView) findViewById(R.id.latLng);
permissions.add(ACCESS_FINE_LOCATION);
permissions.add(ACCESS_COARSE_LOCATION);
permissionsToRequest = findUnAskedPermissions(permissions);
//get the permissions we have asked for before but are not granted..
//we will store this in a global list to access later.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (permissionsToRequest.size() > 0)
requestPermissions(permissionsToRequest.toArray(new String[permissionsToRequest.size()]), ALL_PERMISSIONS_RESULT);
}
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addApi(LocationServices.API)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.build();
}
private ArrayList findUnAskedPermissions(ArrayList wanted) {
ArrayList result = new ArrayList();
for (String perm : wanted) {
if (!hasPermission(perm)) {
result.add(perm);
}
}
return result;
}
@Override
protected void onStart() {
super.onStart();
if (mGoogleApiClient != null) {
mGoogleApiClient.connect();
}
}
@Override
protected void onResume() {
super.onResume();
if (!checkPlayServices()) {
latLng.setText("Please install Google Play services.");
}
}
@Override
public void onConnected(@Nullable Bundle bundle) {
if (ActivityCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
//TODO: Consider calling
// ActivityCompat#requestPermissions
//here to request the missing permissions, and then overriding
// public void onRequestPermissionsResult(int requestCode, String[] permissions,
// int[] grantResults)
//to handle the case where the user grants the permission. See the documentation
//for ActivityCompat#requestPermissions for more details.
return;
}
mLocation = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
if(mLocation!=null)
{
latLng.setText("Latitude : "+mLocation.getLatitude()+" , Longitude : "+mLocation.getLongitude());
}
startLocationUpdates();
}
@Override
public void onConnectionSuspended(int i) {
}
@Override
public void onConnectionFailed(@NonNull ConnectionResult connectionResult) {
}
@Override
public void onLocationChanged(Location location) {
if(location!=null)
latLng.setText("Latitude : "+location.getLatitude()+" , Longitude : "+location.getLongitude());
}
private boolean checkPlayServices() {
GoogleApiAvailability apiAvailability = GoogleApiAvailability.getInstance();
int resultCode = apiAvailability.isGooglePlayServicesAvailable(this);
if (resultCode != ConnectionResult.SUCCESS) {
if (apiAvailability.isUserResolvableError(resultCode)) {
apiAvailability.getErrorDialog(this, resultCode, PLAY_SERVICES_RESOLUTION_REQUEST)
.show();
} else
finish();
return false;
}
return true;
}
protected void startLocationUpdates() {
mLocationRequest = new LocationRequest();
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
mLocationRequest.setInterval(UPDATE_INTERVAL);
mLocationRequest.setFastestInterval(FASTEST_INTERVAL);
if (ActivityCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
Toast.makeText(getApplicationContext(), "Enable Permissions", Toast.LENGTH_LONG).show();
}
LocationServices.FusedLocationApi.requestLocationUpdates(
mGoogleApiClient, mLocationRequest, this);
}
private boolean hasPermission(String permission) {
if (canMakeSmores()) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
return (checkSelfPermission(permission) == PackageManager.PERMISSION_GRANTED);
}
}
return true;
}
private boolean canMakeSmores() {
return (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP_MR1);
}
@TargetApi(Build.VERSION_CODES.M)
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
switch (requestCode) {
case ALL_PERMISSIONS_RESULT:
for (String perms : permissionsToRequest) {
if (!hasPermission(perms)) {
permissionsRejected.add(perms);
}
}
if (permissionsRejected.size() > 0) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (shouldShowRequestPermissionRationale(permissionsRejected.get(0))) {
showMessageOKCancel("These permissions are mandatory for the application. Please allow access.",
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
requestPermissions(permissionsRejected.toArray(new String[permissionsRejected.size()]), ALL_PERMISSIONS_RESULT);
}
}
});
return;
}
}
}
break;
}
}
private void showMessageOKCancel(String message, DialogInterface.OnClickListener okListener) {
new AlertDialog.Builder(MainActivity.this)
.setMessage(message)
.setPositiveButton("OK", okListener)
.setNegativeButton("Cancel", null)
.create()
.show();
}
@Override
protected void onDestroy() {
super.onDestroy();
stopLocationUpdates();
}
public void stopLocationUpdates()
{
if (mGoogleApiClient.isConnected()) {
LocationServices.FusedLocationApi
.removeLocationUpdates(mGoogleApiClient, this);
mGoogleApiClient.disconnect();
}
}
}
" mLocation = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);"用于从位置服务获取最近的已知位置。
以下是在genymotion模拟器上运行应用程序时的输出。
由于未安装Google Play服务,因此我们的模拟器无法获取位置。
我们来看看智能手机上的输出是什么样子。
上述应用程序中的纬度和经度文本每5-15秒更新一次。

