Android GPS定位(獲取經緯度)
簡述:
android 定位一般有四種方法,這四種方式分別是:GPS定位,WIFI定位,基站定位,AGPS定位。
本篇博文主要記錄一下GPS定位:這種方式需要手機支援GPS模組硬體支援。通過GPS方式準確度是最高的,但是它的缺點也非常明顯:
1、比較耗電;
2、絕大部分使用者預設不開啟GPS模組;
3、從GPS模組啟動到獲取第一次定位資料,可能需要比較長的時間;
4、室內幾乎無法使用。
這其中,缺點2,3都是比較致命的。
GPS定位優點:GPS走的是衛星通訊的通道,在沒有網路連線的情況下也能使用。
GPS定位:
相關類
(1)、LocationManager:位置服務管理器類
是獲取位置資訊的入口級類,要獲取位置資訊,首先需要獲取一個LocationManger物件:
LocationManager pLocationManager = (LocationManager) Context.getSystemService(Context.LOCATION_SERVICE);
(2)、LocationProvider:位置源提供者用於描述位置提供者資訊,可以先使用方法獲取最佳提供者的名稱:
String providerName = LocationManger.getBestProvider(Criteria criteria, boolean enabledOnly);
LocationManger.getProvider(String name)獲取LocationProvider物件。
(3)、Location:位置物件
描述地理位置資訊的類,記錄了經緯度、海拔高度、獲取座標時間、速度、方位等。可以通過LocationManager.getLastKnowLocation(provider)獲取位置座標,provider就是上文中提到的GPS_PROVIDER、NETWORK_PROVIDER、PASSIVE_PROVIDER、FUSED_PROVIDER;不過很多時候得到的Location物件為null;實時動態座標可以在監聽器locationListener的onLocationChanged(Location
location)方法中來獲取。
(4)、LocationListener:位置監聽介面
用於監聽位置(包括GPS、網路、基站等所有提供位置的)變化,監聽裝置開關與狀態。實時動態獲取位置資訊,首先要實現該介面,在相關方法中新增實現功能的程式碼,實現該介面可以使用內部類或者匿名實現。然後註冊監聽:LocationManger.requestLocationUpdates(Stringprovider, long minTime, float minDistance, LocationListener listener)。使用完之後需要在適當的位置移除監聽:LocationManager
.removeUpdates(LocationListener listener)。LocationListener需要實現的方法:
onLocationChanged(Locationlocation):當位置發生變化的時候會自動呼叫該方法,引數location記錄了最新的位置資訊。
onStatusChanged(String provider, int status, Bundle extras):當位置提供者的狀態發生改變(可用到不可用、不可用到可用)時自動呼叫該方法;引數provider為位置提供者的名稱,status為狀態資訊:OUT_OF_SERVICE 、AVAILABLE 、TEMPORARILY_UNAVAILABLE ,extras為附加資料:key/value,如satellites;
onProviderEnabled(String provider):位置資訊提供者可用時自動呼叫,比如使用者關閉了GPS時,provider則為“gps”;
onProviderDisabled(String provider):位置資訊不可用時自動呼叫。
(5)、Criteria:用於選擇位置資訊提供者的輔助類
建立LocationProvider物件時會使用到該類,參考上文中內容。定位資訊提供者會根據精度、電量、是否提供高度、速度、方位、服務商付費等資訊進行排序選擇定位提供者。 可以參考一個示例:
/** this criteria needs high accuracy, high power and cost */
public static Criteria createFineCriteria() {
Criteriac = new Criteria();
c.setAccuracy(Criteria.ACCURACY_FINE);//高精度
c.setAltitudeRequired(true);//包含高度資訊
c.setBearingRequired(true);//包含方位資訊
c.setSpeedRequired(true);//包含速度資訊
c.setCostAllowed(true);//允許付費
c.setPowerRequirement(Criteria.POWER_HIGH);//高耗電
return c;
}
(6)、GpsStatus.Listener:GPS狀態監聽的一個介面 使用方法與locationListener介面類似,先實現介面並建立物件,實現介面中的方法:onGpsStatusChanged(int event);在方法中實現對衛星狀態資訊變化的監聽,根據event的型別編寫邏輯程式碼。建立物件後再註冊監聽:LocationManager .addGpsStatusListener(GpsStatus.Listener listener);使用後在合適的位置釋放監聽:LocationManager .removeGpsStatusListener(GpsStatus.Listener
listener)。
GPS定位流程
(1)配置許可權:
新增如下許可權:
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission..ACCESS_FINE_LOCATION" />
(2)獲取LocationManager型別物件:
LocationManager mLocationManager =(LocationManager) mContext.getSystemService (Context.LOCATION_SERVICE);
(3) 獲取最佳位置定位方式pProvider:(這步可有可無,根據情況而定)
mLocationManager.getBestProvider(mCriteria,true); mCriteria為Criteria型別的物件,包含精度、是否返回高度、方位、速度等資訊。建立Criteria物件示例:
/** this criteria needs highaccuracy, high power, and cost */
public static CriteriacreateFineCriteria() {
Criteriac = new Criteria();
c.setAccuracy(Criteria.ACCURACY_FINE);//高精度
c.setAltitudeRequired(true);//包含高度資訊
c.setBearingRequired(true);//包含方位資訊
c.setSpeedRequired(true);//包含速度資訊
c.setCostAllowed(true);//允許付費
c.setPowerRequirement(Criteria.POWER_HIGH);//高耗電
return c;
}
(4) 實現LocationListener介面:可以採用內部類(MyLocationListener)或匿名類方式實現,重寫介面方法.
(5) 建立MyLocationListener物件mLocationListener,並新增監聽:
mLocationListener =new MyLocationListener();
mLocationManager.requestLocationUpdates(pProvider, MIN_TIME_UPDATE,MIN_DISTANCE_UPDATE, mLocationListener);
(6) 使用完釋放監聽:
mLocationManager.removeUpdates(mLocationListener);
該方法執行的位置需要特別注意,如果是在Activity物件中,則需要考慮Activity的生命週期,onPause方法中比較合適,因為onStop、onDestroy兩個方法在異常情況下不會被執行。(7) 如果需要監聽GPS衛星狀態,則需要實現GpsStatus.Listener介面,並建立物件、新增監聽、使用完後釋放監聽:
實現介面:
private class MyGpsStatusListener implements GpsStatus.Listener;
建立物件:
MyGpsStatusListener mGpsStatusListener = new MyGpsStatusListener();
新增監聽:
mLocationManager.addGpsStatusListener (mGpsStatusListener;
釋放監聽:
mLocationManager.removeGpsStatusListener(mGpsStatusListener);
案例實現:
全部程式碼貼出來:
package com.lzy.gpslocation;
import android.Manifest;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.location.Criteria;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.location.LocationProvider;
import android.support.annotation.NonNull;
import android.support.v4.app.ActivityCompat;
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.TextView;
import android.widget.Toast;
import com.fastaccess.permission.base.PermissionHelper;
import com.fastaccess.permission.base.callback.OnPermissionCallback;
import java.util.Arrays;
public class MainActivity extends AppCompatActivity implements OnPermissionCallback {
private static final String TAG = MainActivity.class.getSimpleName();
private static final String GPS_LOCATION_NAME = android.location.LocationManager.GPS_PROVIDER;
private static final int REQUEST_PRESSMION_CODE = 10000;
private final static String[] MULTI_PERMISSIONS = new String[]{
Manifest.permission.ACCESS_COARSE_LOCATION,
Manifest.permission.ACCESS_FINE_LOCATION};
private LocationManager locationManager;
private boolean isGpsEnabled;
private String locateType;
private TextView textLocationShow;
private Button btnLocation;
//許可權檢測類
private PermissionHelper mPermissionHelper;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initData();
initViews();
}
/**
* 方法描述:初始化定位相關資料
*/
private void initData() {
//獲取定位服務
locationManager = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE);
//判斷是否開啟GPS定位功能
isGpsEnabled = locationManager.isProviderEnabled(GPS_LOCATION_NAME);
//定位型別:GPS
locateType = locationManager.GPS_PROVIDER;
//初始化PermissionHelper
mPermissionHelper = PermissionHelper.getInstance(MainActivity.this);
}
/**
* 方法描述:初始化View元件資訊及相關點選事件
*/
private void initViews() {
textLocationShow = (TextView) findViewById(R.id.text_location_show);
btnLocation = (Button) findViewById(R.id.btn_location);
btnLocation.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
getLocation();
}
});
((Button)findViewById(R.id.btn_skip)).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(MainActivity.this,ThirdActivity.class);
startActivity(intent);
}
});
}
private void getLocation() {
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
!= PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission
(MainActivity.this, Manifest.permission.ACCESS_COARSE_LOCATION)
!= PackageManager.PERMISSION_GRANTED) {
mPermissionHelper.request(MULTI_PERMISSIONS);
return;
}
Location location = locationManager.getLastKnownLocation(locateType); // 通過GPS獲取位置
if (location != null) {
updateUI(location);
}
// 設定監聽*器,自動更新的最小時間為間隔N秒(1秒為1*1000,這樣寫主要為了方便)或最小位移變化超過N米
locationManager.requestLocationUpdates(locateType, 100,0,
locationListener);
}
private LocationListener locationListener = new LocationListener() {
/**
* 位置資訊變化時觸發:當座標改變時觸發此函式,如果Provider傳進相同的座標,它就不會被觸發
* @param location
*/
@Override
public void onLocationChanged(Location location) {
Toast.makeText(MainActivity.this, "onLocationChanged函式被觸發!", Toast.LENGTH_SHORT).show();
updateUI(location);
Log.i(TAG, "時間:" + location.getTime());
Log.i(TAG, "經度:" + location.getLongitude());
Log.i(TAG, "緯度:" + location.getLatitude());
Log.i(TAG, "海拔:" + location.getAltitude());
}
/**
* GPS狀態變化時觸發:Provider被disable時觸發此函式,比如GPS被關閉
* @param provider
* @param status
* @param extras
*/
@Override
public void onStatusChanged(String provider, int status, Bundle extras) {
switch (status) {
//GPS狀態為可見時
case LocationProvider.AVAILABLE:
Toast.makeText(MainActivity.this, "onStatusChanged:當前GPS狀態為可見狀態", Toast.LENGTH_SHORT).show();
break;
//GPS狀態為服務區外時
case LocationProvider.OUT_OF_SERVICE:
Toast.makeText(MainActivity.this, "onStatusChanged:當前GPS狀態為服務區外狀態", Toast.LENGTH_SHORT).show();
break;
//GPS狀態為暫停服務時
case LocationProvider.TEMPORARILY_UNAVAILABLE:
Toast.makeText(MainActivity.this, "onStatusChanged:當前GPS狀態為暫停服務狀態", Toast.LENGTH_SHORT).show();
break;
}
}
/**
* 方法描述:GPS開啟時觸發
* @param provider
*/
@Override
public void onProviderEnabled(String provider) {
Toast.makeText(MainActivity.this, "onProviderEnabled:方法被觸發", Toast.LENGTH_SHORT).show();
getLocation();
}
/**
* 方法描述: GPS禁用時觸發
* @param provider
*/
@Override
public void onProviderDisabled(String provider) {
}
};
/**
* 方法描述:在View上更新位置資訊的顯示
*
* @param location
*/
private void updateUI(Location location) {
double longitude = location.getLongitude();
double latitude = location.getLatitude();
textLocationShow.setText("當前經度:" + longitude + "\n當前緯度:" + latitude);
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
mPermissionHelper.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
mPermissionHelper.onActivityForResult(requestCode);
}
@Override
public void onPermissionGranted(@NonNull String[] permissionName) {
getLocation();
Log.i("onPermissionGranted", "Permission(s) " + Arrays.toString(permissionName) + " Granted");
}
@Override
public void onPermissionDeclined(@NonNull String[] permissionName) {
}
@Override
public void onPermissionPreGranted(@NonNull String permissionsName) {
}
@Override
public void onPermissionNeedExplanation(@NonNull String permissionName) {
}
@Override
public void onPermissionReallyDeclined(@NonNull String permissionName) {
}
@Override
public void onNoPermissionNeeded() {
}
}
程式碼封裝:
高效的開發者絕對不會做重複的程式碼的事情。那麼可以編寫一個GPS定位管理類,將公共的功能邏輯封裝好實現模組化,在activity中實現差異化的內容。
1、GPSLocationListener:利用Java面向介面程式設計的方式定義該介面用於實時監聽資料回撥
import android.location.Location;
import android.os.Bundle;
/**
* 類描述:供外部實現的介面
* Created by lizhenya on 2016/9/12.
*/
public interface GPSLocationListener {
/**
* 方法描述:位置資訊發生改變時被呼叫
*
* @param location 更新位置後的新的Location物件
*/
void UpdateLocation(Location location);
/**
* 方法描述:provider定位源型別變化時被呼叫
*
* @param provider provider的型別
* @param status provider狀態
* @param extras provider的一些設定引數(如高精度、低功耗等)
*/
void UpdateStatus(String provider, int status, Bundle extras);
/**
* 方法描述:GPS狀態發生改變時被呼叫(GPS手動啟動、手動關閉、GPS不在服務區、GPS佔時不可用、GPS可用)
*
* @param gpsStatus 詳見{@link GPSProviderStatus}
*/
void UpdateGPSProviderStatus(int gpsStatus);
}
2、GPSLocation:實現動態地實時更新位置座標資訊、狀態資訊
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationProvider;
import android.os.Bundle;
/**
* 類描述:實現LocationListener的子類,同時實現自己的介面呼叫
* Created by lizhenya on 2016/9/12.
*/
public class GPSLocation implements LocationListener {
private GPSLocationListener mGpsLocationListener;
public GPSLocation(GPSLocationListener gpsLocationListener) {
this.mGpsLocationListener = gpsLocationListener;
}
@Override
public void onLocationChanged(Location location) {
if (location != null) {
mGpsLocationListener.UpdateLocation(location);
}
}
@Override
public void onStatusChanged(String provider, int status, Bundle extras) {
mGpsLocationListener.UpdateStatus(provider, status, extras);
switch (status) {
case LocationProvider.AVAILABLE:
mGpsLocationListener.UpdateGPSProviderStatus(GPSProviderStatus.GPS_AVAILABLE);
break;
case LocationProvider.OUT_OF_SERVICE:
mGpsLocationListener.UpdateGPSProviderStatus(GPSProviderStatus.GPS_OUT_OF_SERVICE);
break;
case LocationProvider.TEMPORARILY_UNAVAILABLE:
mGpsLocationListener.UpdateGPSProviderStatus(GPSProviderStatus.GPS_TEMPORARILY_UNAVAILABLE);
break;
}
}
@Override
public void onProviderEnabled(String provider) {
mGpsLocationListener.UpdateGPSProviderStatus(GPSProviderStatus.GPS_ENABLED);
}
@Override
public void onProviderDisabled(String provider) {
mGpsLocationListener.UpdateGPSProviderStatus(GPSProviderStatus.GPS_DISABLED);
}
}
3、GPS狀態資訊類
/**
* 類描述:GPS狀態類
* Created by lizhenya on 2016/9/12.
*/
public class GPSProviderStatus {
//使用者手動開啟GPS
public static final int GPS_ENABLED = 0;
//使用者手動關閉GPS
public static final int GPS_DISABLED = 1;
//服務已停止,並且在短時間內不會改變
public static final int GPS_OUT_OF_SERVICE = 2;
//服務暫時停止,並且在短時間內會恢復
public static final int GPS_TEMPORARILY_UNAVAILABLE = 3;
//服務正常有效
public static final int GPS_AVAILABLE = 4;
}
4、GPSLocationManager:實現GPS定位的初始化、GPS定位的啟動和終止
import android.Manifest;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.location.Location;
import android.location.LocationManager;
import android.os.Build;
import android.provider.Settings;
import android.support.v4.app.ActivityCompat;
import android.widget.Toast;
import java.lang.ref.WeakReference;
/**
* 類描述:GPS定位的管理類
* Created by lizhenya on 2016/9/12.
*/
public class GPSLocationManager {
private static final String GPS_LOCATION_NAME = android.location.LocationManager.GPS_PROVIDER;
private static GPSLocationManager gpsLocationManager;
private static Object objLock = new Object();
private boolean isGpsEnabled;
private static String mLocateType;
private WeakReference<Activity> mContext;
private LocationManager locationManager;
private GPSLocation mGPSLocation;
private boolean isOPenGps;
private long mMinTime;
private float mMinDistance;
private GPSLocationManager(Activity context) {
initData(context);
}
private void initData(Activity context) {
this.mContext = new WeakReference<>(context);
if (mContext.get() != null) {
locationManager = (LocationManager) (mContext.get().getSystemService(Context.LOCATION_SERVICE));
}
//定位型別:GPS
mLocateType = locationManager.GPS_PROVIDER;
//預設不強制開啟GPS設定面板
isOPenGps = false;
//預設定位時間間隔為1000ms
mMinTime = 1000;
//預設位置可更新的最短距離為0m
mMinDistance = 0;
}
public static GPSLocationManager getInstances(Activity context) {
if (gpsLocationManager == null) {
synchronized (objLock) {
if (gpsLocationManager == null) {
gpsLocationManager = new GPSLocationManager(context);
}
}
}
return gpsLocationManager;
}
/**
* 方法描述:設定發起定位請求的間隔時長
*
* @param minTime 定位間隔時長(單位ms)
*/
public void setScanSpan(long minTime) {
this.mMinTime = minTime;
}
/**
* 方法描述:設定位置更新的最短距離
*
* @param minDistance 最短距離(單位m)
*/
public void setMinDistance(float minDistance) {
this.mMinDistance = minDistance;
}
/**
* 方法描述:開啟定位(預設情況下不會強制要求使用者開啟GPS設定面板)
*
* @param gpsLocationListener
*/
public void start(GPSLocationListener gpsLocationListener) {
this.start(gpsLocationListener, isOPenGps);
}
/**
* 方法描述:開啟定位
*
* @param gpsLocationListener
* @param isOpenGps 當用戶GPS未開啟時是否強制使用者開啟GPS
*/
public void start(GPSLocationListener gpsLocationListener, boolean isOpenGps) {
this.isOPenGps = isOpenGps;
if (mContext.get() == null) {
return;
}
mGPSLocation = new GPSLocation(gpsLocationListener);
isGpsEnabled = locationManager.isProviderEnabled(GPS_LOCATION_NAME);
if (!isGpsEnabled && isOPenGps) {
openGPS();
return;
}
if (ActivityCompat.checkSelfPermission(mContext.get(), Manifest.permission.ACCESS_FINE_LOCATION)
!= PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission
(mContext.get(), Manifest.permission.ACCESS_COARSE_LOCATION)
!= PackageManager.PERMISSION_GRANTED) {
return;
}
Location lastKnownLocation = locationManager.getLastKnownLocation(mLocateType);
mGPSLocation.onLocationChanged(lastKnownLocation);
//備註:引數2和3,如果引數3不為0,則以引數3為準;引數3為0,則通過時間來定時更新;兩者為0,則隨時重新整理
locationManager.requestLocationUpdates(mLocateType, mMinTime, mMinDistance, mGPSLocation);
}
/**
* 方法描述:轉到手機設定介面,使用者設定GPS
*/
public void openGPS() {
Toast.makeText(mContext.get(), "請開啟GPS設定", Toast.LENGTH_SHORT).show();
if (Build.VERSION.SDK_INT > 15) {
Intent intent = new Intent(
Settings.ACTION_LOCATION_SOURCE_SETTINGS);
mContext.get().startActivityForResult(intent, 0);
}
}
/**
* 方法描述:終止GPS定位,該方法最好在onPause()中呼叫
*/
public void stop() {
if (mContext.get() != null) {
if (ActivityCompat.checkSelfPermission(mContext.get(), Manifest.permission.ACCESS_FINE_LOCATION) !=
PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(mContext.get(),
Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
return;
}
locationManager.removeUpdates(mGPSLocation);
}
}
}
GPS管理類的使用:在Activity中Oncreate()方法中進行初始化和開啟定位,在onPause()方法中終止定位
import android.app.Activity;
import android.location.Location;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
import com.lzy.gpslocation.location.GPSLocationListener;
import com.lzy.gpslocation.location.GPSLocationManager;
import com.lzy.gpslocation.location.GPSProviderStatus;
/**
* Created by lizhenya on 2016/9/12.
*/
public class ThirdActivity extends Activity {
private TextView text_gps_3;
private Button btn_gps_3;
private GPSLocationManager gpsLocationManager;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_third);
initData();
}
private void initData() {
gpsLocationManager = GPSLocationManager.getInstances(ThirdActivity.this);
text_gps_3 = (TextView) findViewById(R.id.text_gps_3);
btn_gps_3 = (Button) findViewById(R.id.btn_gps_3);
btn_gps_3.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//開啟定位
gpsLocationManager.start(new MyListener());
}
});
}
class MyListener implements GPSLocationListener {
@Override
public void UpdateLocation(Location location) {
if (location != null) {
text_gps_3.setText("經度:" + location.getLongitude() + "\n緯度:" + location.getLatitude());
}
}
@Override
public void UpdateStatus(String provider, int status, Bundle extras) {
if ("gps" == provider) {
Toast.makeText(ThirdActivity.this, "定位型別:" + provider, Toast.LENGTH_SHORT).show();
}
}
@Override
public void UpdateGPSProviderStatus(int gpsStatus) {
switch (gpsStatus) {
case GPSProviderStatus.GPS_ENABLED:
Toast.makeText(ThirdActivity.this, "GPS開啟", Toast.LENGTH_SHORT).show();
break;
case GPSProviderStatus.GPS_DISABLED:
Toast.makeText(ThirdActivity.this, "GPS關閉", Toast.LENGTH_SHORT).show();
break;
case GPSProviderStatus.GPS_OUT_OF_SERVICE:
Toast.makeText(ThirdActivity.this, "GPS不可用", Toast.LENGTH_SHORT).show();
break;
case GPSProviderStatus.GPS_TEMPORARILY_UNAVAILABLE:
Toast.makeText(ThirdActivity.this, "GPS暫時不可用", Toast.LENGTH_SHORT).show();
break;
case GPSProviderStatus.GPS_AVAILABLE:
Toast.makeText(ThirdActivity.this, "GPS可用啦", Toast.LENGTH_SHORT).show();
break;
}
}
}
@Override
protected void onPause() {
super.onPause();
//在onPause()方法終止定位
gpsLocationManager.stop();
}
}
OK,關於GPS定位獲取經緯度的總結先這麼多。