How to use GPS in Android


How to use GPS to obtain location information in Android? A small Demo is as follows

Introduction to GPS

Gobal Positioning System, Global Positioning System, is a high-precision radio navigation positioning system based on artificial earth satellites developed by the United States in the 1970s. It can provide accurate geographic location anywhere in the world and in near-Earth space. , vehicle speed and accurate time information; it is a new generation of satellite navigation and positioning system with all-round real-time three-dimensional navigation and positioning functions in sea, land and air.

The positioning system used in China is the Beidou Navigation Satellite System, or BDS for short. BDS, GPS, Russia's GLONASS, and the European Union's GALILEO are suppliers identified by the United Nations Satellite Navigation Commission.

The positioning function of mobile phones is widely used. In this chapter, we will learn the application development of GPS.

Common APIs for GPS

The GPS system consists of three parts, the satellite space part, the ground monitoring part and the user equipment part.

For the Android machine, it is the part of the user equipment and the receiver of the GPS positioning system, that is to say, GPS positioning requires hardware to support the GPS function. For Android developers, GPS applications can be developed through some methods of the three APIs, LocationManager, LocationProvider, and Location.

The LocationManger object of the program cannot be created directly, but must be obtained through the Context.getSystemService method

LocationManager locationManager= (LocationManager) getSystemService(Context.LOCATION_SERVICE);
List<String> allProviders = locationManager.getAllProviders();

By asking chatGPT, such a form is sorted out. The method and function of LocationManger are as follows:

method name

return value

effect

getLastKnownLocation(String provider)

Location

Get the latest location information of the specified provider

requestLocationUpdates(String provider, long minTime, float minDistance, LocationListener listener)

void

Register a location listener to get location updates from the provider. The parameters minTime and minDistance represent the minimum time interval and minimum distance interval of location update respectively

removeUpdates(LocationListener listener)

void

Unregister the location listener

isProviderEnabled(String provider)

boolean

Determine whether the specified provider is available

addProximityAlert(double latitude, double longitude, float radius, long expiration, PendingIntent intent)

void

Register a "geofence" that triggers an intent when the device enters a circular area with a specified radius

removeProximityAlert(PendingIntent intent)

void

Cancellation of "geofence" registration

When using LocationManager, you need to apply for appropriate permissions, such as ACCESS_FINE_LOCATION or ACCESS_COARSE_LOCATION permissions.

Another API is LocationProvider, which is not a class in Android, but an abstract class in the Android system, which defines the standard interface of the location provider, and its implementation class is used to provide location information. The implementation class of LocationProvider can be obtained through the system service LocationManager. When an application requests to obtain location information, LocationManager will select an appropriate location provider to obtain location information, and select different location providers according to different needs.

method name

return value

effect

getName()

String

Get the name of the location provider (locationProvider)

getAccuracy()

int

Get the precision of this location provider

getPowerRequirement()

int

Get the battery consumption of this location provider

hasMonetaryCost()

boolean

Determine whether the location provider needs to pay a fee

requiresCell()

boolean

Determine whether the location provider needs to use the mobile network

requiresNetwork()

boolean

Determine whether the location provider needs to use the data network

requiresSatellite()

boolean

Determine whether the location provider needs to use satellites

supportsAltitude()

boolean

Determine whether the location provider supports altitude information

supportsBearing()

boolean

Determine whether the location provider supports direction information

supportsSpeed()

boolean

Determine whether the location provider supports speed information

Another API is Location, which is a class used to represent location information in Android, which includes location information such as longitude, latitude, altitude, speed, and direction. The Location object is provided by the LocationProvider, and the LocationManager is responsible for obtaining the location information provided by the LocationProvider, packaging it into a Location object, and then providing it to the application. Methods as below:

method name

return value

effect

getLatitude()

double

Get the latitude of the location

getLongitude()

double

Get the longitude of the location

getAltitude()

double

Get the altitude of the location

getAccuracy()

float

Get the precision of this position

getBearing()

float

Get directions to this location

getSpeed()

float

Get the velocity of the position

getTime()

long

Get the timestamp of the location information

hasAccuracy()

boolean

Determine whether the location information contains accuracy information

hasAltitude()

boolean

Determine whether the location information contains altitude information

hasBearing()

boolean

Determine whether the location information contains direction information

hasSpeed()

boolean

Determine whether the position information contains speed information

It should be noted that a null value may appear when obtaining a Location object, so it is necessary to make a non-null judgment before using the Location object. In addition, obtaining location information requires applying for appropriate permissions, such as ACCESS_FINE_LOCATION or ACCESS_COARSE_LOCATION permissions.

The above three APIs are the three core APIs supported by Android GPS positioning. The steps to use are as follows:

1 Get the LocationManger object of the system.

2 使用LocationManger,通过指定的locationProvider来获取定位信息,定位信息由Location表示。

3 从Location对象中获取定位信息。

locationProvider

写一个简单的demo来获取当前系统所有的locationProvider

public class MainActivity extends AppCompatActivity {
    private static final String TAG = "MainActivity";

