Android Location API can be used to track your mobile current location and show in the app. In this tutorial, we’ll develop an application that fetches the user’s current location programmatically.
Android Location API可用于跟踪您的移动设备当前位置并在应用程序中显示。 在本教程中,我们将开发一个应用程序,该程序以编程方式获取用户的当前位置。
Android Location API (Android Location API)
There are two ways to get a users location in our application:
有两种方法可以在应用程序中获取用户位置:
android.location.LocationListener
: This is a part of the Android API.android.location.LocationListener
:这是Android API的一部分。com.google.android.gms.location.LocationListener
: This is present in the Google Play Services API. (We’ll look into this in the next tutorial)com.google.android.gms.location.LocationListener
:它存在于Google Play服务API中。 (我们将在下一个教程中对此进行研究)
Android Location Services is available since Android API 1.
Google officially recommends using Google Play Location Service APIs. Android Location Services API is still used to develop location-based apps for devices that don’t support Google Play Services.
自Android API 1起即可使用Android定位服务。
Google正式建议使用Google Play定位服务API。 Android Location Services API仍用于为不支持Google Play服务的设备开发基于位置的应用。
LocationListener (LocationListener)
The LocationListener interface, which is part of the Android Locations API is used for receiving notifications from the LocationManager when the location has changed. The LocationManager class provides access to the systems location services.
LocationListener接口是Android Locations API的一部分,用于在位置更改后从LocationManager接收通知。 LocationManager类提供对系统位置服务的访问。
The LocationListener class needs to implement the following methods.
LocationListener类需要实现以下方法。
- onLocationChanged(Location location) : Called when the location has changed. onLocationChanged(位置位置) :位置更改时调用。
- onProviderDisabled(String provider) : Called when the provider is disabled by the user. onProviderDisabled(String provider) :当用户禁用提供程序时调用。
- onProviderEnabled(String provider) : Called when the provider is enabled by the user. onProviderEnabled(String provider) :当用户启用了提供程序时调用。
- onStatusChanged(String provider, int status, Bundle extras) : Called when the provider status changes. onStatusChanged(String provider,int status,Bundle extras) :当提供者状态更改时调用。
The android.location
has two means of acquiring location data:
android.location
有两种获取位置数据的方法:
- LocationManager.GPS_PROVIDER: Determines location using satellites. Depending on the conditions, this provider may take a while to return a location fix LocationManager.GPS_PROVIDER :使用卫星确定位置。 根据条件,此提供商可能需要一段时间才能返回位置信息
- LocationManager.NETWORK_PROVIDER: Determines location based on the availability of nearby cell towers and WiFi access points. This is faster than GPS_PROVIDER LocationManager.NETWORK_PROVIDER :根据附近的手机信号塔和WiFi接入点的可用性来确定位置。 这比GPS_PROVIDER快
In this tutorial, we’ll create a Service that implements the LocationListener class to receive periodic location updates via GPS Providers or Network Providers.
在本教程中,我们将创建一个服务,该服务实现LocationListener类,以通过GPS提供商或网络提供商定期接收位置更新。
Android Location API项目结构 (Android Location API Project Structure)
The project consists of a MainActivity.java
class which displays a Get Location and a LocationTrack.java
Service class.
该项目包含一个MainActivity.java
类,该类显示一个Get Location和一个LocationTrack.java
Service类。
Android Location APICode ( Android Location APICode)
The activity_main.xml layout is defined below.
下面定义了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.journaldev.gpslocationtracking.MainActivity">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/btn"
android:layout_centerInParent="true"
android:text="GET LOCATION" />
</RelativeLayout>
The MainActivity.java class is defined below.
MainActivity.java类在下面定义。
package com.journaldev.gpslocationtracking;
import android.annotation.TargetApi;
import android.content.DialogInterface;
import android.content.pm.PackageManager;
import android.os.Build;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
import java.util.ArrayList;
import static android.Manifest.permission.ACCESS_COARSE_LOCATION;
import static android.Manifest.permission.ACCESS_FINE_LOCATION;
public class MainActivity extends AppCompatActivity {
private ArrayList permissionsToRequest;
private ArrayList permissionsRejected = new ArrayList();
private ArrayList permissions = new ArrayList();
private final static int ALL_PERMISSIONS_RESULT = 101;
LocationTrack locationTrack;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
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);
}
Button btn = (Button) findViewById(R.id.btn);
btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
locationTrack = new LocationTrack(MainActivity.this);
if (locationTrack.canGetLocation()) {
double longitude = locationTrack.getLongitude();
double latitude = locationTrack.getLatitude();
Toast.makeText(getApplicationContext(), "Longitude:" + Double.toString(longitude) + "\nLatitude:" + Double.toString(latitude), Toast.LENGTH_SHORT).show();
} else {
locationTrack.showSettingsAlert();
}
}
});
}
private ArrayList findUnAskedPermissions(ArrayList wanted) {
ArrayList result = new ArrayList();
for (String perm : wanted) {
if (!hasPermission(perm)) {
result.add(perm);
}
}
return result;
}
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();
locationTrack.stopListener();
}
}
In the above code, we’re implementing runtime permissions that are used in Android 6.0+ devices.
We’ve added the ACCESS_FINE_LOCATION and ACCESS_COARSE_LOCATION permissions in the AndroidManifest.xml file.
Clicking the button invokes the LocationTrack.java service class. If the location returned is NULL in the case of GPS Provider, we call the showSettingsAlert()
method from the LocationTrack.java class that we’ll be seeing shortly. When the activity is destroyed stopLocationTrack()
method is called to turn off the location updates.
在上面的代码中,我们正在实现Android 6.0+设备中使用的运行时权限。
我们已经在AndroidManifest.xml文件中添加了ACCESS_FINE_LOCATION和ACCESS_COARSE_LOCATION权限。
单击按钮将调用LocationTrack.java服务类。 如果在GPS Provider的情况下返回的位置为NULL, showSettingsAlert()
不久将要看到的LocationTrack.java类中调用showSettingsAlert()
方法。 活动销毁后,将调用stopLocationTrack()
方法关闭位置更新。
The LocationTrack.java
class is defined below.
LocationTrack.java
类在下面定义。
public class LocationTrack extends Service implements LocationListener {
private final Context mContext;
boolean checkGPS = false;
boolean checkNetwork = false;
boolean canGetLocation = false;
Location loc;
double latitude;
double longitude;
private static final long MIN_DISTANCE_CHANGE_FOR_UPDATES = 10;
private static final long MIN_TIME_BW_UPDATES = 1000 * 60 * 1;
protected LocationManager locationManager;
public LocationTrack(Context mContext) {
this.mContext = mContext;
getLocation();
}
private Location getLocation() {
try {
locationManager = (LocationManager) mContext
.getSystemService(LOCATION_SERVICE);
// get GPS status
checkGPS = locationManager
.isProviderEnabled(LocationManager.GPS_PROVIDER);
// get network provider status
checkNetwork = locationManager
.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
if (!checkGPS && !checkNetwork) {
Toast.makeText(mContext, "No Service Provider is available", Toast.LENGTH_SHORT).show();
} else {
this.canGetLocation = true;
// if GPS Enabled get lat/long using GPS Services
if (checkGPS) {
if (ActivityCompat.checkSelfPermission(mContext, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(mContext, 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.
}
locationManager.requestLocationUpdates(
LocationManager.GPS_PROVIDER,
MIN_TIME_BW_UPDATES,
MIN_DISTANCE_CHANGE_FOR_UPDATES, this);
if (locationManager != null) {
loc = locationManager
.getLastKnownLocation(LocationManager.GPS_PROVIDER);
if (loc != null) {
latitude = loc.getLatitude();
longitude = loc.getLongitude();
}
}
}
/*if (checkNetwork) {
if (ActivityCompat.checkSelfPermission(mContext, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(mContext, 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.
}
locationManager.requestLocationUpdates(
LocationManager.NETWORK_PROVIDER,
MIN_TIME_BW_UPDATES,
MIN_DISTANCE_CHANGE_FOR_UPDATES, this);
if (locationManager != null) {
loc = locationManager
.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
}
if (loc != null) {
latitude = loc.getLatitude();
longitude = loc.getLongitude();
}
}*/
}
} catch (Exception e) {
e.printStackTrace();
}
return loc;
}
public double getLongitude() {
if (loc != null) {
longitude = loc.getLongitude();
}
return longitude;
}
public double getLatitude() {
if (loc != null) {
latitude = loc.getLatitude();
}
return latitude;
}
public boolean canGetLocation() {
return this.canGetLocation;
}
public void showSettingsAlert() {
AlertDialog.Builder alertDialog = new AlertDialog.Builder(mContext);
alertDialog.setTitle("GPS is not Enabled!");
alertDialog.setMessage("Do you want to turn on GPS?");
alertDialog.setPositiveButton("Yes", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
mContext.startActivity(intent);
}
});
alertDialog.setNegativeButton("No", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
dialog.cancel();
}
});
alertDialog.show();
}
public void stopListener() {
if (locationManager != null) {
if (ActivityCompat.checkSelfPermission(mContext, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(mContext, 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;
}
locationManager.removeUpdates(LocationTrack.this);
}
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onLocationChanged(Location location) {
}
@Override
public void onStatusChanged(String s, int i, Bundle bundle) {
}
@Override
public void onProviderEnabled(String s) {
}
@Override
public void onProviderDisabled(String s) {
}
}
Few inferences drawn from the above code are:
从以上代码得出的推论很少是:
- In the above code
isProviderEnabled(String provider)
is called upon the locationManager object and is used to check whether GPS/Network Provider is enabled or not. 在上面的代码中,对locationManager对象调用了isProviderEnabled(String provider)
,用于检查是否启用了GPS / Network Provider。 - If the Providers aren’t enabled we’re calling the method
showSettingsAlert()
that shows a prompt to enable GPS. 如果未启用提供者,我们将调用showSettingsAlert()
方法,该方法显示启用GPS的提示。 requestLocationUpdates(String provider, long minTime, float minDistance, LocationListener listener)
method of the LocationManager class is used to register the current activity to be notified periodically by the named provider. LocationManager类的requestLocationUpdates(String provider, long minTime, float minDistance, LocationListener listener)
方法用于注册要由命名提供者定期通知的当前活动。onLocationChanged
is invoked periodically based upon the minTime and minDistance, whichever comes first.onLocationChanged
调用定期于minTime和minDistance才会,以先到者为准为主。- Location class hosts the latitude and longitude.
To get the current location the following code snippet is used.Location loc = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
On the above Location object, getters are called to store the double values of latitude and longitude. These double values are then disabled as a Toast message on the screen.
位置类别主持纬度和经度。
要获取当前位置,请使用以下代码段。在上面的Location对象上,调用getter来存储纬度和经度的双精度值。 然后,将这些双精度值作为Toast消息在屏幕上禁用。
- To stop location updates removeUpdates method is called on the LocationManager instance. 要停止位置更新,请在LocationManager实例上调用removeUpdates方法。
The output of the above application in action on an emulator is:
Our emulators can’t fetch locations, hence it’s returning 0.0 for lat/lng. You can connect your smartphone and run the application in debug mode to check your current location.
To emulate GPS Locations in an emulator we can pass fixed Latitude and Longitude values from Android Studio. Besides the emulator window, you can see a list of options. The one at the bottom (which has three dots) is our Extended Controls options. Open that and send a dummy location. Your application should look like this:
我们的仿真器无法提取位置,因此纬度/经度返回0.0。 您可以连接智能手机并以调试模式运行该应用程序以检查您的当前位置。
要在模拟器中模拟GPS位置,我们可以从Android Studio中传递固定的纬度和经度值。 除了模拟器窗口,您还可以看到选项列表。 底部的一个(有三个点)是我们的扩展控件选项。 打开该地址并发送一个虚拟位置。 您的应用程序应如下所示:
This brings an end to this tutorial. We’ll be implementing Location API using Google Play Services in a later tutorial. You can download the Android GPSLocationTracking Project from the link below.
本教程到此结束。 在稍后的教程中,我们将使用Google Play服务实现Location API。 您可以从下面的链接下载Android GPSLocationTracking项目 。
翻译自: https://www.journaldev.com/13325/android-location-api-tracking-gps