Android 简明教程

Android - Location Based Services

这借助 Google Play services 成为可能,它使添加位置感知与对自动位置跟踪、地理围栏和活动识别的应用程序成为可能。

本教程向您展示如何在您的 APP 中使用位置服务来获取当前位置,获取定期位置更新、查找地址等。

The Location Object

Location 对象表示地理位置,该位置可能包括纬度、经度、时间戳以及其他信息,例如方位、高度和速度。以下是您可以使用位置对象来获取具体位置信息的重要方法 −

Sr.No.

Method & Description

1

float distanceTo(Location dest) 返回此位置和给定位置之间的近似距离(以米为单位)。

2

float getAccuracy() 获取此位置的预估精度(以米为单位)。

3

double getAltitude() 获取高度,如果可用,则以高于海平面的米为单位。

4

float getBearing() 获取方位(以度为单位)。

5

double getLatitude() 获取纬度,单位为度。

6

double getLongitude() 获取经度,单位为度。

7

float getSpeed() 如果可用,获取地面速度,单位为米/秒。

8

boolean hasAccuracy() 如果此位置具有精度,则为 True。

9

boolean hasAltitude() 如果此位置具有海拔,则为 True。

10

boolean hasBearing() 如果此位置具有方位,则为 True。

11

boolean hasSpeed() 如果此位置具有速度,则为 True。

12

void reset() 清除位置的内容。

13

void setAccuracy(float accuracy) 设置此位置的估计精度,单位为米。

14

void setAltitude(double altitude) 设置海拔,单位为米(海拔高度)。

15

void setBearing(float bearing) 设置方位,单位为度。

16

void setLatitude(double latitude) 设置纬度,单位为度。

17

void setLongitude(double longitude) 设置经度,单位为度。

18

void setSpeed(float speed) 设置地面速度,单位为米/秒。

19

String toString() 返回一个包含该对象简洁易读的描述的字符串。

Get the Current Location

若要获取当前位置,请创建一个 LocationClient 对象的位置客户端,使用 connect() 方法将其连接到定位服务,然后调用其 getLastLocation() 方法。此方法将以 Location 对象的形式返回最近的位置,其中包含纬度和经度坐标及如上所述的其他信息。要在活动中获得基于位置的功能,您需要实现两个接口 −

  1. GooglePlayServicesClient.ConnectionCallbacks

  2. GooglePlayServicesClient.OnConnectionFailedListener

这些接口提供以下重要的回调方法,您需要在活动类中实现 −

Sr.No.

Callback Methods & Description

1

abstract void onConnected(Bundle connectionHint) 当定位服务成功连接到定位客户端时,将调用此回调方法。您将使用 connect() 方法连接到定位客户端。

2

abstract void onDisconnected() 客户端断开连接时,将调用此回调方法。您将使用 disconnect() 方法从定位客户端断开连接。

3

abstract void onConnectionFailed(ConnectionResult result) 当客户端连接到服务时出现错误时会调用此回调方法。

Get the Updated Location

如果您愿意接收位置更新,那么除了上面提到的接口之外,您还需要实现 LocationListener 接口。此接口提供了以下回调方法,您需要在活动类中实现此方法 −

Sr.No.

Callback Method & Description

1

abstract void onLocationChanged(Location location) 此回调方法用于在位置发生更改时从 LocationClient 接收通知。

Location Quality of Service

LocationRequest 对象用于从 LocationClient 请求位置更新的服务质量 (QoS)。以下是有用的 setter 方法,您可以使用它们来处理 QoS。有等效的 getter 方法可用,您可以在 Android 官方文档中查看这些方法。

Sr.No.

Method & Description

1

setExpirationDuration(long millis) 设置此请求的持续时间(以毫秒为单位)。

2

setExpirationTime(long millis) 设置请求的过期时间(自启动以来经过的毫秒数)。

3

setFastestInterval(long millis) 显式设置位置更新的最快速间隔(以毫秒为单位)。

4

setInterval(long millis) 设置主动位置更新的所需间隔(以毫秒为单位)。

5

setNumUpdates(int numUpdates) 设置位置更新的次数。

6

setPriority(int priority) 设置请求的优先级。

现在,例如,如果您的应用程序需要高精度的,则它应该创建一个位置请求,其中 setPriority(int) 设置为 PRIORITY_HIGH_ACCURACY 和 setInterval(long) 设置为 5 秒。您还可以使用更大的间隔和/或其他优先级,例如 PRIORITY_LOW_POWER 来请求“城市”级别精度,或 PRIORITY_BALANCED_POWER_ACCURACY 来请求“街区”级别精度。

Displaying a Location Address

有了 Location 对象之后,您可以使用 Geocoder.getFromLocation() 方法获取给定纬度和经度的地址。此方法是同步的,并且可能需要很长时间才能完成其工作,因此您应该从 doInBackground() 类的方法中调用该方法。