    private ListView listView;
    private LocationManager locationManager;

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

        listView = findViewById(R.id.list);
        locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);

        //获取所有的locationProvider名称
        List<String> allProviders = locationManager.getAllProviders();
        ArrayAdapter adapter=new ArrayAdapter(this, android.R.layout.simple_list_item_1,allProviders);
        listView.setAdapter(adapter);
    }
}

在真机上运行可以看到该系统上有如下四个LocationProvider

移动端通常通过WIFI、GPS、基站这三种方式来定位设备。

以下这四种provider分别来介绍一下

    public static final String NETWORK_PROVIDER = "network";
    public static final String GPS_PROVIDER = "gps";
    public static final String PASSIVE_PROVIDER = "passive";
    public static final String FUSED_PROVIDER = "fused";

NETWORK_PROVIDER:通过移动网络的基站或者 Wi-Fi 来获取地理位置;优点:只要有网络,就可以快速定位,室内室外都可;缺点:精确度不高;

GPS_PROVIDER:通过 GPS 来获取地理位置的经纬度信息;优点:获取地理位置信息精确度高;缺点:只能在户外使用,获取经纬度信息耗时,耗电;

PASSIVE_PROVIDER:被动接收更新地理位置信息,而不用自己请求地理位置信息。

PASSIVE_PROVIDER 返回的位置是通过其他 providers 产生的,可以查询 getProvider() 方法决定位置更新的由来,需要 ACCESS_FINE_LOCATION 权限,但是如果未启用 GPS,则此 provider 可能只返回粗略位置匹配;

FUSED_PROVIDER:已经被废弃了

通过名称获取指定的locationProvider

LocationProvider provider = locationManager.getProvider(LocationManager.GPS_PROVIDER);

使用GPS获取位置信息

代码如下:

public class MainActivity extends AppCompatActivity {
    private static final String TAG = "MainActivity";

    private LocationManager locationManager;
    private TextView showInfo;

    @RequiresApi(api = Build.VERSION_CODES.M)
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        showInfo = findViewById(R.id.show_location);
        requestPermissions(new String[]{Manifest.permission.ACCESS_FINE_LOCATION},0x123);
    }

    private void updateView(Location location) {
        if (location != null) {
            Log.d(TAG, "updateView: 222");
            String res = "实时位置:\n" +
                    "经度:" + location.getLongitude() +
                    "\n纬度:" + location.getLatitude() +
                    "\n高度:" + location.getAltitude() +
                    "\n速度:" + location.getSpeed()
                    + "\n方向:" + location.getBearing();
            showInfo.setText(res);
        } else {
            Log.d(TAG, "updateView: 111");
            showInfo.setText("");
        }
    }
    @SuppressLint("MissingPermission")
    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        if (requestCode == 0x123 && grantResults.length == 1 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
            //创建locationManger对象
            locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
            //获取最新的定位信息
            Location lastKnownLocation = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
            updateView(lastKnownLocation);
            //每隔三秒获取一次GPS信息
            locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 3000, 8f, new LocationListener() {
                @Override
                public void onLocationChanged(@NonNull Location location) {
                    updateView(location);
                }
            });
        }
    }
}

这里代码也很简单,我布局文件只写了一个textView来展示经纬度信息,首先在onCreate方法里动态申请权限。在Android6.0以上不仅仅要在声明文件里静态注册,还有动态申请,否则会出现安全异常。然后就是一个更新UI的方法,通过传入的location获取经纬度高度等信息。选择完获取权限后,会执行onRequestPermissionsResult回调函数,然后就是获取定位信息更新UI。

最后需要在声明文件里静态注册权限。

<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>

我获取到的是北京市内某地区的经纬度,把该程序和地图功能结合,就能反映出该经纬度在地图上的具体位置,即可开发出GPS导航系统。

室内WIFI定位

室内WIFI定位主要根据WIFI路由器所在的位置进行定位,主要应用于室内较小的空间的精准定位。

Android 9 添加了WiFi 室内定义功能(RTT),以下内容来自 developer.android.com

Android 9 添加了对 IEEE 802.11mc Wi-Fi 协议(也称为 Wi-Fi Round-Trip-Time (RTT))的平台支持,从而让您的应用可以利用室内定位功能。
在运行 Android 9 且具有硬件支持的设备上,应用可以使用 RTT API 来测量与附近支持 RTT 的 Wi-Fi 接入点 (AP) 的距离。 设备必须已启用位置服务并开启 Wi-Fi 扫描(在 Settings > Location 下),同时您的应用必须具有 ACCESS_FINE_LOCATION 权限。

设备无需连接到接入点即可使用 RTT。 为了保护隐私,只有手机可以确定与接入点的距离;接入点无此信息。

如果您的设备测量与 3 个或更多接入点的距离,您可以使用一个多点定位算法来预估与这些测量值最相符的设备位置。 结果通常精准至 1 至 2 米。

室内WIFI定位的管理器是WifiRttManager,获取方式如下,由于在Android9后才增加该功能,所以需要先判断。

