1.AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.hrg.family"> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" > </uses-permission> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" > </uses-permission> <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" > </uses-permission> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" > </uses-permission> <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" > </uses-permission> <uses-permission android:name="android.permission.READ_PHONE_STATE" > </uses-permission> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" > </uses-permission> <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" > </uses-permission> <uses-permission android:name="android.permission.READ_LOGS" > </uses-permission> <uses-permission android:name="android.permission.VIBRATE" /> <uses-permission android:name="android.permission.WAKE_LOCK" /> <uses-permission android:name="android.permission.WRITE_SETTINGS" /> <application android:name="com.hrg.family.LocationApplication" android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/AppTheme"> <meta-data android:name="com.baidu.lbsapi.API_KEY" android:value="EnhhoIGBTLnirutXropVvxVfmTAfypxy" > </meta-data> <service android:name="com.baidu.location.f" android:enabled="true" android:process=":remote" > <intent-filter> <action android:name="com.baidu.location.service_v2.2" > </action> </intent-filter> </service> <activity android:name=".MainActivity"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <activity android:name="com.hrg.family.LocationFilter"></activity> </application> </manifest>
2.LocationService.java
package com.hrg.family.service; import com.baidu.location.BDAbstractLocationListener; import com.baidu.location.LocationClient; import com.baidu.location.LocationClientOption; import com.baidu.location.LocationClientOption.LocationMode; import android.content.Context; /** * * @author baidu * */ public class LocationService { private LocationClient client = null; private LocationClientOption mOption,DIYoption; private Object objLock = new Object(); /*** * * @param locationContext */ public LocationService(Context locationContext){ synchronized (objLock) { if(client == null){ client = new LocationClient(locationContext); client.setLocOption(getDefaultLocationClientOption()); } } } /*** * * @param listener * @return */ public boolean registerListener(BDAbstractLocationListener listener){ boolean isSuccess = false; if(listener != null){ client.registerLocationListener(listener); isSuccess = true; } return isSuccess; } public void unregisterListener(BDAbstractLocationListener listener){ if(listener != null){ client.unRegisterLocationListener(listener); } } /*** * * @param option * @return isSuccessSetOption */ public boolean setLocationOption(LocationClientOption option){ boolean isSuccess = false; if(option != null){ if(client.isStarted()) client.stop(); DIYoption = option; client.setLocOption(option); } return isSuccess; } public LocationClientOption getOption(){ return DIYoption; } /*** * * @return DefaultLocationClientOption */ public LocationClientOption getDefaultLocationClientOption(){ if(mOption == null){ mOption = new LocationClientOption(); mOption.setLocationMode(LocationMode.Hight_Accuracy);//可选,默认高精度,设置定位模式,高精度,低功耗,仅设备 mOption.setCoorType("bd09ll");//可选,默认gcj02,设置返回的定位结果坐标系,如果配合百度地图使用,建议设置为bd09ll; mOption.setScanSpan(3000);//可选,默认0,即仅定位一次,设置发起定位请求的间隔需要大于等于1000ms才是有效的 mOption.setIsNeedAddress(true);//可选,设置是否需要地址信息,默认不需要 mOption.setIsNeedLocationDescribe(true);//可选,设置是否需要地址描述 mOption.setNeedDeviceDirect(false);//可选,设置是否需要设备方向结果 mOption.setLocationNotify(false);//可选,默认false,设置是否当gps有效时按照1S1次频率输出GPS结果 mOption.setIgnoreKillProcess(true);//可选,默认true,定位SDK内部是一个SERVICE,并放到了独立进程,设置是否在stop的时候杀死这个进程,默认不杀死 mOption.setIsNeedLocationDescribe(true);//可选,默认false,设置是否需要位置语义化结果,可以在BDLocation.getLocationDescribe里得到,结果类似于“在北京天安门附近” mOption.setIsNeedLocationPoiList(true);//可选,默认false,设置是否需要POI结果,可以在BDLocation.getPoiList里得到 mOption.SetIgnoreCacheException(false);//可选,默认false,设置是否收集CRASH信息,默认收集 mOption.setIsNeedAltitude(false);//可选,默认false,设置定位时是否需要海拔信息,默认不需要,除基础定位版本都可用 } return mOption; } public void start(){ synchronized (objLock) { if(client != null && !client.isStarted()){ client.start(); } } } public void stop(){ synchronized (objLock) { if(client != null && client.isStarted()){ client.stop(); } } } public boolean requestHotSpotState(){ return client.requestHotSpotState(); } }3.Utils.javapackage com.hrg.family.service; public class Utils { public final static String CoorType_GCJ02 = "gcj02"; public final static String CoorType_BD09LL= "bd09ll"; public final static String CoorType_BD09MC= "bd09"; /*** *61 : GPS定位结果,GPS定位成功。 *62 : 无法获取有效定位依据,定位失败,请检查运营商网络或者wifi网络是否正常开启,尝试重新请求定位。 *63 : 网络异常,没有成功向服务器发起请求,请确认当前测试手机网络是否通畅,尝试重新请求定位。 *65 : 定位缓存的结果。 *66 : 离线定位结果。通过requestOfflineLocaiton调用时对应的返回结果。 *67 : 离线定位失败。通过requestOfflineLocaiton调用时对应的返回结果。 *68 : 网络连接失败时,查找本地离线定位时对应的返回结果。 *161: 网络定位结果,网络定位定位成功。 *162: 请求串密文解析失败。 *167: 服务端定位失败,请您检查是否禁用获取位置信息权限,尝试重新请求定位。 *502: key参数错误,请按照说明文档重新申请KEY。 *505: key不存在或者非法,请按照说明文档重新申请KEY。 *601: key服务被开发者自己禁用,请按照说明文档重新申请KEY。 *602: key mcode不匹配,您的ak配置过程中安全码设置有问题,请确保:sha1正确,“;”分号是英文状态;且包名是您当前运行应用的包名,请按照说明文档重新申请KEY。 *501~700:key验证失败,请按照说明文档重新申请KEY。 */ public static float[] EARTH_WEIGHT = {0.1f,0.2f,0.4f,0.6f,0.8f}; // 推算计算权重_地球 //public static float[] MOON_WEIGHT = {0.0167f,0.033f,0.067f,0.1f,0.133f}; //public static float[] MARS_WEIGHT = {0.034f,0.068f,0.152f,0.228f,0.304f}; }4.LocationApplication.java
package com.hrg.family; import com.hrg.family.service.LocationService; import com.baidu.mapapi.SDKInitializer; import android.app.Application; import android.app.Service; import android.os.Vibrator; /** * 主Application,所有百度定位SDK的接口说明请参考线上文档:http://developer.baidu.com/map/loc_refer/index.html * * 百度定位SDK官方网站:http://developer.baidu.com/map/index.php?title=android-locsdk * * 直接拷贝com.baidu.location.service包到自己的工程下,简单配置即可获取定位结果,也可以根据demo内容自行封装 */ public class LocationApplication extends Application { public LocationService locationService; public Vibrator mVibrator; @Override public void onCreate() { super.onCreate(); /*** * 初始化定位sdk,建议在Application中创建 */ locationService = new LocationService(getApplicationContext()); mVibrator =(Vibrator)getApplicationContext().getSystemService(Service.VIBRATOR_SERVICE); SDKInitializer.initialize(getApplicationContext()); } }5.LocationFilter.java
package com.hrg.family; import java.util.LinkedList; import com.baidu.location.BDAbstractLocationListener; import com.baidu.location.BDLocation; import com.baidu.location.BDLocationListener; import com.baidu.location.LocationClientOption; import com.hrg.family.service.LocationService; import com.hrg.family.service.Utils; import com.baidu.mapapi.map.BaiduMap; import com.baidu.mapapi.map.BitmapDescriptor; import com.baidu.mapapi.map.BitmapDescriptorFactory; import com.baidu.mapapi.map.MapStatusUpdateFactory; import com.baidu.mapapi.map.MapView; import com.baidu.mapapi.map.MarkerOptions; import com.baidu.mapapi.map.OverlayOptions; import com.baidu.mapapi.model.LatLng; import com.baidu.mapapi.utils.DistanceUtil; import android.app.Activity; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; /*** * 定位滤波demo,实际定位场景中,可能会存在很多的位置抖动,此示例展示了一种对定位结果进行的平滑优化处理 * 实际测试下,该平滑策略在市区步行场景下,有明显平滑效果,有效减少了部分抖动,开放算法逻辑,希望能够对开发者提供帮助 * 注意:该示例场景仅用于对定位结果优化处理的演示,里边相关的策略或算法并不一定适用于您的使用场景,请注意!!! * * @author baidu * */ public class LocationFilter extends Activity { private MapView mMapView = null; private BaiduMap mBaiduMap; private Button reset; private LocationService locService; private LinkedList<LocationEntity> locationList = new LinkedList<LocationEntity>(); // 存放历史定位结果的链表,最大存放当前结果的前5次定位结果 @Override protected void onCreate(Bundle savedInstanceState) { // TODO Auto-generated method stub super.onCreate(savedInstanceState); setContentView(R.layout.locationfilter); mMapView = (MapView) findViewById(R.id.bmapView); reset = (Button) findViewById(R.id.clear); mBaiduMap = mMapView.getMap(); mBaiduMap.setMapType(BaiduMap.MAP_TYPE_NORMAL); mBaiduMap.setMapStatus(MapStatusUpdateFactory.zoomTo(15)); locService = ((LocationApplication) getApplication()).locationService; LocationClientOption mOption = locService.getDefaultLocationClientOption(); mOption.setLocationMode(LocationClientOption.LocationMode.Battery_Saving); mOption.setCoorType("bd09ll"); locService.setLocationOption(mOption); locService.registerListener(listener); locService.start(); } /*** * 定位结果回调,在此方法中处理定位结果 */ BDAbstractLocationListener listener = new BDAbstractLocationListener() { @Override public void onReceiveLocation(BDLocation location) { // TODO Auto-generated method stub if (location != null && (location.getLocType() == 161 || location.getLocType() == 66)) { Message locMsg = locHander.obtainMessage(); Bundle locData; locData = Algorithm(location); if (locData != null) { locData.putParcelable("loc", location); locMsg.setData(locData); locHander.sendMessage(locMsg); } } } }; /*** * 平滑策略代码实现方法,主要通过对新定位和历史定位结果进行速度评分, * 来判断新定位结果的抖动幅度,如果超过经验值,则判定为过大抖动,进行平滑处理,若速度过快, * 则推测有可能是由于运动速度本身造成的,则不进行低速平滑处理 ╭(●`∀´●)╯ * * @param BDLocation * @return Bundle */ private Bundle Algorithm(BDLocation location) { Bundle locData = new Bundle(); double curSpeed = 0; if (locationList.isEmpty() || locationList.size() < 2) { LocationEntity temp = new LocationEntity(); temp.location = location; temp.time = System.currentTimeMillis(); locData.putInt("iscalculate", 0); locationList.add(temp); } else { if (locationList.size() > 5) locationList.removeFirst(); double score = 0; for (int i = 0; i < locationList.size(); ++i) { LatLng lastPoint = new LatLng(locationList.get(i).location.getLatitude(), locationList.get(i).location.getLongitude()); LatLng curPoint = new LatLng(location.getLatitude(), location.getLongitude()); double distance = DistanceUtil.getDistance(lastPoint, curPoint); curSpeed = distance / (System.currentTimeMillis() - locationList.get(i).time) / 1000; score += curSpeed * Utils.EARTH_WEIGHT[i]; } if (score > 0.00000999 && score < 0.00005) { // 经验值,开发者可根据业务自行调整,也可以不使用这种算法 location.setLongitude( (locationList.get(locationList.size() - 1).location.getLongitude() + location.getLongitude()) / 2); location.setLatitude( (locationList.get(locationList.size() - 1).location.getLatitude() + location.getLatitude()) / 2); locData.putInt("iscalculate", 1); } else { locData.putInt("iscalculate", 0); } LocationEntity newLocation = new LocationEntity(); newLocation.location = location; newLocation.time = System.currentTimeMillis(); locationList.add(newLocation); } return locData; } /*** * 接收定位结果消息,并显示在地图上 */ private Handler locHander = new Handler() { @Override public void handleMessage(Message msg) { // TODO Auto-generated method stub super.handleMessage(msg); try { BDLocation location = msg.getData().getParcelable("loc"); int iscal = msg.getData().getInt("iscalculate"); if (location != null) { LatLng point = new LatLng(location.getLatitude(), location.getLongitude()); // 构建Marker图标 BitmapDescriptor bitmap = null; if (iscal == 0) { bitmap = BitmapDescriptorFactory.fromResource(R.drawable.huaji); // 非推算结果 } else { bitmap = BitmapDescriptorFactory.fromResource(R.drawable.icon_openmap_focuse_mark); // 推算结果 } // 构建MarkerOption,用于在地图上添加Marker OverlayOptions option = new MarkerOptions().position(point).icon(bitmap); // 在地图上添加Marker,并显示 mBaiduMap.addOverlay(option); mBaiduMap.setMapStatus(MapStatusUpdateFactory.newLatLng(point)); } } catch (Exception e) { // TODO: handle exception } } }; @Override protected void onDestroy() { super.onDestroy(); // 在activity执行onDestroy时执行mMapView.onDestroy(),实现地图生命周期管理 // WriteLog.getInstance().close(); locService.unregisterListener(listener); locService.stop(); mMapView.onDestroy(); } @Override protected void onResume() { super.onResume(); // 在activity执行onResume时执行mMapView. onResume (),实现地图生命周期管理 mMapView.onResume(); reset.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { // TODO Auto-generated method stub if (mBaiduMap != null) mBaiduMap.clear(); } }); } @Override protected void onPause() { super.onPause(); // 在activity执行onPause时执行mMapView. onPause (),实现地图生命周期管理 mMapView.onPause(); } /** * 封装定位结果和时间的实体类 * * @author baidu * */ class LocationEntity { BDLocation location; long time; } }6.MainActivity.java
package com.hrg.family; import java.util.ArrayList; import java.util.List; import android.Manifest; import android.annotation.TargetApi; import android.app.Activity; import android.content.Intent; import android.content.pm.PackageManager; import android.os.Build; import android.os.Bundle; import android.view.View; import android.widget.AdapterView; import android.widget.AdapterView.OnItemClickListener; import android.widget.ArrayAdapter; import android.widget.ListView; /*** * 本类代码同定位业务本身无关,负责现实列表 * * @author baidu * */ public class MainActivity extends Activity { private final int SDK_PERMISSION_REQUEST = 127; private ListView FunctionList; private String permissionInfo; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.function_list); FunctionList = (ListView) findViewById(R.id.functionList); FunctionList.setAdapter(new ArrayAdapter<String>(this, android.R.layout.simple_expandable_list_item_1, getData())); // after andrioid m,must request Permiision on runtime getPersimmions(); } @TargetApi(23) private void getPersimmions() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { ArrayList<String> permissions = new ArrayList<String>(); /*** * 定位权限为必须权限,用户如果禁止,则每次进入都会申请 */ // 定位精确位置 if(checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED){ permissions.add(Manifest.permission.ACCESS_FINE_LOCATION); } if(checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED){ permissions.add(Manifest.permission.ACCESS_COARSE_LOCATION); } /* * 读写权限和电话状态权限非必要权限(建议授予)只会申请一次,用户同意或者禁止,只会弹一次 */ // 读写权限 if (addPermission(permissions, Manifest.permission.WRITE_EXTERNAL_STORAGE)) { permissionInfo += "Manifest.permission.WRITE_EXTERNAL_STORAGE Deny \n"; } // 读取电话状态权限 if (addPermission(permissions, Manifest.permission.READ_PHONE_STATE)) { permissionInfo += "Manifest.permission.READ_PHONE_STATE Deny \n"; } if (permissions.size() > 0) { requestPermissions(permissions.toArray(new String[permissions.size()]), SDK_PERMISSION_REQUEST); } } } @TargetApi(23) private boolean addPermission(ArrayList<String> permissionsList, String permission) { if (checkSelfPermission(permission) != PackageManager.PERMISSION_GRANTED) { // 如果应用没有获得对应权限,则添加到列表中,准备批量申请 if (shouldShowRequestPermissionRationale(permission)){ return true; }else{ permissionsList.add(permission); return false; } }else{ return true; } } @TargetApi(23) @Override public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { // TODO Auto-generated method stub super.onRequestPermissionsResult(requestCode, permissions, grantResults); } @Override protected void onStart() { // TODO Auto-generated method stub super.onStart(); FunctionList.setOnItemClickListener(new OnItemClickListener() { @Override public void onItemClick(AdapterView<?> arg0, View arg1, int arg2, long arg3) { // TODO Auto-generated method stub Class<?> TargetClass = null; switch (arg2) { case 0: TargetClass = LocationFilter.class; break; default: break; } if (TargetClass != null) { Intent intent = new Intent(MainActivity.this, TargetClass); intent.putExtra("from", 0); startActivity(intent); } } }); } private List<String> getData() { List<String> data = new ArrayList<String>(); data.add("连续定位示例"); return data; } }