AsyncTask 必须是子类才能使用,并且该子类将覆盖 doInBackground(Params…​) 方法以在后台执行任务,并且 onPostExecute(Result) 方法在后台计算完成并且显示结果时在 UI 线程上调用。AyncTask 中还提供了一个更重要的方法,即 execute(Params…​ params) ,此方法使用指定的参数执行该任务。

Example

以下示例以实际方式向您展示如何在应用程序中使用位置服务来获取当前位置及其等效地址等。

Create Android Application

Step

Description

1

您将使用 Android studio IDE 创建一个 Android 应用程序,并将其命名为 Tutorialspoint,并放在包 com.example.tutorialspoint7.myapplication 中。

2

添加 src/GPSTracker.java 文件并添加所需的代码。

3

修改 src/MainActivity.java 文件并按如下所示添加必要的代码以处理获取当前位置及其等效地址。

4

修改布局 XML 文件 res/layout/activity_main.xml 以添加所有 GUI 组件,其中包括三个按钮和两个文本视图,以显示位置/地址。

5

修改 res/values/strings.xml 以定义必需的常量值

6

修改 AndroidManifest.xml,如下所示

7

运行应用,以启动 Android 模拟器,并验证应用中已执行的更改。

以下是修改后的主活动文件内容 MainActivity.java

package com.example.tutorialspoint7.myapplication;

import android.Manifest;
import android.app.Activity;
import android.os.Bundle;
import android.support.v4.app.ActivityCompat;
import android.test.mock.MockPackageManager;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;

public class MainActivity extends Activity {

   Button btnShowLocation;
   private static final int REQUEST_CODE_PERMISSION = 2;
   String mPermission = Manifest.permission.ACCESS_FINE_LOCATION;

   // GPSTracker class
   GPSTracker gps;

   @Override
   public void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.activity_main);

      try {
         if (ActivityCompat.checkSelfPermission(this, mPermission)
            != MockPackageManager.PERMISSION_GRANTED) {

            ActivityCompat.requestPermissions(this, new String[]{mPermission},
               REQUEST_CODE_PERMISSION);

            // If any permission above not allowed by user, this condition will
               execute every time, else your else part will work
         }
      } catch (Exception e) {
         e.printStackTrace();
      }

      btnShowLocation = (Button) findViewById(R.id.button);

      // show location button click event
      btnShowLocation.setOnClickListener(new View.OnClickListener() {

         @Override
         public void onClick(View arg0) {
            // create class object
            gps = new GPSTracker(MainActivity.this);

            // check if GPS enabled
            if(gps.canGetLocation()){

               double latitude = gps.getLatitude();
               double longitude = gps.getLongitude();

               // \n is for new line
               Toast.makeText(getApplicationContext(), "Your Location is - \nLat: "
                  + latitude + "\nLong: " + longitude, Toast.LENGTH_LONG).show();
            }else{
               // can't get location
               // GPS or Network is not enabled
               // Ask user to enable GPS/network in settings
               gps.showSettingsAlert();
            }

         }
      });
   }
}

以下是已修改主活动文件 GPSTracker.java 的内容。

package com.example.tutorialspoint7.myapplication;

import android.app.AlertDialog;
import android.app.Service;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.os.IBinder;
import android.provider.Settings;
import android.util.Log;

public class GPSTracker extends Service implements LocationListener {

   private final Context mContext;

   // flag for GPS status
   boolean isGPSEnabled = false;

   // flag for network status
   boolean isNetworkEnabled = false;

   // flag for GPS status
   boolean canGetLocation = false;

   Location location; // location
   double latitude; // latitude
   double longitude; // longitude

   // The minimum distance to change Updates in meters
   private static final long MIN_DISTANCE_CHANGE_FOR_UPDATES = 10; // 10 meters

   // The minimum time between updates in milliseconds
   private static final long MIN_TIME_BW_UPDATES = 1000 * 60 * 1; // 1 minute

   // Declaring a Location Manager
   protected LocationManager locationManager;

   public GPSTracker(Context context) {
      this.mContext = context;
      getLocation();
   }

