Android Location API可用于跟踪您的移动当前位置并在应用程序中显示。在本教程中,我们将开发一个以编程方式获取用户当前位置的应用程序。
Android位置接口
在我们的应用程序中,有两种方法可以获取用户的位置:
android.Location.LocationListener
:这是Android接口的一部分。 *com.google.android.gms.location.LocationListener
:它出现在Google Play服务API中。(我们将在下一个教程中研究这一点)
Android位置服务从Android API 1开始提供。Google官方推荐使用Google Play位置服务API。Android Location Services API仍用于为不支持Google Play服务的设备开发基于位置的应用程序。
位置监听器
LocationListener接口是Android Locations接口的一部分,用于在位置发生变化时接收来自LocationManager 的通知。** LocationManager** 类提供对系统位置服务的访问。LocationListener类需要实现以下方法。
- onLocationChanged(Location Location) :位置变更时调用。
- onProviderDisable(字符串提供者) :当用户关闭提供者时调用。
- onProviderEnabled(字符串提供者) :当用户开启提供者时调用。
- onStatusChanged(String Provider,int Status,Bundle Extras) :提供者状态改变时调用。
android.location
有两种获取位置数据的方式:
- LocationManager.GPS_PROVIDER :卫星定位。根据情况,此提供程序可能需要一段时间才能返回位置定位
- LocationManager.NETWORK_PROVIDER :根据附近基站和WiFi接入点的可用性确定位置。这比GPS_PROVIDER更快
在本教程中,我们将创建一个实现LocationListener类的服务,以通过GPS提供程序或网络提供程序接收定期位置更新。
Android Location API项目结构
项目由一个**
MainActivity.java
** 类和一个** LocationTrack.java
** Service类组成,该类展示了一个** Get Location** 和一个** LocationTrack.java
** Service类。
Android位置APICode
Activity_main.xml布局定义如下。
1<?xml version="1.0" encoding="utf-8"?>
2<RelativeLayout xmlns:android="https://schemas.android.com/apk/res/android"
3 xmlns:tools="https://schemas.android.com/tools"
4 android:id="@+id/activity_main"
5 android:layout_width="match_parent"
6 android:layout_height="match_parent"
7 android:paddingBottom="@dimen/activity_vertical_margin"
8 android:paddingLeft="@dimen/activity_horizontal_margin"
9 android:paddingRight="@dimen/activity_horizontal_margin"
10 android:paddingTop="@dimen/activity_vertical_margin"
11 tools:context="com.journaldev.gpslocationtracking.MainActivity">
12
13 <Button
14 android:layout_width="wrap_content"
15 android:layout_height="wrap_content"
16 android:id="@+id/btn"
17 android:layout_centerInParent="true"
18 android:text="GET LOCATION" />
19</RelativeLayout>
下面定义了MainActivity.java类。
1package com.journaldev.gpslocationtracking;
2
3import android.annotation.TargetApi;
4import android.content.DialogInterface;
5import android.content.pm.PackageManager;
6import android.os.Build;
7import android.support.v7.app.AlertDialog;
8import android.support.v7.app.AppCompatActivity;
9import android.os.Bundle;
10import android.util.Log;
11import android.view.View;
12import android.widget.Button;
13import android.widget.Toast;
14
15import java.util.ArrayList;
16
17import static android.Manifest.permission.ACCESS_COARSE_LOCATION;
18import static android.Manifest.permission.ACCESS_FINE_LOCATION;
19
20public class MainActivity extends AppCompatActivity {
21
22 private ArrayList permissionsToRequest;
23 private ArrayList permissionsRejected = new ArrayList();
24 private ArrayList permissions = new ArrayList();
25
26 private final static int ALL_PERMISSIONS_RESULT = 101;
27 LocationTrack locationTrack;
28
29 @Override
30 protected void onCreate(Bundle savedInstanceState) {
31 super.onCreate(savedInstanceState);
32 setContentView(R.layout.activity_main);
33
34 permissions.add(ACCESS_FINE_LOCATION);
35 permissions.add(ACCESS_COARSE_LOCATION);
36
37 permissionsToRequest = findUnAskedPermissions(permissions);
38 //get the permissions we have asked for before but are not granted..
39 //we will store this in a global list to access later.
40
41 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
42
43 if (permissionsToRequest.size() > 0)
44 requestPermissions(permissionsToRequest.toArray(new String[permissionsToRequest.size()]), ALL_PERMISSIONS_RESULT);
45 }
46
47 Button btn = (Button) findViewById(R.id.btn);
48
49 btn.setOnClickListener(new View.OnClickListener() {
50 @Override
51 public void onClick(View view) {
52
53 locationTrack = new LocationTrack(MainActivity.this);
54
55 if (locationTrack.canGetLocation()) {
56
57 double longitude = locationTrack.getLongitude();
58 double latitude = locationTrack.getLatitude();
59
60 Toast.makeText(getApplicationContext(), "Longitude:" + Double.toString(longitude) + "\nLatitude:" + Double.toString(latitude), Toast.LENGTH_SHORT).show();
61 } else {
62
63 locationTrack.showSettingsAlert();
64 }
65
66 }
67 });
68
69 }
70
71 private ArrayList findUnAskedPermissions(ArrayList wanted) {
72 ArrayList result = new ArrayList();
73
74 for (String perm : wanted) {
75 if (!hasPermission(perm)) {
76 result.add(perm);
77 }
78 }
79
80 return result;
81 }
82
83 private boolean hasPermission(String permission) {
84 if (canMakeSmores()) {
85 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
86 return (checkSelfPermission(permission) == PackageManager.PERMISSION_GRANTED);
87 }
88 }
89 return true;
90 }
91
92 private boolean canMakeSmores() {
93 return (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP_MR1);
94 }
95
96 @TargetApi(Build.VERSION_CODES.M)
97 @Override
98 public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
99
100 switch (requestCode) {
101
102 case ALL_PERMISSIONS_RESULT:
103 for (String perms : permissionsToRequest) {
104 if (!hasPermission(perms)) {
105 permissionsRejected.add(perms);
106 }
107 }
108
109 if (permissionsRejected.size() > 0) {
110
111 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
112 if (shouldShowRequestPermissionRationale(permissionsRejected.get(0))) {
113 showMessageOKCancel("These permissions are mandatory for the application. Please allow access.",
114 new DialogInterface.OnClickListener() {
115 @Override
116 public void onClick(DialogInterface dialog, int which) {
117 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
118 requestPermissions(permissionsRejected.toArray(new String[permissionsRejected.size()]), ALL_PERMISSIONS_RESULT);
119 }
120 }
121 });
122 return;
123 }
124 }
125
126 }
127
128 break;
129 }
130
131 }
132
133 private void showMessageOKCancel(String message, DialogInterface.OnClickListener okListener) {
134 new AlertDialog.Builder(MainActivity.this)
135 .setMessage(message)
136 .setPositiveButton("OK", okListener)
137 .setNegativeButton("Cancel", null)
138 .create()
139 .show();
140 }
141
142 @Override
143 protected void onDestroy() {
144 super.onDestroy();
145 locationTrack.stopListener();
146 }
147}
在上面的代码中,我们实现了在Android 6.0+设备中使用的运行时权限。我们在AndroidManifest.xml文件中添加了 ACCESS_FINE_LOCATION 和** ACCESS_COARSE_LOCATION** 权限。单击该按钮将调用LocationTrack.java服务类。如果在GPS提供程序的情况下返回的位置为NULL,则我们将从LocationTrack.java类中调用** showSettingsAlert()
** 方法,我们将很快看到。当Activity被销毁时,将调用** stopLocationTrack()
** 方法关闭位置更新。下面定义了** LocationTrack.java
** 类。
1public class LocationTrack extends Service implements LocationListener {
2
3 private final Context mContext;
4
5 boolean checkGPS = false;
6
7 boolean checkNetwork = false;
8
9 boolean canGetLocation = false;
10
11 Location loc;
12 double latitude;
13 double longitude;
14
15 private static final long MIN_DISTANCE_CHANGE_FOR_UPDATES = 10;
16
17 private static final long MIN_TIME_BW_UPDATES = 1000 * 60 * 1;
18 protected LocationManager locationManager;
19
20 public LocationTrack(Context mContext) {
21 this.mContext = mContext;
22 getLocation();
23 }
24
25 private Location getLocation() {
26
27 try {
28 locationManager = (LocationManager) mContext
29 .getSystemService(LOCATION_SERVICE);
30
31 // get GPS status
32 checkGPS = locationManager
33 .isProviderEnabled(LocationManager.GPS_PROVIDER);
34
35 // get network provider status
36 checkNetwork = locationManager
37 .isProviderEnabled(LocationManager.NETWORK_PROVIDER);
38
39 if (!checkGPS && !checkNetwork) {
40 Toast.makeText(mContext, "No Service Provider is available", Toast.LENGTH_SHORT).show();
41 } else {
42 this.canGetLocation = true;
43
44 // if GPS Enabled get lat/long using GPS Services
45 if (checkGPS) {
46
47 if (ActivityCompat.checkSelfPermission(mContext, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(mContext, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
48 // TODO: Consider calling
49 // ActivityCompat#requestPermissions
50 // here to request the missing permissions, and then overriding
51 // public void onRequestPermissionsResult(int requestCode, String[] permissions,
52 // int[] grantResults)
53 // to handle the case where the user grants the permission. See the documentation
54 // for ActivityCompat#requestPermissions for more details.
55 }
56 locationManager.requestLocationUpdates(
57 LocationManager.GPS_PROVIDER,
58 MIN_TIME_BW_UPDATES,
59 MIN_DISTANCE_CHANGE_FOR_UPDATES, this);
60 if (locationManager != null) {
61 loc = locationManager
62 .getLastKnownLocation(LocationManager.GPS_PROVIDER);
63 if (loc != null) {
64 latitude = loc.getLatitude();
65 longitude = loc.getLongitude();
66 }
67 }
68
69 }
70
71 /*if (checkNetwork) {
72
73 if (ActivityCompat.checkSelfPermission(mContext, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(mContext, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
74 // TODO: Consider calling
75 // ActivityCompat#requestPermissions
76 // here to request the missing permissions, and then overriding
77 // public void onRequestPermissionsResult(int requestCode, String[] permissions,
78 // int[] grantResults)
79 // to handle the case where the user grants the permission. See the documentation
80 // for ActivityCompat#requestPermissions for more details.
81 }
82 locationManager.requestLocationUpdates(
83 LocationManager.NETWORK_PROVIDER,
84 MIN_TIME_BW_UPDATES,
85 MIN_DISTANCE_CHANGE_FOR_UPDATES, this);
86
87 if (locationManager != null) {
88 loc = locationManager
89 .getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
90
91 }
92
93 if (loc != null) {
94 latitude = loc.getLatitude();
95 longitude = loc.getLongitude();
96 }
97 }*/
98
99 }
100
101 } catch (Exception e) {
102 e.printStackTrace();
103 }
104
105 return loc;
106 }
107
108 public double getLongitude() {
109 if (loc != null) {
110 longitude = loc.getLongitude();
111 }
112 return longitude;
113 }
114
115 public double getLatitude() {
116 if (loc != null) {
117 latitude = loc.getLatitude();
118 }
119 return latitude;
120 }
121
122 public boolean canGetLocation() {
123 return this.canGetLocation;
124 }
125
126 public void showSettingsAlert() {
127 AlertDialog.Builder alertDialog = new AlertDialog.Builder(mContext);
128
129 alertDialog.setTitle("GPS is not Enabled!");
130
131 alertDialog.setMessage("Do you want to turn on GPS?");
132
133 alertDialog.setPositiveButton("Yes", new DialogInterface.OnClickListener() {
134 public void onClick(DialogInterface dialog, int which) {
135 Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
136 mContext.startActivity(intent);
137 }
138 });
139
140 alertDialog.setNegativeButton("No", new DialogInterface.OnClickListener() {
141 public void onClick(DialogInterface dialog, int which) {
142 dialog.cancel();
143 }
144 });
145
146 alertDialog.show();
147 }
148
149 public void stopListener() {
150 if (locationManager != null) {
151
152 if (ActivityCompat.checkSelfPermission(mContext, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(mContext, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
153 // TODO: Consider calling
154 // ActivityCompat#requestPermissions
155 // here to request the missing permissions, and then overriding
156 // public void onRequestPermissionsResult(int requestCode, String[] permissions,
157 // int[] grantResults)
158 // to handle the case where the user grants the permission. See the documentation
159 // for ActivityCompat#requestPermissions for more details.
160 return;
161 }
162 locationManager.removeUpdates(LocationTrack.this);
163 }
164 }
165
166 @Override
167 public IBinder onBind(Intent intent) {
168 return null;
169 }
170
171 @Override
172 public void onLocationChanged(Location location) {
173
174 }
175
176 @Override
177 public void onStatusChanged(String s, int i, Bundle bundle) {
178
179 }
180
181 @Override
182 public void onProviderEnabled(String s) {
183
184 }
185
186 @Override
187 public void onProviderDisabled(String s) {
188
189 }
190}
从上面的代码中得出的一些推论是:
- 在上面的代码中,
isProviderEnabled(字符串提供者)
** 是在LocationManager对象上调用的,用于检查GPS/Network Provider是否开启。 - 如果未启用提供程序,我们将调用方法
showSettingsAlert()
** ,该方法会显示启用GPS的提示。 LocationManager类的*questLocationUpdate(字符串提供者,long minTime,Float minDistance,LocationListener Listener)
方法用于注册命名提供者定期通知的当前活动。 onLocationChanged
根据minTime和minDistance(以先到者为准)定期调用。- Location 类托管纬度和经度。要获取当前位置,需要使用以下代码片段。
1位置锁定=locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
2在上面的Location对象上,调用getter来存储纬度和经度的双重值。然后,这些双精度值将作为Toast消息在屏幕上禁用。
3* **若要停止位置更新,将在LocationManager实例上调用** emoveUpdate**方法。
4
5在仿真器上运行的上述应用程序的输出是:[](https://cdn.jsdelivr.net/gh/andsky/tutorials-images/spaces/2016/11/android-location-tracking-output-1.gif)我们的仿真器无法获取位置,因此它为lat/lng返回0.0。你可以连接你的智能手机,并在调试模式下运行该应用程序,以检查你的当前位置。要在模拟器中模拟GPS位置,我们可以从Android Studio传递固定的纬度和经度值。除了仿真器窗口外,您还可以看到选项列表。底部的那个(有三个点)是我们的扩展控制选项。打开它,然后发送一个虚拟位置。您的应用程序应该如下所示:[](https://cdn.jsdelivr.net/gh/andsky/tutorials-images/spaces/2016/11/android-location-tracking-output-2.gif)这将结束本教程。在后面的教程中,我们将使用Google Play服务来实现位置API。您可以通过下面的链接下载**Android GPSLocationTrackingProject** 。
6
7[下载安卓位置接口Project](https://journaldev.nyc3.digitaloceanspaces.com/android/GPSLocationTracking.zip)