一,概述:
1 android原生是有定位api的,但稳定性和准确度远远不够,所以通常需要借助三方SDK获取位置信息
2 国内SDK选择性较多,百度,腾讯,高德等定位api,但都是需要在平台建立应用,配置key的,包括基础的定位。
3 国外普遍的用google定位api和google地图,google定位是免费的,但地图是需要key的,包括地理编码webapi接口都需要key
4 国内就不说了,基本没限制,用哪个厂家的SDK都可以,我们主要说下不采用国内的SDK的方案
二,Android原生定位
1 定位普遍采用网络定位或者GPS定位,两者区别也比较大
GPS定位精确度高;但仅能在户外使用,获取定位信息速度慢,耗费电池
Network定位户内户外都能使用,定位速度快,电量耗费低;但精确度不太高
2 原生定位实践
public class AndroidLocationActivity extends Activity { private static final String TAG = "MainActivity"; private Button btnLocation; private TextView tvResult; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_location); btnLocation = (Button) findViewById(R.id.btn_location); tvResult = (TextView) findViewById(R.id.tv_result); btnLocation.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { checkLocationServiceOpen(); } }); } //检查定位服务是否开启 private void checkLocationServiceOpen() { if (isLocServiceEnable(this) && isLocServiceEnable(this, 1)) { initLocation(); } else { Intent intent = new Intent(); intent.setAction(Settings.ACTION_LOCATION_SOURCE_SETTINGS); startActivityForResult(intent, LOCATION_SERVICCE); } } private final static int LOCATION_SERVICCE = 1;// 定位 private final int REQUEST_CHECK_SETTINGS = 2;//google权限设置 public boolean isLocServiceEnable(Context context) { int locationMode = 0; String locationProviders; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { try { locationMode = Settings.Secure.getInt(context.getContentResolver(), Settings.Secure.LOCATION_MODE); } catch (Settings.SettingNotFoundException e) { e.printStackTrace(); return false; } return locationMode != Settings.Secure.LOCATION_MODE_OFF; } else { locationProviders = Settings.Secure.getString(context.getContentResolver(), Settings.Secure.LOCATION_PROVIDERS_ALLOWED); return !TextUtils.isEmpty(locationProviders); } } public boolean isLocServiceEnable(Context context, int type) { LocationManager locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE); boolean gps = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER); boolean network = locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER); if (gps || network) { return true; } return false; } public void initLocation() { AndPermission.with(this) .runtime() .permission(Permission.Group.LOCATION) .onGranted(new Action>() { @Override public void onAction(List permissions) { Log.e(TAG, "onAction: " + "开始定位"); startLocation(); } }) .onDenied(new Action>() { @Override public void onAction(@NonNull List permissions) { Log.e(TAG, "onAction: " + "定位失败"); startLocation();// // 判断用户是不是不再显示权限弹窗了,若不再显示的话进入权限设置页// if (AndPermission.hasAlwaysDeniedPermission(mContext, permissions)) {//// 打开权限设置页//AndPermission.permissionSetting(mContext).start();//return;// } } }) .start(); } private LocationManager locationManager; public void startLocation() { try { if (locationManager == null) { locationManager = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE); } Criteria criteria = new Criteria(); criteria.setAltitudeRequired(true); String bestProvider = locationManager.getBestProvider(criteria, false); Log.e(TAG, "最佳的定位方式:" + bestProvider); //最佳定位方式LocationManager.GPS_PROVIDER LocationManager.NETWORK_PROVIDER locationManager.requestLocationUpdates(bestProvider, 0, 0, myLocationListener); } catch (SecurityException e) { e.printStackTrace(); } } private LocationListener myLocationListener = new LocationListener() { @Override public void onLocationChanged(final Location location) { locationManager.removeUpdates(myLocationListener); setLocationResult(location); } @Override public void onStatusChanged(String provider, int status, Bundle extras) { } @Override public void onProviderEnabled(String provider) { } @Override public void onProviderDisabled(String provider) { } }; private void setLocationResult(Location location) { if (location == null) { tvResult.setText("定位失败"); return; } long time = location.getTime(); float accuracy = location.getAccuracy();//获取精确位置 double altitude = location.getAltitude();//获取海拔 double latitude = location.getLatitude();//获取纬度,平行 double longitude = location.getLongitude();//获取经度,垂直 StringBuffer sb = new StringBuffer(); sb.append("time : "); sb.append(time); sb.append("\nlatitude : "); sb.append(latitude); sb.append("\nlontitude : "); sb.append(longitude); Log.e(TAG, "Android定位:\n"+sb.toString() + "\n\n"); tvResult.setText("Android定位:\n"+sb.toString() + "\n\n"); geocoderAddress(location); } //获取地址信息:城市、街道等信息 public void geocoderAddress(Location location) { try { if (location != null) { Geocoder gc = new Geocoder(this, Locale.getDefault()); List result = gc.getFromLocation(location.getLatitude(), location.getLongitude(), 1); Log.e(TAG, "获取地址信息:" + result.toString()); } } catch (Exception e) { e.printStackTrace(); } } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode == LOCATION_SERVICCE) {//开启定位服务 if (isLocServiceEnable(this) && isLocServiceEnable(this, 1)) { checkLocationServiceOpen(); } } else if (requestCode == REQUEST_CHECK_SETTINGS) { switch (resultCode) { case Activity.RESULT_OK: // All required changes were successfully made Log.e("locationSettingCallback", "RESULT_OK"); startLocation(); break; case Activity.RESULT_CANCELED: Log.e("locationSettingCallback", "RESULT_CANCELED"); // The user was asked to change settings, but chose not to// googleLocationStar();// checkLocationPermission(); break; default: break; } } }}
注意:
Geocoder的使用
1,Geocoder该类用于获取地理位置的前向编码和反向编码,前向编码是根据地址获取经纬度;反向编码是根据经纬度获取对应的详细地址
2,Geocoder 请求的是一个后台服务,但是该服务不包括在标准android framework中,因此如果当前设备不包含location services,则Geocoder返回的地址或者经纬度为空。大部分手机可能都用不了,不支持的会闪退,做好异常处理
监听设置
设置成功后需要取消监听,否则下载再定位不会更新位置
locationManager.removeUpdates(myLocationListener);
三 google定位实践
1 用google限制比较大
- 首先手机要支持google服务,但国产手机由于各厂家的定制化严重,基本上都不会默认带google服务
- 手机网络需要VPN,不然也用不了国外的服务
2 解决限制的方法
安装google三件套,谷歌服务框架、商店和google账户管理程序,方法可以自己去搜。同时安装翻网工具,这个也自己去搜
2 示例
module级build.gradle添加定位依赖
implementation 'com.google.android.gms:play-services-location:18.0.0'
在清单文件添加权限
java源码
public class GoogleLocationActivity extends Activity { private static final String TAG = "MainActivity"; private Button btnLocation; private TextView tvResult; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_location); btnLocation = (Button) findViewById(R.id.btn_location); tvResult = (TextView) findViewById(R.id.tv_result); btnLocation.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { checkLocationServiceOpen(); } }); } //检查定位服务是否开启 private void checkLocationServiceOpen() { if (isLocServiceEnable(this) && isLocServiceEnable(this, 1)) { initLocation(); } else { Intent intent = new Intent(); intent.setAction(Settings.ACTION_LOCATION_SOURCE_SETTINGS); startActivityForResult(intent, LOCATION_SERVICCE); } } private final static int LOCATION_SERVICCE = 1;// 定位 private final int REQUEST_CHECK_SETTINGS = 2;//google权限设置 public boolean isLocServiceEnable(Context context) { int locationMode = 0; String locationProviders; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { try { locationMode = Settings.Secure.getInt(context.getContentResolver(), Settings.Secure.LOCATION_MODE); } catch (Settings.SettingNotFoundException e) { e.printStackTrace(); return false; } return locationMode != Settings.Secure.LOCATION_MODE_OFF; } else { locationProviders = Settings.Secure.getString(context.getContentResolver(), Settings.Secure.LOCATION_PROVIDERS_ALLOWED); return !TextUtils.isEmpty(locationProviders); } } public boolean isLocServiceEnable(Context context, int type) { LocationManager locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE); boolean gps = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER); boolean network = locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER); if (gps || network) { return true; } return false; } public void initLocation() { AndPermission.with(this) .runtime() .permission(Permission.Group.LOCATION) .onGranted(new Action>() { @Override public void onAction(List permissions) { Log.e(TAG, "onAction: " + "开始定位"); initGooglePlayService(); } }) .onDenied(new Action>() { @Override public void onAction(@NonNull List permissions) { Log.e(TAG, "onAction: " + "定位失败"); initGooglePlayService();// // 判断用户是不是不再显示权限弹窗了,若不再显示的话进入权限设置页// if (AndPermission.hasAlwaysDeniedPermission(mContext, permissions)) {//// 打开权限设置页//AndPermission.permissionSetting(mContext).start();//return;// } } }) .start(); } //连接google服务 private void initGooglePlayService() { GoogleApiClient mGoogleApiClient = new GoogleApiClient.Builder(this) .addApi(LocationServices.API) .addConnectionCallbacks(new GoogleApiClient.ConnectionCallbacks() { @Override public void onConnected(@Nullable Bundle bundle) { Log.e(TAG, "onConnected"); initGoogleLocation(); } @Override public void onConnectionSuspended(int i) { Log.e(TAG, "onConnectionSuspended" + "---i"); //startBaiduLocation(); } }) .addOnConnectionFailedListener(new GoogleApiClient.OnConnectionFailedListener() { @Override public void onConnectionFailed(@NonNull ConnectionResult connectionResult) { Log.e(TAG, "onConnectionFailed---" + connectionResult.getErrorCode() + "---" + connectionResult.getErrorMessage()); //startBaiduLocation(); } }) .build(); mGoogleApiClient.connect(); } private LocationRequest locationRequest; private void initGoogleLocation() { try { locationRequest = LocationRequest.create();// locationRequest.setInterval(20000);// locationRequest.setFastestInterval(10000);// locationRequest.setNumUpdates(1);// locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY); LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder() .addLocationRequest(locationRequest); SettingsClient client = LocationServices.getSettingsClient(this); Task task = client.checkLocationSettings(builder.build()); task.addOnSuccessListener(this, new OnSuccessListener() { @Override public void onSuccess(LocationSettingsResponse locationSettingsResponse) { Log.e(TAG, "onSuccess"); startLocation(); } }); task.addOnFailureListener(this, new OnFailureListener() { @Override public void onFailure(@NonNull Exception e) { Log.e(TAG, "onFailure"); if (e instanceof ResolvableApiException) { // Location settings are not satisfied, but this can be fixed // by showing the user a dialog. try {// Show the dialog by calling startResolutionForResult(),// and check the result in onActivityResult().ResolvableApiException resolvable = (ResolvableApiException) e;resolvable.startResolutionForResult(GoogleLocationActivity.this, REQUEST_CHECK_SETTINGS); } catch (IntentSender.SendIntentException sendEx) {// Ignore the error. } } } }); } catch (Exception e) { } } private Location lastKnownLocation; private FusedLocationProviderClient locationProviderClient; private void startLocation() { // Construct a FusedLocationProviderClient. if (locationProviderClient == null) { locationProviderClient = LocationServices.getFusedLocationProviderClient(this); } try { Task locationResult = locationProviderClient.getLastLocation(); locationResult.addOnCompleteListener(this, new OnCompleteListener() { @Override public void onComplete(Task task) { if (task.isSuccessful()) { // Set the map's camera position to the current location of the device. lastKnownLocation = task.getResult(); if(lastKnownLocation!=null){updateLocation(); }else {startNewLocation(); } } else { Log.d(TAG, "Current location is null. Using defaults."); Log.e(TAG, "Exception: %s", task.getException()); } } }); } catch (SecurityException e) { Log.e(TAG, e.getMessage()); } } //开始google定位 private void startNewLocation() { if (locationProviderClient == null) { locationProviderClient = LocationServices.getFusedLocationProviderClient(this); } if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, 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; } Log.e(TAG, "startGoogleLocation11: " + "开始Google定位"); locationProviderClient.requestLocationUpdates(locationRequest, locationCallback, Looper.getMainLooper()) .addOnSuccessListener(new OnSuccessListener() { @Override public void onSuccess(Void unused) { Log.e(TAG, "onSuccess: "); } }); } //定期接受位置信息 LocationCallback locationCallback = new LocationCallback() { @Override public void onLocationResult(LocationResult locationResult) { locationProviderClient.removeLocationUpdates(locationCallback); lastKnownLocation=locationResult.getLastLocation(); updateLocation(); } @Override public void onLocationAvailability(@NonNull LocationAvailability locationAvailability) { super.onLocationAvailability(locationAvailability); Log.e(TAG, "数量3:"+locationAvailability.isLocationAvailable()); } }; private void updateLocation(){ if (lastKnownLocation != null) { StringBuffer sb = new StringBuffer(); sb.append("time : "); sb.append(lastKnownLocation.getTime()); sb.append("\nlatitude : "); sb.append(lastKnownLocation.getLatitude()); sb.append("\nlontitude : "); sb.append(lastKnownLocation.getLongitude()); Log.e(TAG, "google定位:\n"+sb.toString() + "\n\n"); tvResult.setText("google定位:\n"+sb.toString() + "\n\n"); } } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode == LOCATION_SERVICCE) {//开启定位服务 if (isLocServiceEnable(this) && isLocServiceEnable(this, 1)) { checkLocationServiceOpen(); } } else if (requestCode == REQUEST_CHECK_SETTINGS) { switch (resultCode) { case Activity.RESULT_OK: // All required changes were successfully made Log.e("locationSettingCallback", "RESULT_OK"); startLocation(); break; case Activity.RESULT_CANCELED: Log.e("locationSettingCallback", "RESULT_CANCELED"); // The user was asked to change settings, but chose not to// googleLocationStar();// checkLocationPermission(); break; default: break; } } }}
3 注意:
流程上可以先调android原生->再调google最后一次位置->没最后位置就更新位置来确保能获取到定位信息。
4 一定要先请求位置权限,不然会报无权限
3.5 定位精度可以去掉,经尝试加上的话室内一直加载失败
locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
四 总结
国内哪个都可以,国外可以原生和google共用,毕竟google限制条件多,对定位要求不高可以用原生,要求高只能用google定位了
来源地址:https://blog.csdn.net/qq_29848853/article/details/129636031