   public Location getLocation() {
      try {
         locationManager = (LocationManager) mContext.getSystemService(LOCATION_SERVICE);

         // getting GPS status
         isGPSEnabled = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);

         // getting network status
         isNetworkEnabled = locationManager
            .isProviderEnabled(LocationManager.NETWORK_PROVIDER);

         if (!isGPSEnabled && !isNetworkEnabled) {
            // no network provider is enabled
         } else {
            this.canGetLocation = true;
            // First get location from Network Provider
            if (isNetworkEnabled) {
               locationManager.requestLocationUpdates(
                  LocationManager.NETWORK_PROVIDER,
                  MIN_TIME_BW_UPDATES,
                  MIN_DISTANCE_CHANGE_FOR_UPDATES, this);

               Log.d("Network", "Network");
               if (locationManager != null) {
                  location = locationManager
                     .getLastKnownLocation(LocationManager.NETWORK_PROVIDER);

                  if (location != null) {
                     latitude = location.getLatitude();
                     longitude = location.getLongitude();
                  }
               }
            }

            // if GPS Enabled get lat/long using GPS Services
            if (isGPSEnabled) {
               if (location == null) {
                  locationManager.requestLocationUpdates(
                     LocationManager.GPS_PROVIDER,
                     MIN_TIME_BW_UPDATES,
                     MIN_DISTANCE_CHANGE_FOR_UPDATES, this);

                  Log.d("GPS Enabled", "GPS Enabled");
                  if (locationManager != null) {
                     location = locationManager
                        .getLastKnownLocation(LocationManager.GPS_PROVIDER);

                     if (location != null) {
                        latitude = location.getLatitude();
                        longitude = location.getLongitude();
                     }
                  }
               }
            }
         }

      } catch (Exception e) {
         e.printStackTrace();
      }

      return location;
   }

   /**
      * Stop using GPS listener
      * Calling this function will stop using GPS in your app
   * */

   public void stopUsingGPS(){
      if(locationManager != null){
         locationManager.removeUpdates(GPSTracker.this);
      }
   }

   /**
      * Function to get latitude
   * */

   public double getLatitude(){
      if(location != null){
         latitude = location.getLatitude();
      }

      // return latitude
      return latitude;
   }

   /**
      * Function to get longitude
   * */

   public double getLongitude(){
      if(location != null){
         longitude = location.getLongitude();
      }

      // return longitude
      return longitude;
   }

   /**
      * Function to check GPS/wifi enabled
      * @return boolean
   * */

   public boolean canGetLocation() {
      return this.canGetLocation;
   }

   /**
      * Function to show settings alert dialog
      * On pressing Settings button will lauch Settings Options
   * */

   public void showSettingsAlert(){
      AlertDialog.Builder alertDialog = new AlertDialog.Builder(mContext);

      // Setting Dialog Title
      alertDialog.setTitle("GPS is settings");

      // Setting Dialog Message
      alertDialog.setMessage("GPS is not enabled. Do you want to go to settings menu?");

      // On pressing Settings button
      alertDialog.setPositiveButton("Settings", new DialogInterface.OnClickListener() {
         public void onClick(DialogInterface dialog,int which) {
            Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
            mContext.startActivity(intent);
         }
      });

      // on pressing cancel button
      alertDialog.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
         public void onClick(DialogInterface dialog, int which) {
            dialog.cancel();
         }
      });

      // Showing Alert Message
      alertDialog.show();
   }

   @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;
   }
}

以下是 res/layout/activity_main.xml 文件的内容——

<?xml version = "1.0" encoding = "utf-8"?>
<LinearLayout xmlns:android = "http://schemas.android.com/apk/res/android"
   android:layout_width = "fill_parent"
   android:layout_height = "fill_parent"
   android:orientation = "vertical" >


   <Button
      android:id = "@+id/button"
      android:layout_width = "fill_parent"
      android:layout_height = "wrap_content"
      android:text = "getlocation"/>

</LinearLayout>

以下是 res/values/strings.xml 的内容,用于定义两个新常量——

<?xml version = "1.0" encoding = "utf-8"?>
<resources>
   <string name = "app_name">Tutorialspoint</string>
</resources>

以下是 AndroidManifest.xml 的默认内容−

<?xml version = "1.0" encoding = "utf-8"?>
<manifest xmlns:android = "http://schemas.android.com/apk/res/android"
   package = "com.example.tutorialspoint7.myapplication">
   <uses-permission android:name = "android.permission.ACCESS_FINE_LOCATION" />
   <uses-permission android:name = "android.permission.INTERNET" />
   <application
      android:allowBackup = "true"
      android:icon = "@mipmap/ic_launcher"
      android:label = "@string/app_name"
      android:supportsRtl = "true"
      android:theme = "@style/AppTheme">

      <activity android:name = ".MainActivity">
         <intent-filter>
            <action android:name = "android.intent.action.MAIN" />

            <category android:name = "android.intent.category.LAUNCHER" />
         </intent-filter>
      </activity>
   </application>

</manifest>

我们尝试运行您的 Tutorialspoint 应用程序。我假设,您已将您的安卓移动设备连接到您的电脑。要从 Android Studio 运行应用程序,请打开您项目的某个活动文件,然后从工具栏中点击运行图标。在启动您的应用程序之前,Android Studio 安装程序将显示以下窗口,供您选择运行安卓应用程序的位置。

location3

现在查看位置,点击获取位置按钮将显示位置信息,如下所示:

location4