if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.P) {
    WifiRttManager wifiRttManager= (WifiRttManager) getSystemService(Context.WIFI_RTT_RANGING_SERVICE);
}

获取到wifirttmanger对象后,可以用startRanging开始定位,该方法里有三个参数。

startRanging(@NonNull RangingRequest request, @NonNull Executor executor, @NonNull RangingResultCallback callback)

RangingRequest:该参数代表一个定位请求,该参数管理本次定位是基于哪个WIFI节点进行访问的

Executor:创建一个新的线程来执行WIFI定位,避免阻塞UI线程。

RangingResultCallback:定位成功或失败的时候触发该对象内的特定方法

写一个具体的案例来实现室内WIFI定位,代码如下:

public class MainActivity extends AppCompatActivity {
    private static final String TAG = "MainActivity";
    WifiRttManager mWifiRttManager;

    //定义监听WIFI状态改变的BroadcastReceiver
    public class WIfiChangeReceiver extends BroadcastReceiver {

        @Override
        public void onReceive(Context context, Intent intent) {
            if (WifiManager.SCAN_RESULTS_AVAILABLE_ACTION.equals(intent.getAction())) {
                //开始执行wifi定位
                startWifiLoc();
            }
        }

    }


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

        //定义一个监听网络状态的改变 WIFI状态改变的intentFilter
        IntentFilter wifiFilter = new IntentFilter();
        wifiFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
        wifiFilter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
        wifiFilter.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
        registerReceiver(new WIfiChangeReceiver(), wifiFilter);
    }

    @SuppressLint("MissingPermission")
    private void startWifiLoc() {
        //获取wifi管理器
        WifiManager wifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE);
        //判断是否支持室内wifi定位功能
        boolean hasRtt = getPackageManager().hasSystemFeature(PackageManager.FEATURE_WIFI_RTT);
        Log.d(TAG, "startWifiLoc: 是否具有室内WIFI定位功能:" + hasRtt);
        //Android版本大于9才能使用
        if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
            //获取室内WiFi定位管理器
            mWifiRttManager = (WifiRttManager) getSystemService(Context.WIFI_RTT_RANGING_SERVICE);
            RangingRequest request = new RangingRequest.Builder()
                    .addAccessPoints(wifiManager.getScanResults())//添加WiFi扫描结果
                    .build();//创建RangingRequest对象
            Log.d(TAG, "startWifiLoc: request:"+request);
            //开始请求执行室内WIFI定位
            mWifiRttManager.startRanging(request, Executors.newCachedThreadPool(), new RangingResultCallback() {
                @Override
                public void onRangingFailure(int i) {
                    //WIFI定位出错执行的方法
                    Log.d(TAG, "onRangingFailure:错误码是: "+i);
                }

                @Override
                public void onRangingResults(@NonNull List<RangingResult> list) {
                    //室内WiFi定位返回结果时触发
                    for (RangingResult rr : list){
                        Log.d(TAG, "onRangingResults:与 "+rr.getMacAddress()+" WIFI的距离是:"+rr.getDistanceMm());
                    }
                }
            });
        }
    }

}

运行后报错了

 查询了一下原因是我设备硬件不支持WIFIRTT功能。

总结WIFI定位的步骤:

1 获取WifiRttManger对象

2 通过RangingRequest.Builder来创建对象,创建之前应该先添加WiFi扫描得到WiFi访问点的信息

3 调用WifiRttManger对象的startRanging方法

近距离警报

之前学习的API方法中有一个函数:

addProximityAlert(double latitude, double longitude, float radius, long expiration, PendingIntent intent)

代码:

public class MainActivity extends AppCompatActivity {
    private static final String TAG = "MainActivity";

    private LocationManager locationManager;

    @RequiresApi(api = Build.VERSION_CODES.M)
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        requestPermissions(new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, 0x123);

    }


    @SuppressLint("MissingPermission")
    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        if (requestCode == 0x123 && grantResults.length == 1 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
            locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
            //定义靠近点的经纬度信息
            double lon = 116.00;
            double lat = 46.00;
            float radius = 500F; //定义半径500M
            Intent intent = new Intent(this, ProxAlertReciever.class);
            //将intent封装成pendingIntent
            PendingIntent pendingIntent = PendingIntent.getBroadcast(this, -1, intent, 0);
            //添加临近警告
            locationManager.addProximityAlert(lat, lon, radius, -1, pendingIntent);
        }
    }
}

注册一个广播监听变化:

public class ProxAlertReciever extends BroadcastReceiver {
    private static final String TAG = "ProxAlertReciever";

    @Override
    public void onReceive(Context context, Intent intent) {
       boolean isEnter= intent.getBooleanExtra(LocationManager.KEY_PROXIMITY_ENTERING,false);
       if (isEnter){
           //靠近提示
           Log.d(TAG, "onReceive: 快靠近了!!");
       }else {
           Log.d(TAG, "onReceive: 离开了!!");
       }
    }
}

至此 Android中的GPS的就讲完了,想开发出具体的导航系统还要结合地图功能。

Guess you like

Origin blog.csdn.net/m0_56366502/article/details/130512358
Recommended