GPS技术与移动开发应用
GPS技术与移动开发应用
源码地址:https://github.com/shaoyayu/baidumapDome/tree/master/%E4%BD%9C%E4%B8%9A%E6%BA%90%E7%A0%81
作业:地图定位
目的: 搭建Android & GPS 开发环境
利用GPS在地图上进行本地地理位置的定位
环境: Android手机带GPS功能,安装有JDK、eclipse集成的Android开发环境的电脑。
1.内容和原理
1)内容
注册成为百度的开发者,下载地图SDK开发包,利用定位到使用Map、location、model
2)原理
GPS技术与百度地图开发包结合使用原理:
使用百度Android定位SDK必须注册GPS和网络使用权限。定位SDK采用GPS、基站、Wi-Fi信号进行定位。当应用程序向定位SDK发起定位请求时,定位SDK会根据应用的定位因素(GPS、基站、Wi-Fi信号)的实际情况(如是否开启GPS、是否连接网络、是否有信号等)来生成相应定位依据进行定位。
用户可以设置满足自身需求的定位依据:
若用户设置GPS优先,则优先使用GPS进行定位,如果GPS定位未打开或者没有可用位置信息,且网络连接正常,定位SDK则会返回网络定位(即Wi-Fi与基站)的最优结果。为了使获得的网络定位结果更加精确,请打开手机的Wi-Fi开关。
2.需求分析
3.操作方法和步骤
(1) 申请AK(API Key)
1、登录注册百度地图开发者:http://lbsyun.baidu.com/apiconsole/key
2、点击创建应用:
3、最好写你的当前开发的应用程序名称,记者应用类型一定选择Android SDK
选择自己所需要的SDK服务模块,我建议全选。
4、怎么获取SHA1呢。开发版的获取方法:
进入控制台:进入目录 用户目录/.android
keytool -list -v -keystore debug.keystore > sha1.txt
我的建议是输出到文件里面,方便查看,这是开发版的,开发版和发布版的SHA1可以写一样的。
【如果你有自己的签名,你也可以配置一个发布版的sha1,没有签名的后面可省略配置发布版的SHA1】
进入你的签名文件目录:在控制台输入:
keytool -list -v -keystore > sha1.txt
5、填写你的应用程序的包名,一定跟你的AndroidManifest.xml中的包名是一致的,
6、点击提交即可;
(2) 下载SDK开发包
下载地址:SDK下载
点击下载开发包即可:
(3) 在android项目中引用百度SDK
1、添加jar文件
打开解压后的开发包文件夹,找到BaiduLBS_Android.jar文件将其拷贝至工程的app/libs目录下
2、添加so文件
有两种方法可以往项目中添加so文件。 方法一: 在下载的开发包中拷贝需要的CPU架构对应的so文件文件夹到app/libs目录下,
在app目录下的build.gradle文件中android块中配置sourceSets标签,如果没有使用该标签则新增,详细配置代码如下:
sourceSets { main { jniLibs.srcDir 'libs' } }
注意:Jar文件和so文件的版本号必须一致,并且保证Jar文件与so文件是同一版本包取出的。
方法二: 在src/main/目录下新建jniLibs目录(如果您的项目中已经包含该目录不用重复创建),在下载的开发包中拷贝项目中需要的CPU架构对应的so文件文件夹到jniLibs目录。
3、往工程中添加jar文件
在工程配置中需要将前面添加的jar文件集成到我们的工程中。
方法一: 在libs目录下,选中每一个jar文件(此处只有一BaiduLbs_Android.jar)右键,选择Add As Library…,
此时会发现在app目录的build.gradle的dependencies块中生成了工程所依赖的jar文件的对应说明
注意:最新版本的Android Studio中compile被替换为implementation,具体的写法与您的Android Studio版本有关。
(4)、你自己添加的功能
下载百度开发的实例代码:百度地图案例下载
1、 拷贝案例中的assets文件下面的文件到自己项目中的assets目录下面,
2、 拷贝百度地图的导航路线覆盖物类到自己的程序中,在导航路线覆盖物使用的时候直接使用。重要的有:
DrivingRouteOverlay.java
OverlayManager.java
PoiOverlay.java
TransitRouterOverlay.java
WalkingRouteOverlay.java
4、记录与处理
主程序代码如下:
LocationServiceActivity
package icu.shaoyayu.android.iearnit.activity.service;
/**
* @author shaoyayu
* 导航和定位部分,设计位置签到等功能
* Activity和Fragment之间的实时交互
*/
public class LocationServiceActivity extends ModuleActivity {
protected BroadcastReceiver receiver = null;
//当前Activity涉及的权限
private String[] purview = {Manifest.permission.ACCESS_NETWORK_STATE
, Manifest.permission.READ_EXTERNAL_STORAGE
, Manifest.permission.WRITE_EXTERNAL_STORAGE
, Manifest.permission.ACCESS_COARSE_LOCATION
, Manifest.permission.ACCESS_FINE_LOCATION
, Manifest.permission.ACCESS_WIFI_STATE
, Manifest.permission.CHANGE_WIFI_STATE
};
private BDLocation mLocation = null;
private PoiInfo mPoiInfo = null;
private double latitude = 0;
private double longitude = 0;
private LocationClient locationClient;
private MapView mMapView;
private BaiduMap mBaiduMap;
private FloatingActionButton mMapRouteDialog,mMapSearchDialog,mMapShareDialog;
private Switch mHeatMap;
private BottomDialog dialog = null;
private NavigationMap navigationMap = new NavigationMap();
private static final String TAG = "LocationServiceActivity";
private SimpleMenu mSimpleMenu ;
@Override
protected void initWindows() {
//初始化服务
registerSDKCheckReceiver();
}
@Override
protected int getInterfaceResourceId() {
return R.layout.activity_location_service;
}
@Override
public void onPointerCaptureChanged(boolean hasCapture) {
}
@Override
protected void initTheControl() {
super.initTheControl();
locationClient = new LocationClient(getApplicationContext());
//初始化位置权限
mSimpleMenu = findViewById(R.id.menu_location_service);
mMapView = findViewById(R.id.mp_location_service);
mMapRouteDialog = findViewById(R.id.fab_map_route);
mMapSearchDialog = findViewById(R.id.fab_map_search);
mMapShareDialog = findViewById(R.id.fab_map_share);
mHeatMap = findViewById(R.id.sc_open_heat_map);
mBaiduMap = mMapView.getMap();
Log.d(TAG,"初始化控件");
//要放在后面执行
PermissionsUtils.getInstance().checkPermissions(this,
purview,
new PermissionsUtils.IPermissionsResult() {
@Override
public void passPermissions() {
initData();
}
@Override
public void forbidPermissions() {
//弹出解释框,确定后前往设置见面
}
});
}
@Override
protected void initData() {
super.initData();
Log.d(TAG,"初始化数据");
mSimpleMenu.setTvMenuThemeText("位置服务");
mMapView.showZoomControls(false);
//获取地图的最大最小缩放
Log.i(TAG,"最大缩放:"+mBaiduMap.getMaxZoomLevel()+",最小缩放:"+mBaiduMap.getMinZoomLevel());
//设置地图的中心,通过工厂进行创建,注意经纬度是反的,
MapStatusUpdate centerPoint = MapStatusUpdateFactory.newLatLng(new LatLng(26.62587,106.680831));
mBaiduMap.setMapStatus(centerPoint);
//设置一个默认的缩放
MapStatusUpdate defaultZoom = MapStatusUpdateFactory.zoomTo(18);
mBaiduMap.setMapStatus(defaultZoom);
initLocationOption();
}
@Override
protected void initControlBindingEvents() {
super.initControlBindingEvents();
mHeatMap.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (isChecked){
//开启热力图
mBaiduMap.setBaiduHeatMapEnabled(true);
}else {
//显示正常地图
mBaiduMap.setBaiduHeatMapEnabled(false);
}
}
});
mMapSearchDialog.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if(dialog!=null && dialog.getDialog()!=null
&& dialog.getDialog().isShowing()) {
//dialog is showing so do something
dialog.onStart();
dialog = new MapSearchDialog(mLocation,new ImplementCallback());
dialog.show(getSupportFragmentManager(),"搜索");
} else {
//dialog is not showing
dialog = new MapSearchDialog(mLocation,new ImplementCallback());
dialog.show(getSupportFragmentManager(),"搜索");
}
}
});
mMapRouteDialog.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if(dialog!=null && dialog.getDialog()!=null
&& dialog.getDialog().isShowing()) {
//dialog is showing so do something
dialog.onStart();
dialog = new MapRouteDialog(mPoiInfo,mLocation,navigationMap);
dialog.show(getSupportFragmentManager(),"路线");
} else {
//dialog is not showing
dialog = new MapRouteDialog(mPoiInfo,mLocation,navigationMap);
dialog.show(getSupportFragmentManager(),"路线");
}
}
});
mMapShareDialog.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if(dialog!=null && dialog.getDialog()!=null
&& dialog.getDialog().isShowing()) {
//dialog is showing so do something
dialog.onStart();
dialog = new MapShareDialog(mLocation);
dialog.show(getSupportFragmentManager(),"分享");
} else {
//dialog is not showing
dialog = new MapShareDialog(mLocation);
dialog.show(getSupportFragmentManager(),"分享");
}
//从新定位
initLocationOption();
}
});
}
@Override
protected void onResume() {
super.onResume();
//在activity执行onResume时执行mMapView. onResume (),实现地图生命周期管理
mMapView.onResume();
}
@Override
protected void onPause() {
super.onPause();
//在activity执行onPause时执行mMapView. onPause (),实现地图生命周期管理
mMapView.onPause();
}
@Override
protected void onDestroy() {
super.onDestroy();
//在activity执行onDestroy时执行mMapView.onDestroy(),实现地图生命周期管理
mMapView.onDestroy();
unregisterReceiver(receiver);
}
/**
* 初始化地图服务
*/
protected void registerSDKCheckReceiver(){
receiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (SDKInitializer.SDK_BROADCAST_ACTION_STRING_NETWORK_ERROR.equals(action)){
Toast.makeText(context, "网络错误", Toast.LENGTH_SHORT).show();
Log.w(TAG,"网络无法连接");
}else if (SDKInitializer.SDK_BROADTCAST_ACTION_STRING_PERMISSION_CHECK_ERROR.equals(action)){
Toast.makeText(context, "Key验证失败", Toast.LENGTH_SHORT).show();
Log.w(TAG,"key验证失败");
}
}
};
IntentFilter filter = new IntentFilter();
//监听网络错误
filter.addAction(SDKInitializer.SDK_BROADCAST_ACTION_STRING_NETWORK_ERROR);
//监听百度地图的sdk的可以时不时正确
filter.addAction(SDKInitializer.SDK_BROADTCAST_ACTION_STRING_PERMISSION_CHECK_ERROR);
registerReceiver(receiver,filter);
}
/**
* 权限申请
* @param requestCode
* @param permissions
* @param grantResults
*/
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
PermissionsUtils.getInstance().onRequestPermissionsResult(this,requestCode,permissions,grantResults);
}
/**
* 初始化定位参数配置
*/
private void initLocationOption() {
LocationClientOption locationOption = new LocationClientOption();
MyLocationListener myLocationListener = new MyLocationListener();
locationClient.registerLocationListener(myLocationListener);
locationOption.setLocationMode(LocationClientOption.LocationMode.Hight_Accuracy);
locationOption.setCoorType("bd09ll");
locationOption.setScanSpan(0);
locationOption.setIsNeedAddress(true);
locationOption.setIsNeedLocationDescribe(true);
locationOption.setNeedDeviceDirect(false);
locationOption.setLocationNotify(true);
locationOption.setIgnoreKillProcess(true);
locationOption.setIsNeedLocationDescribe(true);
locationOption.setIsNeedLocationPoiList(true);
locationOption.SetIgnoreCacheException(false);
locationOption.setOpenGps(true);
locationOption.setIsNeedAltitude(false);
locationOption.setOpenAutoNotifyMode();
locationOption.setOpenAutoNotifyMode(3000,1, LocationClientOption.LOC_SENSITIVITY_HIGHT);
locationClient.setLocOption(locationOption);
locationClient.start();
}
/**
* 实现定位回调
*/
public class MyLocationListener extends BDAbstractLocationListener {
@Override
public void onReceiveLocation(BDLocation location){
//测试使用 112.193069,30.355534
/* location.setLongitude(112.193069);
location.setLatitude(30.355534);*/
if (mLocation==null){
mLocation = location;
}
if (latitude==0){
latitude = location.getLatitude();
}
if (longitude==0){
longitude = location.getLongitude();
}
Log.d(TAG,"latitude:"+latitude+",longitude:"+longitude);
//初始化位置信息
MapStatusUpdate centerPoint = MapStatusUpdateFactory.newLatLng(new LatLng(latitude,longitude));
mBaiduMap.setMapStatus(centerPoint);
//标记
//构建Marker图标
MarkerOptions markerOptions = new MarkerOptions();
BitmapDescriptor bitmapDescriptor4 = BitmapDescriptorFactory.fromResource(R.mipmap.maps_easyicon);
markerOptions.position(new LatLng(latitude,longitude))
//添加图标
.icon(bitmapDescriptor4);
mBaiduMap.addOverlay(markerOptions);
//---------------------详细信息获取方法---------------------///
locationClient.stop();
}
}
//清除标记物
public void clearMarker(){
LatLng latLng1 = new LatLng(0,0);
LatLng latLng2 = new LatLng(9999,9999);
List<LatLng> latLngs = new ArrayList<>();
//指定搜索范围
LatLngBounds bounds = new LatLngBounds.Builder()
//设置内容
.include(latLng1)
.include(latLng2)
.build();
List<Marker> markersInBounds = mBaiduMap.getMarkersInBounds(bounds);
for (Marker markersInBound : markersInBounds) {
markersInBound.remove();
}
}
/**
* poi搜索过后描述位置信息的回调
*/
public class ImplementCallback implements MapSearchDialog.POICallback {
/**
* 回调显示所有poi检索结果
* 绑定点击事件
* @param poiInfos
*/
@Override
public void showSearchResults(List<PoiInfo> poiInfos) {
}
/**
* 搜索到的内容回调到
* @param view
* @param poiInfo
*/
@Override
public void callbackForDetails(View view, PoiInfo poiInfo) {
mPoiInfo = poiInfo;
Log.d(TAG,"POI详情回调"+poiInfo.name);
clearMarker();
//构建Marker图标
//初始化位置信息
MapStatusUpdate centerPoint = MapStatusUpdateFactory.newLatLng(poiInfo.location);
mBaiduMap.setMapStatus(centerPoint);
MarkerOptions markerOptions = new MarkerOptions();
BitmapDescriptor bitmapDescriptor4 = BitmapDescriptorFactory.fromResource(R.mipmap.maps_easyicon);
markerOptions.position(poiInfo.location)
//添加图标
.icon(bitmapDescriptor4);
mBaiduMap.addOverlay(markerOptions);
}
@Override
public void navigationPositionCallback(View view, PoiInfo poiInfo) {
mPoiInfo = poiInfo;
Log.d(TAG,"POI导航回调"+poiInfo.name);
if(dialog!=null && dialog.getDialog()!=null
&& dialog.getDialog().isShowing()) {
//dialog is showing so do something
dialog.onStart();
dialog = new MapRouteDialog(mPoiInfo,mLocation,navigationMap);
dialog.show(getSupportFragmentManager(),"路线");
} else {
//dialog is not showing
dialog = new MapRouteDialog(mPoiInfo,mLocation,navigationMap);
dialog.show(getSupportFragmentManager(),"路线");
}
}
}
/**
* 绘制导航路线
*/
public class NavigationMap implements MapRouteDialog.RouteSelectionCallback {
/**
* 不行路线导航回调
* @param walkingRouteLine
*/
@Override
public void walkingRoute(WalkingRouteLine walkingRouteLine) {
clearMarker();
WalkingRouteOverlay overlay = new WalkingRouteOverlay(mBaiduMap);
mBaiduMap.setOnMarkerClickListener(overlay);
overlay.setData(walkingRouteLine);
//把搜索结果添加到百度地图里面
overlay.addToMap();
//把搜索结果显示在同一个屏幕
overlay.zoomToSpan();
}
/**
* 公交路线导航回调
* @param transitRouteLine
*/
@Override
public void busRoutes(TransitRouteLine transitRouteLine) {
clearMarker();
TransitRouteOverlay overlay = new TransitRouteOverlay(mBaiduMap);
mBaiduMap.setOnMarkerClickListener(overlay);
//取出查询出来的所有路线,选择第一条
overlay.setData(transitRouteLine);
//把搜索结果添加到百度地图里面
overlay.addToMap();
//把搜索结果显示在同一个屏幕
overlay.zoomToSpan();
}
/**
* 行车路线导航
* @param drivingRouteLine
*/
@Override
public void drivingDirections(DrivingRouteLine drivingRouteLine) {
clearMarker();
DrivingRouteOverlay overlay = new DrivingRouteOverlay(mBaiduMap);
mBaiduMap.setOnMarkerClickListener(overlay);
overlay.setData(drivingRouteLine);
//把搜索结果添加到百度地图里面
overlay.addToMap();
//把搜索结果显示在同一个屏幕
overlay.zoomToSpan();
}
}
//创建一个热力图服务回调的函数
}
MapSearchDialog
package icu.shaoyayu.android.iearnit.dialog.map;
/**
* @author shaoyayu
* avatar dialog box pops up dialog
*/
public class MapSearchDialog extends BottomDialog {
private static final String TAG = "MapSearchDialog";
PoiSearch mPoiSearch = PoiSearch.newInstance();
//当前的我一个位置
private RecyclerView mShowSearchResults;
private BDLocation location;
private EditText mEnterLocation;
private ImageView mCloseSession;
private Button mFindALocation;
//
private POICallback poiCallback;
public MapSearchDialog(BDLocation location,POICallback poiCallback){
this.location = location;
this.poiCallback = poiCallback;
}
@Override
protected View createView(LayoutInflater inflater, ViewGroup container) {
View view = inflater.inflate(R.layout.dialog_map_search,container,false);
mEnterLocation = view.findViewById(R.id.et_map_location_search);
mCloseSession = view.findViewById(R.id.iv_map_search_dog_close);
mFindALocation = view.findViewById(R.id.bt_find_location);
mShowSearchResults = view.findViewById(R.id.rv_map_search_results);
mCloseSession.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
onStop();
}
});
mFindALocation.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//移除输入的焦点
mEnterLocation.clearFocus();//取消焦点
InputMethodManager imm = (InputMethodManager)getActivity().getSystemService(INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(mEnterLocation.getWindowToken(), 0);
String findContent = mEnterLocation.getText().toString().trim();
Log.d(TAG,"搜索内容:"+findContent);
mPoiSearch.setOnGetPoiSearchResultListener(SearchMonitor);
// Log.d(TAG,"当前城市:"+location.getCity());
PoiCitySearchOption citySearchOption = new PoiCitySearchOption();
// citySearchOption.city(location.getCity());
//测试使用
citySearchOption.city("荆州");
citySearchOption.keyword(findContent);
citySearchOption.pageCapacity(100);
citySearchOption.pageNum(0);
mPoiSearch.searchInCity(citySearchOption);
}
});
return view;
}
@Override
public void onStop() {
//回收资源,适配器等
super.onStop();
//关闭的时候释放资源
mPoiSearch.destroy();
}
public interface SearchResultCallback{
void showChooseALocation();
void showReachLocation();
}
/**
* 搜索回调的监听函数
*/
OnGetPoiSearchResultListener SearchMonitor = new OnGetPoiSearchResultListener() {
@Override
public void onGetPoiResult(PoiResult poiResult) {
if (poiResult == null
|| poiResult.error == SearchResult.ERRORNO.RESULT_NOT_FOUND) {// 没有找到检索结果
Log.d(TAG,"为能找到搜索结果");
Toast.makeText(getContext(), "没有搜索结果", Toast.LENGTH_SHORT).show();
return;
}
if (poiResult.error == SearchResult.ERRORNO.NO_ERROR) {// 检索结果正常返回
List<PoiInfo> allPoi = poiResult.getAllPoi();
for (PoiInfo poiInfo : allPoi) {
Log.d(TAG,poiInfo.name);
}
//Sequence
mShowSearchResults.setAdapter(new ShowSearchDataAdapter(allPoi,poiCallback));
FullyLinearLayoutManager mLinearLayoutManager = new FullyLinearLayoutManager(getContext());
mShowSearchResults.setLayoutManager(mLinearLayoutManager);
}
//调用初始化参数显示
}
@Override
public void onGetPoiDetailResult(PoiDetailSearchResult poiDetailSearchResult) {
}
@Override
public void onGetPoiIndoorResult(PoiIndoorResult poiIndoorResult) {
}
//废弃
@Override
public void onGetPoiDetailResult(PoiDetailResult poiDetailResult) {
}
};
//适配器
class ShowSearchDataAdapter extends RecyclerView.Adapter<MyPolicyInfo>{
List<PoiInfo> policyInfos;
POICallback mPoiCallback;
public ShowSearchDataAdapter(List<PoiInfo> policyInfos,POICallback poiCallback){
this.policyInfos = policyInfos;
this.mPoiCallback = poiCallback;
}
@Override
public int getItemViewType(int position) {
return position;
}
@NonNull
@Override
public MyPolicyInfo onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(getContext());
View view = inflater.inflate(R.layout.view_search_results_item,parent,false);
return new MyPolicyInfo(view);
}
@Override
public void onBindViewHolder(@NonNull MyPolicyInfo holder, final int position) {
holder.poiName.setText( policyInfos.get(position).name);
LatLng current = new LatLng(location.getLatitude(),location.getLongitude());
final LatLng poiPlace = policyInfos.get(position).getLocation();
holder.poiDistance.setText(DistanceUtil.getDistance(current,poiPlace)+"米");
holder.poiDetail.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//设置一个新的位置,然后关闭当前的弹窗
onStop();
mPoiCallback.callbackForDetails(v,policyInfos.get(position));
}
});
holder.poiNavigate.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//导航
onStop();
mPoiCallback.navigationPositionCallback(v,policyInfos.get(position));
}
});
}
@Override
public int getItemCount() {
return policyInfos.size();
}
}
class MyPolicyInfo extends RecyclerView.ViewHolder {
//四个控件
TextView poiName;
TextView poiDistance;
Button poiDetail;
Button poiNavigate;
public MyPolicyInfo(@NonNull View itemView) {
super(itemView);
//实例化参数
poiName = itemView.findViewById(R.id.tv_poi_name);
poiDistance = itemView.findViewById(R.id.tv_poi_distance);
poiDetail = itemView.findViewById(R.id.bt_poi_detail);
poiNavigate = itemView.findViewById(R.id.bt_poi_navigate);
//注册一个点击事件
}
}
public interface POICallback {
/**
* 显示搜索结果
* @param poiInfos
*/
void showSearchResults(List<PoiInfo> poiInfos);
/**
* 详情位置回调
* @param view
* @param poiInfo
*/
void callbackForDetails(View view, PoiInfo poiInfo);
/**
* 导航位置回调
* @param view
* @param poiInfo
*/
void navigationPositionCallback(View view, PoiInfo poiInfo);
}
}
MapRouteDialog
package icu.shaoyayu.android.iearnit.dialog.map;
/**
* @author shaoyayu
* 路线规划类
* 驾车
*/
public class MapRouteDialog extends BottomDialog {
private static final String TAG = "MapRouteDialog";
private ImageView mCloseNavigation;
private PoiInfo poiInfo;
private BDLocation location;
private RoutePlanSearch routePlanSearch;
private RecyclerView mRecyclerView;
private RouteSelectionCallback routeSelectionCallback;
//保存三个搜索结果
private List<WalkingRouteLine> walkingRouteLines = null; //步行 walk
private List<TransitRouteLine> transitRouteLines = null; //公交 bus
private List<DrivingRouteLine> drivingRouteLines = null; //自驾 self_driving
//三个都是继承 navigation_route
public MapRouteDialog(PoiInfo poiInfo,BDLocation location,RouteSelectionCallback routeSelectionCallback){
this.poiInfo = poiInfo;
this.location = location;
this.routeSelectionCallback = routeSelectionCallback;
}
@Override
protected View createView(LayoutInflater inflater, ViewGroup container) {
if (poiInfo!=null&&location!=null){
//自驾导航
routePlanSearch = RoutePlanSearch.newInstance();
routePlanSearch.setOnGetRoutePlanResultListener(new PathOnGetRoutePlanResultListener());
routePlanSearch.drivingSearch(getDrivingRoutePlanOption());
routePlanSearch.transitSearch(getTransitRoutePlanOption());
routePlanSearch.walkingSearch(getWalkingRoutePlanOption());
}
View view = inflater.inflate(R.layout.dialog_map_route,container,false);
mCloseNavigation = view.findViewById(R.id.iv_map_navigation_dog_close);
mRecyclerView = view.findViewById(R.id.rv_navigation_type);
mCloseNavigation.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
onStop();
}
});
//给ViewPage注册适配器
return view;
}
@Override
public void onStop() {
super.onStop();
}
private void initRecyclerViewAdapter(){
if (walkingRouteLines!=null && transitRouteLines!=null && drivingRouteLines!=null){
mRecyclerView.setAdapter(new NavigationAdapter());
FullyLinearLayoutManager mLinearLayoutManager = new FullyLinearLayoutManager(getContext());
mRecyclerView.setLayoutManager(mLinearLayoutManager);
//更新适配器
// mRecyclerView.swapAdapter();
}
}
/**
* 驾车导航
* @return
*/
private DrivingRoutePlanOption getDrivingRoutePlanOption() {
DrivingRoutePlanOption drivingRoutePlanOption = new DrivingRoutePlanOption();
drivingRoutePlanOption.from(PlanNode.withLocation(new LatLng(location.getLatitude(),location.getLongitude())));
drivingRoutePlanOption.to(PlanNode.withLocation(poiInfo.location));
return drivingRoutePlanOption;
}
/**
* 公交导航
* @return
*/
private TransitRoutePlanOption getTransitRoutePlanOption() {
TransitRoutePlanOption transitRoutePlanOption = new TransitRoutePlanOption();
// transitRoutePlanOption.city(location.getCity());
transitRoutePlanOption.city("荆州");
transitRoutePlanOption.from(PlanNode.withLocation(new LatLng(location.getLatitude(),location.getLongitude())));
transitRoutePlanOption.to(PlanNode.withLocation(poiInfo.location));
//路线选型
/*
EBUS_NO_SUBWAY
公交检索策略常量:不含地铁
EBUS_TIME_FIRST
公交检索策略常量:时间优先
EBUS_TRANSFER_FIRST
公交检索策略常量:最少换乘
EBUS_WALK_FIRST
公交检索策略常量:最少步行距离
*/
transitRoutePlanOption.policy(TransitRoutePlanOption.TransitPolicy.EBUS_WALK_FIRST);
return transitRoutePlanOption;
}
/**
* 步行导航
* @return
*/
private WalkingRoutePlanOption getWalkingRoutePlanOption() {
WalkingRoutePlanOption walkingRoutePlanOption = new WalkingRoutePlanOption();
walkingRoutePlanOption.from(PlanNode.withLocation(new LatLng(location.getLatitude(),location.getLongitude())));
walkingRoutePlanOption.to(PlanNode.withLocation(poiInfo.location));
return walkingRoutePlanOption;
}
//规划路线回调
class PathOnGetRoutePlanResultListener implements OnGetRoutePlanResultListener{
/**
* 不行路线回调
* @param walkingRouteResult
*/
@Override
public void onGetWalkingRouteResult(WalkingRouteResult walkingRouteResult) {
// mParcelableRouteLines.add(walkingRouteResult.getRouteLines());
walkingRouteLines = walkingRouteResult.getRouteLines();
for (int i = 0; i < walkingRouteLines.size(); i++) {
Log.d(TAG,i+"步行路线耗时:"+walkingRouteLines.get(i).getDuration()/60+"分钟");
List<WalkingRouteLine.WalkingStep> allStep = walkingRouteLines.get(i).getAllStep();
for (int j = 0; j < allStep.size(); j++) {
Log.d(TAG,i+","+j+",步行路线:"+allStep.get(j).getInstructions());
}
}
initRecyclerViewAdapter();
}
@Override
public void onGetTransitRouteResult(TransitRouteResult transitRouteResult) {
transitRouteLines = transitRouteResult.getRouteLines();
for (int i = 0; i < transitRouteLines.size(); i++) {
Log.d(TAG,i+"公交路线:"+transitRouteLines.get(i).getDuration()/60+"分钟");
List<TransitRouteLine.TransitStep> allStep = transitRouteLines.get(i).getAllStep();
for (int j = 0; j < allStep.size(); j++) {
Log.d(TAG,i+","+j+",公交路线:"+allStep.get(j).getInstructions());
}
}
initRecyclerViewAdapter();
}
@Override
public void onGetMassTransitRouteResult(MassTransitRouteResult massTransitRouteResult) {
}
@Override
public void onGetDrivingRouteResult(DrivingRouteResult drivingRouteResult) {
//所有选择方案
drivingRouteLines = drivingRouteResult.getRouteLines();
for (int i = 0; i < drivingRouteLines.size(); i++) {
Log.d(TAG,i+"自驾:"+drivingRouteLines.get(i).getDuration()/60+"分钟");
DrivingRouteLine drivingRouteLine = drivingRouteLines.get(i);
List<DrivingRouteLine.DrivingStep> allStep = drivingRouteLine.getAllStep();
for (int j = 0; j < allStep.size(); j++) {
Log.d(TAG,i+","+j+",自驾:"+allStep.get(j).getInstructions());
}
}
initRecyclerViewAdapter();
}
@Override
public void onGetIndoorRouteResult(IndoorRouteResult indoorRouteResult) {
}
@Override
public void onGetBikingRouteResult(BikingRouteResult bikingRouteResult) {
}
}
/**
* 适配器,需要在填充的时候填写数据
*/
class NavigationAdapter extends RecyclerView.Adapter<MyRouteDetails>{
@Override
public int getItemViewType(int position) {
return position;
}
@NonNull
@Override
public MyRouteDetails onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(getContext());
View view = inflater.inflate(R.layout.view_navigation_route,parent,false);
return new MyRouteDetails(view);
}
@Override
public void onBindViewHolder(@NonNull MyRouteDetails holder, int position) {
if (position<walkingRouteLines.size()){
holder.routeType.setText("步行路线:"+(position+1));
holder.timeConsumingRoute.setText("耗时:"+walkingRouteLines.get(position).getDuration()/60+" Minute");
holder.startNavigation.setImageResource(R.drawable.ic_walk_foreground);
String content = "";
List<WalkingRouteLine.WalkingStep> allStep = walkingRouteLines.get(position).getAllStep();
for (int j = 0; j < allStep.size(); j++) {
content = content + allStep.get(j).getInstructions()+"\n";
}
holder.routeDetails.setText(content);
//设置一个点击事件,回调
final int finalPosition = position;
holder.startNavigation.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
onStop();
routeSelectionCallback.walkingRoute(walkingRouteLines.get(finalPosition));
}
});
}else if (walkingRouteLines.size()<=position && position<(walkingRouteLines.size()+transitRouteLines.size())){
position = position - walkingRouteLines.size();
holder.routeType.setText("公交路线:"+(position+1));
holder.timeConsumingRoute.setText("耗时:"+transitRouteLines.get(position).getDuration()/60+" Minute");
holder.startNavigation.setImageResource(R.drawable.ic_bus_foreground);
String content = "";
List<TransitRouteLine.TransitStep> allStep = transitRouteLines.get(position).getAllStep();
for (int j = 0; j < allStep.size(); j++) {
content = content + allStep.get(j).getInstructions()+"\n";
}
holder.routeDetails.setText(content);
final int finalPosition = position;
holder.startNavigation.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
onStop();
routeSelectionCallback.busRoutes(transitRouteLines.get(finalPosition));
}
});
}else{
position = position - (walkingRouteLines.size()+transitRouteLines.size());
holder.routeType.setText("驾车路线:"+(position+1));
holder.timeConsumingRoute.setText("耗时:"+drivingRouteLines.get(position).getDuration()/60+" Minute");
holder.startNavigation.setImageResource(R.drawable.ic_self_driving_foreground);
String content = "";
DrivingRouteLine drivingRouteLine = drivingRouteLines.get(position);
List<DrivingRouteLine.DrivingStep> allStep = drivingRouteLine.getAllStep();
for (int j = 0; j < allStep.size(); j++) {
content = content + allStep.get(j).getInstructions()+"\n";
}
holder.routeDetails.setText(content);
final int finalPosition = position;
holder.startNavigation.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
onStop();
routeSelectionCallback.drivingDirections(drivingRouteLines.get(finalPosition));
}
});
}
}
@Override
public int getItemCount() {
int size = 0;
if (walkingRouteLines!=null && walkingRouteLines.size()!=0){
size = size +walkingRouteLines.size();
}
if (transitRouteLines!=null && transitRouteLines.size()!=0){
size = size + transitRouteLines.size();
}
if (drivingRouteLines!=null && drivingRouteLines.size()!=0){
size = size +drivingRouteLines.size();
}
return size;
}
}
class MyRouteDetails extends RecyclerView.ViewHolder {
//四个控件
TextView routeType,timeConsumingRoute,routeDetails;
ImageView startNavigation;
public MyRouteDetails(@NonNull View itemView) {
super(itemView);
routeType = itemView.findViewById(R.id.tv_route_type);
timeConsumingRoute = itemView.findViewById(R.id.tv_time_consuming_route);
routeDetails = itemView.findViewById(R.id.tv_details);
startNavigation = itemView.findViewById(R.id.iv_start_navigation);
}
}
public interface RouteSelectionCallback{
//步行路线规划
void walkingRoute(WalkingRouteLine walkingRouteLine);
//换车路线规划
void busRoutes(TransitRouteLine transitRouteLine );
//驾车路线规划
void drivingDirections(DrivingRouteLine drivingRouteLine);
}
}
MapShareDialog
package icu.shaoyayu.android.iearnit.dialog.map;
/**
* @author shaoyayu
* 位置共享解决方案
*/
public class MapShareDialog extends BottomDialog {
private ImageView mStopDialog;
private Switch locationSharing,trackSharing,recordTrack;
private Intent positioningService;
private TextView mLocationInfo;
private BDLocation mLocation;
public MapShareDialog(BDLocation location){
this.mLocation = location;
}
@Override
protected View createView(LayoutInflater inflater, ViewGroup container) {
View view = inflater.inflate(R.layout.dialog_map_share,container,false);
initTheControl(view);
initData();
return view;
}
//初始化控件
private void initTheControl(View view){
positioningService = new Intent(getContext(), LocationSharingService.class);
mStopDialog = view.findViewById(R.id.iv_map_share_dog_close);
//监控关闭弹窗
mStopDialog.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
onStop();
}
});
//位置共享控件
locationSharing = view.findViewById(R.id.sc_location_sharing);
//判断当前的服务是不是正在执行
if (isServiceRunning("icu.shaoyayu.android.iearnit.service.LocationSharingService")){
//设置为执行状态
locationSharing.setChecked(true);
}
//开关事假
locationSharing.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (isChecked){
//开启
showTips("已经为你开启位置共享");
getActivity().startService(positioningService);
}else {
//关闭
showTips("已经为你关闭位置共享");
getActivity().stopService(positioningService);
}
}
});
//轨迹共享
trackSharing = view.findViewById(R.id.sc_track_sharing);
trackSharing.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (isChecked){
//开启
showTips("已经为你开启轨迹共享");
}else {
//关闭
showTips("已经为你关闭轨迹共享");
}
}
});
//轨迹录制
recordTrack = view.findViewById(R.id.sc_track_record);
recordTrack.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (isChecked){
//开启
showTips("已经为你开启轨迹录制");
}else {
//关闭
showTips("已经为你关闭轨迹录制");
}
}
});
mLocationInfo = view.findViewById(R.id.tv_location_info);
}
//初始化数据
private void initData(){
if (mLocation==null){
mLocationInfo.setText("Positioning failed");
}else {
String province = mLocation.getProvince(); //获取省份
String city = mLocation.getCity(); //获取城市
String district = mLocation.getDistrict(); //获取区县
String street = mLocation.getStreet(); //获取街道信息
String town = mLocation.getTown(); //获取乡镇信息
String desc = mLocation.getLocationDescribe(); //详细信息
String locationInfo = province + city + district + street + town +"\n"+ desc;
mLocationInfo.setText(locationInfo);
}
}
//显示一个对话框提示共享开始,
private void showTips(String str){
Toast.makeText(getContext(), str, Toast.LENGTH_SHORT).show();
}
@Override
public void onStop() {
super.onStop();
}
/**
* 根据服务的名称判断当前的服务是不是正在执行
* @param serviceName
* @return
*/
private boolean isServiceRunning(String serviceName) {
ActivityManager manager = (ActivityManager) getActivity().getSystemService(ACTIVITY_SERVICE);
for (ActivityManager.RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
if (serviceName.equals(service.service.getClassName())) {
return true;
}
}
return false;
}
}
LocationSharingService
package icu.shaoyayu.android.iearnit.service;
/**
* @author shaoyayu
* 实现位置实时共享的一个服务
*/
public class LocationSharingService extends Service implements PositioningService.ContinuousPositioningCallback {
private LocationSharingNetService netService = new LocationSharingNetService();
private static final String TAG = "LocationSharingService";
private PositioningService positioningService;
public LocationSharingService() {
}
@Override
public void onCreate() {
super.onCreate();
positioningService = new PositioningService(getApplicationContext(),this,1500);
}
@Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
throw new UnsupportedOperationException("Not yet implemented");
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
positioningService.startPositioning();
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
super.onDestroy();
positioningService.stopPositioning();
}
//定位后的回调方法
@Override
public void getLocation(BDLocation bdLocation, long timestamp) {
Log.d(TAG,"后台定位:"+timestamp+","+bdLocation.getLatitude()+","+bdLocation.getLongitude());
//没一秒上传一次记录到云端,如果上传失败,整合下次一起上传到云端,删除数据。
String country = bdLocation.getCountry(); //获取国家
String province = bdLocation.getProvince(); //获取省份
String city = bdLocation.getCity(); //获取城市
String district = bdLocation.getDistrict(); //获取区县
String street = bdLocation.getStreet(); //获取街道信息
String adcode = bdLocation.getAdCode(); //获取adcode
String town = bdLocation.getTown(); //获取乡镇信息
String desc = bdLocation.getLocationDescribe(); //详细信息
String locationInfo = timestamp+","+bdLocation.getLatitude()+","+bdLocation.getLongitude()+","+System.currentTimeMillis()+","+country+","+province+","+city+","+district+","+street+","+adcode+","+town+","+desc;
netService.locationSharing("soxswmddl4546dsf45dsf,"+locationInfo);
//直接上传到Redis数据库,LocationSharingService
//写入文件系统里面去存储
}
}
PositioningService
package icu.shaoyayu.android.iearnit.service;
/**
* @author shaoyayu
*/
public class PositioningService {
private Context context;
private ContinuousPositioningCallback callback;
private int spacing = 0;
LocationClient locationClient;
public PositioningService(Context context,final ContinuousPositioningCallback callback,int spacing){
this.context = context;
this.callback = callback;
this.spacing = spacing;
locationClient = new LocationClient(context);
initLocationOption();
}
/**
* 联系位置定位在后台
*/
public void initLocationOption() {
//声明LocationClient类实例并配置定位参数
LocationClientOption locationOption = new LocationClientOption();
LocationSharingLocationListener myLocationListener = new LocationSharingLocationListener();
//注册监听函数
locationClient.registerLocationListener(myLocationListener);
//可选,默认高精度,设置定位模式,高精度,低功耗,仅设备
locationOption.setLocationMode(LocationClientOption.LocationMode.Hight_Accuracy);
//可选,默认gcj02,设置返回的定位结果坐标系,如果配合百度地图使用,建议设置为bd09ll;
locationOption.setCoorType("bd09ll");
//可选,默认0,即仅定位一次,设置发起连续定位请求的间隔需要大于等于1000ms才是有效的
locationOption.setScanSpan(this.spacing);
//可选,设置是否需要地址信息,默认不需要
locationOption.setIsNeedAddress(true);
//可选,设置是否需要地址描述
locationOption.setIsNeedLocationDescribe(true);
//可选,设置是否需要设备方向结果
locationOption.setNeedDeviceDirect(false);
//可选,默认false,设置是否当gps有效时按照1S1次频率输出GPS结果
locationOption.setLocationNotify(true);
//可选,默认true,定位SDK内部是一个SERVICE,并放到了独立进程,设置是否在stop的时候杀死这个进程,默认不杀死
locationOption.setIgnoreKillProcess(true);
//可选,默认false,设置是否需要位置语义化结果,可以在BDLocation.getLocationDescribe里得到,结果类似于“在北京天安门附近”
locationOption.setIsNeedLocationDescribe(true);
//可选,默认false,设置是否需要POI结果,可以在BDLocation.getPoiList里得到
locationOption.setIsNeedLocationPoiList(true);
//可选,默认false,设置是否收集CRASH信息,默认收集
locationOption.SetIgnoreCacheException(false);
//可选,默认false,设置是否开启Gps定位
locationOption.setOpenGps(true);
//可选,默认false,设置定位时是否需要海拔信息,默认不需要,除基础定位版本都可用
locationOption.setIsNeedAltitude(false);
//设置打开自动回调位置模式,该开关打开后,期间只要定位SDK检测到位置变化就会主动回调给开发者,该模式下开发者无需再关心定位间隔是多少,定位SDK本身发现位置变化就会及时回调给开发者
locationOption.setOpenAutoNotifyMode();
//设置打开自动回调位置模式,该开关打开后,期间只要定位SDK检测到位置变化就会主动回调给开发者
locationOption.setOpenAutoNotifyMode(3000,1, LocationClientOption.LOC_SENSITIVITY_HIGHT);
//需将配置好的LocationClientOption对象,通过setLocOption方法传递给LocationClient对象使用
locationClient.setLocOption(locationOption);
//核心实现代码如下,详细代码请参考官网Demo。
//开启前台定位服务:
Notification.Builder builder = new Notification.Builder (context);
//获取一个Notification构造器
Intent nfIntent = new Intent(context, LocationServiceActivity.class);
builder.setContentIntent(PendingIntent.getActivity(context, 0, nfIntent, 0)) // 设置PendingIntent
.setContentTitle("正在进行后台定位") // 设置下拉列表里的标题
.setSmallIcon(R.mipmap.ic_launcher) // 设置状态栏内的小图标
.setContentText("后台定位通知") // 设置上下文内容
.setAutoCancel(true)
.setWhen(System.currentTimeMillis()); // 设置该通知发生的时间
Notification notification = null;
notification = builder.build();
notification.defaults = Notification.DEFAULT_SOUND; //设置为默认的声音
locationClient.enableLocInForeground(1001, notification);// 调起前台定位
//停止前台定位服务:
locationClient.disableLocInForeground(true);// 关闭前台定位,同时移除通知栏
}
/**
* 开始定位
*/
public void startPositioning(){
locationClient.start();
}
/**
* 停止定位
*/
public void stopPositioning(){
locationClient.stop();
}
/**
*
* 实现定位回调
*/
public class LocationSharingLocationListener extends BDAbstractLocationListener {
@Override
public void onReceiveLocation(BDLocation location){
callback.getLocation(location,System.currentTimeMillis());
}
}
public interface ContinuousPositioningCallback{
void getLocation(BDLocation bdLocation,long timestamp);
}
}
添加的权限如下:
<!-- 开启访问网络的权限 -->
<!-- 访问网络,进行地图相关业务数据请求,包括地图数据,路线规划,POI检索等 -->
<uses-permission android:name="android.permission.INTERNET" /> <!-- 日历权限 -->
<uses-permission android:name="android.permission.READ_CALENDAR" />
<uses-permission android:name="android.permission.WRITE_CALENDAR" />
<!-- 获取网络状态,根据网络状态切换进行数据请求网络转换 -->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<!-- 读取外置存储。如果开发者使用了so动态加载功能并且把so文件放在了外置存储区域,则需要申请该权限,否则不需要 -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<!-- 写外置存储。如果开发者使用了离线地图,并且数据写在外置存储区域,则需要申请该权限 -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<!-- 这个权限用于进行网络定位 -->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<!-- 这个权限用于访问GPS定位 -->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<!-- 用于访问wifi网络信息,wifi信息会用于进行网络定位 -->
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<!-- 这个权限用于获取wifi的获取权限,wifi信息会用来进行网络定位 -->
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
界面代码:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".activity.service.LocationServiceActivity">
<!--自定义状态栏-->
<icu.shaoyayu.android.iearnit.view.SimpleMenu
android:id="@+id/menu_location_service"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="parent" />
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.baidu.mapapi.map.MapView
android:id="@+id/mp_location_service"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clickable="true">
</com.baidu.mapapi.map.MapView>
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/fab_map_search"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="10dp"
android:layout_marginBottom="240dp"
android:clickable="true"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:srcCompat="@android:drawable/ic_menu_search" />
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/fab_map_route"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="10dp"
android:layout_marginBottom="160dp"
android:clickable="true"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:srcCompat="@android:drawable/ic_menu_send" />
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/fab_map_share"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="10dp"
android:layout_marginBottom="80dp"
android:clickable="true"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:srcCompat="@android:drawable/ic_menu_myplaces" />
<Switch
android:background="@drawable/recommended_album_popup"
android:id="@+id/sc_open_heat_map"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="15dp"
android:layout_marginEnd="15dp"
android:text="开启热力图"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</LinearLayout>
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="720dp"
android:orientation="vertical">
<LinearLayout
android:padding="12dp"
android:background="@drawable/recommended_album_popup"
android:layout_width="match_parent"
android:layout_height="720dp"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="30dp"
android:gravity="center"
android:orientation="vertical">
<ImageView
android:id="@+id/iv_map_search_dog_close"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/ic_down_foreground"/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<EditText
android:id="@+id/et_map_location_search"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:background="@null"
android:layout_weight="5"
android:hint="请输入"/>
<Button
android:id="@+id/bt_find_location"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="开始查找" />
</LinearLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv_map_search_results"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
</LinearLayout>
<?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="720dp"
android:background="@drawable/recommended_album_popup"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="30dp"
android:gravity="center"
android:orientation="vertical">
<ImageView
android:id="@+id/iv_map_navigation_dog_close"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/ic_down_foreground"/>
</LinearLayout>
<LinearLayout
android:padding="12dp"
android:layout_width="match_parent"
android:layout_height="690dp"
android:orientation="vertical">
<RadioGroup
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<RadioButton
android:gravity="center"
android:layout_width="wrap_content"
android:layout_weight="1"
android:button="@null"
android:layout_height="wrap_content"
android:text="驾车导航"/>
<RadioButton
android:gravity="center"
android:layout_weight="1"
android:button="@null"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="驾车导航"/>
<RadioButton
android:gravity="center"
android:layout_weight="1"
android:button="@null"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="驾车导航"/>
</RadioGroup>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv_navigation_type"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
</LinearLayout>
<?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="720dp"
android:background="@drawable/recommended_album_popup"
android:orientation="vertical">
<!--设置一个滚动滚动条-->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="30dp"
android:gravity="center"
android:orientation="vertical">
<ImageView
android:id="@+id/iv_map_share_dog_close"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/ic_down_foreground"/>
</LinearLayout>
<LinearLayout
android:padding="15dp"
android:layout_width="match_parent"
android:layout_height="720dp"
android:orientation="vertical">
<TextView
android:padding="5dp"
android:textStyle="bold"
android:textSize="22sp"
android:id="@+id/tv_location_info"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="location information" />
<Switch
android:layout_margin="5dp"
android:id="@+id/sc_location_sharing"
android:textSize="20sp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="位置共享" />
<Switch
android:layout_margin="5dp"
android:id="@+id/sc_track_sharing"
android:textSize="20sp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="轨迹共享" />
<Switch
android:layout_margin="5dp"
android:id="@+id/sc_track_record"
android:textSize="20sp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="轨迹录制" />
<TextView
android:layout_margin="5dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textStyle="bold"
android:text="记录"
android:textSize="20sp"/>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv_location_history"
android:layout_margin="5dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</LinearLayout>
</LinearLayout>
5、结果及分析
手机实验的验证过程:
我们采用测试数据,把位置替换成长江大学文理学院,把城市替换成荆州。
1、 今天activity见面,就可以实现当前位置的定位,在右下角有三个图标,
2、 点击第一个搜索图标,弹出一个弹窗,弹窗上面的按钮可以退出弹窗,输入搜索内容,就会在当前城市搜索出50个以下的搜索结构出现,可滑动选择。
3、 点击搜索结果的定位按钮,就可以直接定位到搜索结果的地方,
4、 点击搜索结果的导航按钮,就会弹出一个导航的弹窗,在导航弹窗里面,我们提供你三种导航方案,步行导航,换成导航和驾车导航三种导航方式,每种导航方式都有不同的导航方案,在每一个导航的方案右侧有个导航标识。
5、 点击导航标识,就可以退出导航窗口,在地图上面看到一条导航的路线绘制出来。
6、 点击activity的右下角最后一个图标,就可以弹出定位相关的位置信息显示出来,在位置信息下面还有“位置共享”,“轨迹共享”和“轨迹录制”三种功能,
7、 开启位置共享功能,程序会启动一个后台的服务,后台服务会两秒钟地位一次位置,讲定位到的位置信息即时的通过UDP协议发送给服务器。同时还会通过文件的形式写入本地,形成一次位置记录信息。
8、 共享轨迹功能。会开启一个后台服务,不停的位置用户定位,但是不会即时发送用户的信息到服务器端,会先写入本地保存,间隔一定的时间后会上传运动轨迹到服务器,可以降低用户的流量消耗和手机电量消耗。
9、 录制轨迹功能,会开启一个后台的服务,监控用户的位置信息,讲用户的位置信息写入本地文件中,不会上传到服务器上,用户可以选择是否上传。上传后会生成一个共享连接。
手机屏幕截图如下: