Android中原生GPS的使用

说到做手机定位,大家想到的肯定是高德地图或者是百度地图,因为这些位置服务商可以根据我们返回的基站数据,WIFI数据,以及我们GPS的定位,来确定我们更加精确的位置信息。不过其中的GPS定位,其实Android原生系统中就带着一套。虽然我们多数时候都不会直接用它,但作为一个严谨的开发者,我们有必要进行相应的了解。另外,在一些特殊环境下,比如专属设备中,专属网络中,可能我们并不能访问到三方网站或者接入三方SDK,这时候就需要原生GPS来进行定位操作了。

下面我从相关定位工具和示例代码两块对GPS定位进行介绍。

1.相关工具介绍

<1>定位条件器Criteria

定位条件器用于设置定位的前提条件,比如精度、速度、海拔、方位等信息,有以下5个常用参数。

  • setAccuracy:设置定位精度。有两个取值,Criteria.ACCURACY_FINE表示精度高,Criteria.ACCURACY_COARSE表示精度低。
  • setSpeedAccuracy:设置速度精确度。速度精确度的取值见表1。
表1
Criteria类的速度精确度 说明
ACCURACY_HIGH 精度高,误差小于100米
ACCURACY_MEDIUM 精度中等,误差在100米到500米之间
ACCURACY_LOW 精度低,误差大于500米
  • setAltitudeRequired:设置是否需要海拔信息。取值true表示需要,false表示不需要。
  • setBearingRequired:设置是否需要方位信息。取值true表示需要,false表示不需要。
  • setCostAllowed:设置是否允许运营商收费。取值true表示允许,false表示不允许。
  • setPowerRequirement:这是对电源的需求。有3个取值,Criteria.POWER_LOW表示耗电低,Criteria.POWER_MEDIUM表示耗电中等,Criteria.POWER_HIGH表示好点高。

<2>定位管理器LocationManager

定位管理器用于获取定位信息的提供者、设置监听器,并获取最近一次的位置信息。定位管理器的对象从系统服务LOCATION_SERVICE获取。

  • getBestProvider:获取最佳的定位提供者。第一个参数为定位条件器Criteria的实例,第二个参数取值true表示只要可用的。定位提供者的取值见表2。
表2
定位提供者的名称 说明 定位功能的开启状态
gps 卫星定位 开启GPS功能
network 网络定位 开启数据连接或WLAN功能
passive 无法定位 为开启定位相关功能
  • isProviderEnabled:判断指定的定位提供者是否可用。
  • getLastKnownLocation:获取最近一次的定位地点。
  • requestLocationUpdates:设置定位监听器。其中,第一个参数为定位提供者,第二个参数为位置更新的最小间隔时间,第三个参数为位置更新的最小距离,第四个参数为定位监听器示例。
  • removeUpdates:移除定位监听器。
  • addGpsStatusListener:添加定位状态的监听器。该监听器需实现GpsStatus.Listener接口的onGpsStatusChanged方法。
  • removeGpsStatusListener:移除定位状态的监听器。

<3>定位监听器Locationistener

定位监听器用于监听定位信息的变化事件,如定位提供者的开关、位置信息发生变化等。

  • onLocationChanged:在位置地点发生变化时调用。在此可获取最新的位置信息。
  • onProviderDisabled:在定位提供者被用户关闭时调用。
  • onProviderEnabled:在定位提供者被用户开启时调用。
  • onStatusChanged:在定位提供者的状态变化时调用。定位提供者的状态取值见表3。
表3
LocationProvider类的状态类型 说明
OUT_OF_SERVICE 在服务范围外
TEMPORARILY_UNAVAILABLE 暂时不可用
AVAILABLE 可用状态

2.相关代码示例

添加权限

<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"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >
    <TextView
        android:id="@+id/tv_location"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textColor="@color/black"
        android:textSize="17sp" />
</LinearLayout>

MainActivity.java

public class MainActivity extends WaterPermissionActivity {

    private final static String TAG = "LocationActivity";
    private TextView tv_location;
    private String mLocation = "";
    private LocationManager mLocationMgr; // 声明一个定位管理器对象
    private Criteria mCriteria = new Criteria(); // 声明一个定位准则对象
    private Handler mHandler = new Handler(); // 声明一个处理器
    private boolean isLocationEnable = false; // 定位服务是否可用

    @Override
    protected MvcBaseModel getModelImp() {
        return null;
    }

    @Override
    protected int getContentLayoutId() {
        return R.layout.activity_main;
    }

    @Override
    protected void initWidget() {
        tv_location = findViewById(R.id.tv_location);
        checkGpsIsOpen(this, "需要打开定位功能才能查看定位结果信息");
    }

    @Override
    protected void onResume() {
        super.onResume();
        requestPermission(ACCESS_COARSE_LOCATION);
    }

    @Override
    protected void doAccessCoarseLocation() {
        requestPermission(ACCESS_FINE_LOCATION);
    }

    @Override
    protected void doAccessFineLocation() {
        mHandler.removeCallbacks(mRefresh); // 移除定位刷新任务
        initLocation();
        mHandler.postDelayed(mRefresh, 100); // 延迟100毫秒启动定位刷新任务
    }

    // 初始化定位服务
    private void initLocation() {
        // 从系统服务中获取定位管理器
        mLocationMgr = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
        // 设置定位精确度。Criteria.ACCURACY_COARSE表示粗略,Criteria.ACCURACY_FIN表示精细
        mCriteria.setAccuracy(Criteria.ACCURACY_FINE);
        // 设置是否需要海拔信息
        mCriteria.setAltitudeRequired(true);
        // 设置是否需要方位信息
        mCriteria.setBearingRequired(true);
        // 设置是否允许运营商收费
        mCriteria.setCostAllowed(true);
        // 设置对电源的需求
        mCriteria.setPowerRequirement(Criteria.POWER_LOW);
        // 获取定位管理器的最佳定位提供者
        String bestProvider = mLocationMgr.getBestProvider(mCriteria, true);
        if (mLocationMgr.isProviderEnabled(bestProvider)) { // 定位提供者当前可用
            tv_location.setText("正在获取" + bestProvider + "定位对象");
            mLocation = String.format("定位类型=%s", bestProvider);
            beginLocation(bestProvider);
            isLocationEnable = true;
        } else { // 定位提供者暂不可用
            tv_location.setText("\n" + bestProvider + "定位不可用");
            isLocationEnable = false;
        }
    }

    // 设置定位结果文本
    private void setLocationText(Location location) {
        if (location != null) {
            String desc = String.format("%s\n定位对象信息如下: " +
                            "\n\t其中时间:%s" + "\n\t其中经度:%f,纬度:%f" +
                            "\n\t其中高度:%d米,精度:%d米",
                    mLocation, getNowDateTimeFormat(),
                    location.getLongitude(), location.getLatitude(),
                    Math.round(location.getAltitude()), Math.round(location.getAccuracy()));
            Log.d(TAG, desc);
            tv_location.setText(desc);
        } else {
            tv_location.setText(mLocation + "\n暂未获取到定位对象");
        }
    }

    // 开始定位
    @SuppressLint("MissingPermission")
    private void beginLocation(String method) {
        // 检查当前设备是否已经开启了定位功能
        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
                != PackageManager.PERMISSION_GRANTED) {
            Toast.makeText(this, "请授予定位权限并开启定位功能", Toast.LENGTH_SHORT).show();
            return;
        }
        // 设置定位管理器的位置变更监听器
        mLocationMgr.requestLocationUpdates(method, 300, 0, mLocationListener);
        // 获取最后一次成功定位的位置信息
        Location location = mLocationMgr.getLastKnownLocation(method);
        setLocationText(location);
    }

    // 定义一个位置变更监听器
    private LocationListener mLocationListener = new LocationListener() {
        @Override
        public void onLocationChanged(Location location) {
            setLocationText(location);
        }

        @Override
        public void onProviderDisabled(String arg0) {}

        @Override
        public void onProviderEnabled(String arg0) {}

        @Override
        public void onStatusChanged(String arg0, int arg1, Bundle arg2) {}
    };

    // 定义一个刷新任务,若无法定位则每隔一秒就尝试定位
    private Runnable mRefresh = new Runnable() {
        @Override
        public void run() {
            if (!isLocationEnable) {
                initLocation();
                mHandler.postDelayed(this, 1000);
            }
        }
    };

    @SuppressLint("MissingPermission")
    @Override
    protected void onDestroy() {
        if (mLocationMgr != null) {
            // 移除定位管理器的位置变更监听器
            mLocationMgr.removeUpdates(mLocationListener);
        }
        super.onDestroy();
    }

    // 获取定位功能的开关状态
    public static boolean getGpsStatus(Context ctx) {
        // 从系统服务中获取定位管理器
        LocationManager lm = (LocationManager) ctx.getSystemService(Context.LOCATION_SERVICE);
        return lm.isProviderEnabled(LocationManager.GPS_PROVIDER);
    }

    // 检查定位功能是否打开,若未打开则跳到系统的定位功能设置页面
    public static void checkGpsIsOpen(Context ctx, String hint) {
        if (!getGpsStatus(ctx)) {
            Toast.makeText(ctx, hint, Toast.LENGTH_SHORT).show();
            Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
            ctx.startActivity(intent);
        }
    }

    public static String getNowDateTimeFormat() {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        return sdf.format(new Date());
    }
}

同样的,有关动态权限的申请可以使用自己项目中的。

猜你喜欢

转载自blog.csdn.net/weixin_38322371/article/details/115342567