package com.dayu.pipirrapp.fragment; import static com.dayu.pipirrapp.net.Constants.BASE_URL; import android.content.Context; import android.content.Intent; import android.content.res.Resources; import android.net.Uri; import android.os.Bundle; import android.text.TextUtils; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.webkit.ValueCallback; import android.webkit.WebResourceError; import android.webkit.WebResourceRequest; import android.webkit.WebResourceResponse; import android.webkit.WebView; import android.webkit.WebViewClient; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.core.content.ContextCompat; import androidx.lifecycle.Observer; import com.dayu.pipirrapp.MyApplication; import com.dayu.pipirrapp.R; import com.dayu.pipirrapp.activity.AddIssueActivity; import com.dayu.pipirrapp.bean.db.CenterPointBean; import com.dayu.pipirrapp.bean.db.DivideBean; import com.dayu.pipirrapp.bean.db.InspectionBean; import com.dayu.pipirrapp.bean.db.InspectionLocationBean; import com.dayu.pipirrapp.bean.db.LatLonBean; import com.dayu.pipirrapp.bean.db.MarkerBean; import com.dayu.pipirrapp.bean.db.PipeNetWorkDataBean; import com.dayu.pipirrapp.bean.db.PipeNetworkBean; import com.dayu.pipirrapp.bean.db.PipeNetworkDataCoordinateBean; import com.dayu.pipirrapp.bean.net.BaseListResult; import com.dayu.pipirrapp.bean.net.CenterPointResult; import com.dayu.pipirrapp.bean.net.DivideListResult; import com.dayu.pipirrapp.bean.net.DivideResult; import com.dayu.pipirrapp.bean.net.InsectionResult; import com.dayu.pipirrapp.bean.net.InspectionRequest; import com.dayu.pipirrapp.bean.net.IntakeListResult; import com.dayu.pipirrapp.bean.net.IntakeResult; import com.dayu.pipirrapp.bean.net.MarkerListResult; import com.dayu.pipirrapp.bean.net.MarkerResult; import com.dayu.pipirrapp.bean.net.PipeNetworkResult; import com.dayu.pipirrapp.dao.DaoSingleton; import com.dayu.pipirrapp.databinding.FragmentMapBinding; import com.dayu.pipirrapp.net.ApiManager; import com.dayu.pipirrapp.net.BaseResponse; import com.dayu.pipirrapp.net.Constants; import com.dayu.pipirrapp.net.subscribers.SubscriberListener; import com.dayu.pipirrapp.observer.MapFragmenObserver; import com.dayu.pipirrapp.tool.InspectionUtils; import com.dayu.pipirrapp.tool.MarkerUtils; import com.dayu.pipirrapp.tool.MyWebViewInterface; import com.dayu.pipirrapp.utils.CommonData; import com.dayu.pipirrapp.utils.CommonKeyName; import com.dayu.pipirrapp.utils.DateUtils; import com.dayu.pipirrapp.utils.MapJpgUtils; import com.dayu.pipirrapp.utils.MyLog; import com.dayu.pipirrapp.utils.ServiceUtils; import com.dayu.pipirrapp.utils.SharedPreferencesHelper; import com.dayu.pipirrapp.utils.ToastUtil; import com.dayu.pipirrapp.utils.WebViewUtils; import com.dayu.pipirrapp.view.ConfirmDialog; import com.dayu.pipirrapp.view.SearchResultDialog; import com.dayu.pipirrapp.view.TipUtil; import com.example.expand_button.ExpandButton; import com.hjq.permissions.OnPermissionCallback; import com.hjq.permissions.Permission; import com.hjq.permissions.XXPermissions; import com.jeremyliao.liveeventbus.LiveEventBus; import com.tencent.bugly.crashreport.CrashReport; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.stream.Collectors; import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers; import io.reactivex.rxjava3.disposables.CompositeDisposable; import io.reactivex.rxjava3.schedulers.Schedulers; import io.reactivex.rxjava3.core.Single; /** * author: zuo * Date: 2023/12/20 * Time: 10:16 * 备注:地图页 */ public class MapFragment extends BaseFragment { static String TAG = "MapFragment"; FragmentMapBinding binding; WebView mWebView; CenterPointBean centerPointBean; //当前巡检状态 int mInspectionState; MapFragmenObserver mapFragmenObserver; //当前巡检记录的相关信息 public InspectionBean mInspectionBean; //最后一次定位的坐标 LatLonBean lastLatLonBean; //web是否加载完成 volatile boolean webViewIsFinished = false; List aginShowlocationBeans; //web加载时网页还没加载完时的数据 List webNoFinishMarkerData = new ArrayList<>(); List webNoFinishDivideData = new ArrayList<>(); List webNoFinishPipeNetworkData = new ArrayList<>(); //所有的Marker数据键为marker的Id Map markerBeanSet = new HashMap<>(); //所有分水房 Map divideBeanMap = new HashMap<>(); //中心点坐标 public double centerLng; public double centerLat; MarkerBean mMarkerBean; //是否显示Marker boolean isShowMarker, isShowPipeNetwork, isShowDivide; // 添加CompositeDisposable来管理所有订阅 private CompositeDisposable compositeDisposable = new CompositeDisposable(); @Override public void onAttach(@NonNull Context context) { super.onAttach(context); Log.i(TAG, "onAttach"); mapFragmenObserver = new MapFragmenObserver(); requireActivity().getLifecycle().addObserver(mapFragmenObserver); } @Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setRetainInstance(true); Log.i(TAG, "onCreate"); mInspectionState = SharedPreferencesHelper.getInstance(this.getContext()).get(CommonKeyName.inspectionState, 0); // 添加刷新数据的监听 LiveEventBus.get(CommonKeyName.refreshData).observe(this, o -> { // 显示加载动画 TipUtil.showLoading(MapFragment.this.getActivity(), "正在更新数据..."); // 创建多个Single对象来表示每个网络请求 Single centerPointSingle = Single.create(emitter -> { getCenterPoint(); emitter.onSuccess(true); }); Single markerDataSingle = Single.create(emitter -> { getMarkerData(); emitter.onSuccess(true); }); Single divideListSingle = Single.create(emitter -> { getDivideList(); emitter.onSuccess(true); }); Single pipeNetworkListSingle = Single.create(emitter -> { getPipeNetworkList(); emitter.onSuccess(true); }); // 组合所有Single compositeDisposable.add( Single.zip( centerPointSingle, markerDataSingle, divideListSingle, pipeNetworkListSingle, (centerPoint, marker, divide, pipe) -> true ) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .doFinally(() -> { // 无论成功还是失败,都需要隐藏加载动画 TipUtil.dismissLoading(); }) .subscribe( result -> { ToastUtil.showToast(MapFragment.this.getContext(), "数据更新完成"); }, throwable -> { Log.e(TAG, "数据更新失败: " + throwable.getMessage()); ToastUtil.showToast(MapFragment.this.getContext(), "数据更新失败"); } ) ); }); } @Override public void onStart() { super.onStart(); Log.i(TAG, "onStart"); } @Nullable @Override public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { binding = FragmentMapBinding.inflate(inflater, container, false); mapFragmenObserver.setmWebView(binding.webView); Log.i("MapFragment", "onCreateView"); mWebView = binding.webView; mWebView = WebViewUtils.initWebView(mWebView); MyWebViewInterface myWebViewInterface = new MyWebViewInterface(MapFragment.this); mWebView.addJavascriptInterface(myWebViewInterface, "Android"); mWebView.loadUrl("file:///android_asset/index.html"); // 异步加载本地数据 loadLocalData(); initView(); initWeb(); chageInspecState(mInspectionState); return binding.getRoot(); } /** * 异步加载本地数据 */ private void loadLocalData() { // 异步加载中心点数据 compositeDisposable.add( DaoSingleton.getAsynchInstance(this.getContext()).centerPointDao().findFirst() .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(result -> { centerPointBean = result; if (centerPointBean == null) { getCenterPoint(); } else { jumpCenterPoint(); } }, throwable -> { Log.e(TAG, "Load centerPoint error: " + throwable); getCenterPoint(); }, () -> { // 当Maybe为空时调用 getCenterPoint(); }) ); isShowMarker = SharedPreferencesHelper.getInstance(this.getContext()).get(CommonKeyName.markerKeyIsShow, true); // 异步加载取水口数据 compositeDisposable.add( DaoSingleton.getAsynchInstance(this.getContext()).markerDao().getAll() .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(markers -> { if (markers == null || markers.isEmpty()) { getMarkerData(); } else { for (MarkerBean marker : markers) { markerBeanSet.put(marker.getId(), marker); setMapMarker(marker); } } }, throwable -> { Log.e(TAG, "Load markers error: " + throwable.getMessage()); getMarkerData(); }, () -> { // 当Maybe为空时调用 getMarkerData(); }) ); isShowDivide = SharedPreferencesHelper.getInstance(this.getContext()).get(CommonKeyName.divideIsShow, true); // 异步加载分水房数据 compositeDisposable.add( DaoSingleton.getAsynchInstance(this.getContext()).divideDao().getAll() .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(divides -> { if (divides == null || divides.isEmpty()) { getDivideList(); } else { for (DivideBean divide : divides) { divideBeanMap.put(divide.getId(), divide); setMapDivide(divide); } } }, throwable -> { Log.e(TAG, "Load divides error: " + throwable.getMessage()); getDivideList(); }, () -> { // 当Maybe为空时调用 getDivideList(); }) ); isShowPipeNetwork = SharedPreferencesHelper.getInstance(this.getContext()).get(CommonKeyName.pipeNetworkIsShow, true); //异步加载管网数据 compositeDisposable.add( DaoSingleton.getAsynchInstance(this.getContext()).pipeNetDao().getAll() .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(pipeNetworkBeans -> { if (pipeNetworkBeans == null || pipeNetworkBeans.isEmpty()) { getPipeNetworkList(); } else { for (PipeNetworkBean pipeNetworkBean : pipeNetworkBeans) { setMapPipe(pipeNetworkBean); } } }, throwable -> { Log.e(TAG, "Load PipeNetworkBean error: " + throwable.getMessage()); getPipeNetworkList(); }, () -> { // 当Maybe为空时调用 getPipeNetworkList(); }) ); } private void initWeb() { mWebView.setWebViewClient(new WebViewClient() { @Override public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) { String url = request.getUrl().toString(); //判断当前是否为加载瓦片 if (MapJpgUtils.getInsatance().isTianDiTuTileRequest(url)) { String androidUrl = url.replace(CommonData.webKey, CommonData.androidKey); // 检查本地缓存 File cachedTile = MapJpgUtils.getInsatance().getCachedTile(androidUrl); if (cachedTile != null && cachedTile.exists()) { // 检查文件是否超过6个月 long sixMonthsInMillis = 6L * 30 * 24 * 60 * 60 * 1000; // 6个月的毫秒数 long fileAge = System.currentTimeMillis() - cachedTile.lastModified(); if (fileAge > sixMonthsInMillis) { // 如果文件超过6个月,删除旧文件并重新下载 if (cachedTile.delete()) { Log.d(TAG, "已删除过期瓦片: " + androidUrl); } else { Log.e(TAG, "删除过期瓦片失败: " + androidUrl); } ApiManager.getInstance().donwLoadTile(MapFragment.this.getContext(), androidUrl); } else { try { // 从缓存加载瓦片 return new WebResourceResponse("image/jpg", "utf-8", new FileInputStream(cachedTile)); } catch (FileNotFoundException e) { e.printStackTrace(); } } } else { //下载瓦片 ApiManager.getInstance().donwLoadTile(MapFragment.this.getContext(), androidUrl); } } return super.shouldInterceptRequest(view, request); } @Override public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) { super.onReceivedError(view, request, error); // 捕获加载过程中发生的错误 int errorCode = error.getErrorCode(); String description = error.getDescription().toString(); String failingUrl = request.getUrl().toString(); Log.e("setWebViewClient", "errorCode:" + errorCode + ">>>>description:" + description + ">>>>failingUrl:" + failingUrl); // 处理错误,例如显示错误页面或提示用户 } @Override public void onReceivedHttpError(WebView view, WebResourceRequest request, WebResourceResponse errorResponse) { super.onReceivedHttpError(view, request, errorResponse); // 捕获HTTP错误(如404, 500等) int statusCode = errorResponse.getStatusCode(); String description = errorResponse.getReasonPhrase(); Log.e("setWebViewClient", "statusCode:" + statusCode + ">>>>description:" + description); // 根据HTTP状态码处理错误 } @Override public void onPageFinished(WebView view, String url) { super.onPageFinished(view, url); //页面加载完成 webViewIsFinished = true; webFinishInitLocalData(); aginShowLocation(null); } }); } /** * web加载完初始化本地数据 */ public void webFinishInitLocalData() { // 只在本地没有数据时获取中心点 if (centerPointBean != null) { jumpCenterPoint(); } //添加因webview没有加载完成导致没有添加的地图标注 if (!webNoFinishMarkerData.isEmpty()) { for (MarkerBean bean : webNoFinishMarkerData) { setMapMarker(bean); } } if (!webNoFinishDivideData.isEmpty()) { for (DivideBean bean : webNoFinishDivideData) { setMapDivide(bean); } } if (!webNoFinishPipeNetworkData.isEmpty()) { for (PipeNetworkBean bean : webNoFinishPipeNetworkData) { setMapPipe(bean); } } //显示所有取水口 MarkerUtils.showLocoMarks(MapFragment.this); //显示巡检状态并且显示因意外关闭的历史数据 switch (mInspectionState) { case InspectionUtils.STAT_INSPECTION: case InspectionUtils.PAUSE_INSPECTION: InspectionUtils.aginShowLocation(MapFragment.this); } } /** * 获取取水口列表 */ private void getMarkerData() { ApiManager.getInstance().requestGetHideLoading(this.getContext(), Constants.BASE_URL + "/project/intake/all", MarkerListResult.class, null, new SubscriberListener>() { @Override public void onNext(BaseResponse t) { if (t.isSuccess()) { if (t.getContent().getObj() != null && !t.getContent().getObj().isEmpty()) { List markerBeans = t.getContent().getObj().stream() .map(result -> { MarkerBean markerBean = new MarkerBean(); markerBean.setId(result.getId()); markerBean.setLng(result.getLng()); markerBean.setLat(result.getLat()); markerBean.setBlockId(result.getBlockId()); markerBean.setName(result.getName()); markerBean.setRemarks(result.getRemarks()); markerBean.setTownId(result.getTownId()); markerBean.setVillageId(result.getVillageId()); markerBean.setCountyId(result.getCountyId()); markerBean.setAddress(result.getAddress()); markerBean.setBlockName(result.getBlockName()); markerBean.setDivideId(result.getDivideId()); setMapMarker(markerBean); return markerBean; }) .collect(Collectors.toList()); DaoSingleton.getInstance(MapFragment.this.getContext()).markerDao().deleteAll(); // 使用 CompositeDisposable 管理数据库插入操作 compositeDisposable.add( DaoSingleton.getAsynchInstance(MapFragment.this.getContext()).markerDao().insertAll(markerBeans) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe( () -> { // 插入成功 Log.i("mWebView", "数据插入成功"); }, throwable -> { // 插入失败 Log.e("mWebView", "数据插入失败: " + throwable.getMessage()); } ) ); } } else { ToastUtil.showToast(MapFragment.this.getContext(), t.getMsg()); } } }); } void initView() { //巡检按钮 binding.inspectButton.setOnClickListener(v -> { if (XXPermissions.isGranted(MapFragment.this.getContext(), Permission.ACCESS_BACKGROUND_LOCATION)) { new ConfirmDialog(MapFragment.this.getActivity(), "确认开始巡检吗?", (confirmDialog, v1) -> { chageInspecState(InspectionUtils.STAT_INSPECTION_ONCLICK); confirmDialog.dismiss(); }).show(); } else { TipUtil.show(MapFragment.this.getActivity(), "巡检定位需要您选择\"始终允许\"定位信息,否则无法巡检。", new TipUtil.TipListener() { @Override public void onCancle() { getPermissions(); } }); } }); //暂停巡检 binding.inspectPause.setOnClickListener(v -> { if (mInspectionState == InspectionUtils.STAT_INSPECTION) { chageInspecState(InspectionUtils.PAUSE_INSPECTION); } else { chageInspecState(InspectionUtils.STAT_INSPECTION); } }); //停止巡检 binding.inspectClose.setOnClickListener(v -> { chageInspecState(InspectionUtils.STOP_INSPECTION); }); //上报问题 binding.putButton.setOnClickListener(v -> { new ConfirmDialog(MapFragment.this.getActivity(), "确认上报问题吗?", (confirmDialog, v1) -> { Intent issue = new Intent(MapFragment.this.getActivity(), AddIssueActivity.class); MapFragment.this.getActivity().startActivity(issue); confirmDialog.dismiss(); }).show(); }); binding.expandButton.setLegendsArray(new ExpandButton.Quadruple( ContextCompat.getDrawable(requireContext(), R.drawable.marker_blue), ContextCompat.getDrawable(requireContext(), R.drawable.marker_unselected), "取水口", isShowMarker ), new ExpandButton.Quadruple( ContextCompat.getDrawable(requireContext(), R.drawable.divide_home_blue), ContextCompat.getDrawable(requireContext(), R.drawable.divide_home_unselected), "分水房", isShowDivide ), new ExpandButton.Quadruple( ContextCompat.getDrawable(requireContext(), R.drawable.ic_pipenetwork_line), ContextCompat.getDrawable(requireContext(), R.drawable.ic_pipenetwork_line_unselected), "管网", isShowPipeNetwork ) ); binding.expandButton.setOnLegendItemClickListener((position, isSelected) -> { switch (position) { case 0: showMarkers(isSelected); SharedPreferencesHelper.getInstance(this.getContext()).put(CommonKeyName.markerKeyIsShow, isSelected); break; case 1: showDivideMarkers(isSelected); SharedPreferencesHelper.getInstance(this.getContext()).put(CommonKeyName.divideIsShow, isSelected); break; case 2: showPipeLine(isSelected); SharedPreferencesHelper.getInstance(this.getContext()).put(CommonKeyName.pipeNetworkIsShow, isSelected); break; } }); binding.searchButton.setOnSearchClickListener(s -> { if (s != null && !s.isEmpty()) { SearchResultDialog searchDialog = new SearchResultDialog(requireContext()); searchDialog.setOnItemClickListener(item -> { // 根据类型处理点击事件 // if ("marker".equals(item.getType())) { // MarkerBean markerBean = new MarkerBean(); // markerBean.setId(item.getId()); // getInstakeDetail(markerBean); // } else { // DivideBean divideBean = new DivideBean(); // divideBean.setDivideId(item.getId()); // getDivideDetail(divideBean); // } // 跳转到选择的位置 mWebView.evaluateJavascript( String.format("javascript:setCenterAndZoom(\"%s\",\"%s\",\"17\")", item.getLng(), item.getLat()), null ); }); // 执行搜索 compositeDisposable.add( DaoSingleton.getAsynchInstance(requireContext()) .divideDao() .searchAllByKeyword(s) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe( results -> { if (results != null && !results.isEmpty()) { searchDialog.setData(results); searchDialog.show(); } else { ToastUtil.showToast(requireContext(), "未找到相关结果"); } }, throwable -> { ToastUtil.showToast(requireContext(), "搜索失败:" + throwable.getMessage()); } ) ); } return null; }); } /** * 显示取水口详情 * * @param data */ public void showWaterIntakeDetail(String data) { MyLog.i(data); MarkerBean markerBean = markerBeanSet.get(data); if (markerBean != null) { getInstakeDetail(markerBean); } } /** * 显示分水房详情 * * @param data */ public void showDivideDetail(String data) { MyLog.i(data); DivideBean markerBean = divideBeanMap.get(data); if (markerBean != null) { binding.bottomLL.setVisibility(View.GONE); getDivideDetail(markerBean); } } /** * 获取地图中心点 */ private void getCenterPoint() { ApiManager.getInstance().requestGetHideLoading(this.getContext(), Constants.BASE_URL + "/base/dict_item/map_center", CenterPointResult.class, null, new SubscriberListener>() { @Override public void onNext(BaseResponse t) { if (t.isSuccess()) { if (centerPointBean == null) { centerPointBean = new CenterPointBean(); } centerPointBean.setLat(t.getContent().getLat()); centerPointBean.setLng(t.getContent().getLng()); centerPointBean.setZoomMp(t.getContent().getZoomMp()); DaoSingleton.getInstance(MapFragment.this.getContext()).centerPointDao().deleteAll(); DaoSingleton.getInstance(MapFragment.this.getContext()).centerPointDao().insert(centerPointBean); jumpCenterPoint(); } else { ToastUtil.showToast(MapFragment.this.getContext(), t.getMsg()); } } }); } /** * 隐藏底部布局的动画效果 */ private void hideBottomLayoutWithAnimation() { binding.bottomLL.animate() .translationY(binding.bottomLL.getHeight()) .setDuration(300) .setInterpolator(new android.view.animation.AccelerateInterpolator()) .withEndAction(() -> { binding.bottomLL.setVisibility(View.GONE); binding.bottomLL.setTranslationY(0); }) .start(); } public void closeWaterIntakeDetail() { hideBottomLayoutWithAnimation(); } /** * 上报巡检记录 */ private void pushLocationData(InspectionLocationBean inspectionLocationBean) { InspectionRequest inspectionRequest = InspectionRequest.getInstance(); inspectionRequest.setInspectId(inspectionLocationBean.getInspectId()); inspectionRequest.setInspectorId(mInspectionBean.getInspectorId()); if (mInspectionBean != null) { inspectionRequest.setStartTime(mInspectionBean.getStartTime()); if (!TextUtils.isEmpty(mInspectionBean.getStopTime())) { inspectionRequest.setStopTime(mInspectionBean.getStopTime()); } } InspectionRequest.Track track = new InspectionRequest.Track(); track.setLat(inspectionLocationBean.getLat()); track.setLng(inspectionLocationBean.getLng()); track.setLocateTime(inspectionLocationBean.getLocateTime()); inspectionRequest.addTracks(track); ApiManager.getInstance().requestPostHideLoading(MapFragment.this.getContext(), BASE_URL + "/app/inspect/save", InsectionResult.class, inspectionRequest.toMap(inspectionRequest), new SubscriberListener>>() { @Override public void onNext(BaseResponse> t) { try { if (t.isSuccess()) { if (t.getContent() != null) { MyLog.d("InspectId:" + String.valueOf(t.getContent().get(0).getInspectId())); mInspectionBean.setInspectId(String.valueOf(t.getContent().get(0).getInspectId())); InspectionUtils.upataInspectionData(MapFragment.this.getContext(), mInspectionBean); } inspectionLocationBean.setPost(true); InspectionUtils.updateInspectionLocationData(MapFragment.this.getContext(), inspectionLocationBean); } else { } } catch (Exception e) { e.printStackTrace(); CrashReport.postCatchedException(e); } } }); } /** * 定位监听 */ private Observer locationObserver = new Observer() { @Override public void onChanged(Object o) { if (mInspectionBean != null) { LatLonBean latLonBean = (LatLonBean) o; if (InspectionUtils.isThanMinMeters(lastLatLonBean, latLonBean)) { //大于最小距离 lastLatLonBean = latLonBean; Log.i("chageInspecState", "lat:" + latLonBean.getLatitude() + ",log:" + latLonBean.getLongitude()); InspectionLocationBean inspectionLocationBean = InspectionUtils.createInspectionLocation(latLonBean, mInspectionBean); //添加巡检记录坐标 InspectionUtils.addInspectionLocationData(MapFragment.this.getContext(), inspectionLocationBean); //更新到地图 mWebView.evaluateJavascript("javascript:updateInspectionLocation(\"" + latLonBean.getLongitude() + "\",\"" + latLonBean.getLatitude() + "\")", value -> { }); mWebView.evaluateJavascript("javascript:updateLocation(\"" + latLonBean.getLongitude() + "\",\"" + latLonBean.getLatitude() + "\")", value -> { }); //上传坐标 pushLocationData(inspectionLocationBean); } else { Log.d(TAG, "isThanMinMeters>>>false"); } } } }; /** * 修改巡检状态 * * @param inspectionState */ private void chageInspecState(int inspectionState) { //0没有开始,1开始,2暂停,3关闭 switch (inspectionState) { case InspectionUtils.NO_INSPECTION: binding.inspectButton.setVisibility(View.VISIBLE); binding.inspectRL.setVisibility(View.GONE); binding.inspectButton.setText("巡"); LiveEventBus.get(CommonKeyName.locationData).removeObserver(locationObserver); //关闭定位 ServiceUtils.stopLocationService(MapFragment.this.getContext()); break; case InspectionUtils.STAT_INSPECTION_ONCLICK: //添加新的巡检记录 mInspectionBean = InspectionUtils.startInspection(this.getContext()); startLocation(); break; case InspectionUtils.STAT_INSPECTION://1开始 startLocation(); break; case InspectionUtils.PAUSE_INSPECTION://暂停 try { //关闭定位 ServiceUtils.stopLocationService(MapFragment.this.getContext()); binding.stateText.setText("已暂停巡检"); binding.inspectPause.setText("继续"); binding.inspectRL.setBackgroundColor(this.getContext().getResources().getColor(R.color.inspect_rl_bg_color)); SharedPreferencesHelper.getInstance(this.getContext()).put(CommonKeyName.inspectionState, InspectionUtils.PAUSE_INSPECTION); //清除地图巡检轨迹 mWebView.evaluateJavascript("javascript:cleanLoclLay()", value -> { }); } catch (Resources.NotFoundException e) { e.printStackTrace(); } break; case InspectionUtils.STOP_INSPECTION://关闭 ConfirmDialog confirmDialog = new ConfirmDialog(MapFragment.this.getActivity(), "提示", "确认关闭巡检吗?", new ConfirmDialog.ConfirmOnClickListener() { @Override public void onClick(ConfirmDialog confirmDialog, View v) { confirmDialog.dismiss(); chageInspecState(InspectionUtils.NO_INSPECTION); SharedPreferencesHelper.getInstance(MapFragment.this.getContext()).put(CommonKeyName.inspectionState, InspectionUtils.NO_INSPECTION); //有可能还没获取到定位信息就结束巡检了 if (lastLatLonBean != null) { //更新本地数据库结束时间 mInspectionBean.setStopTime(DateUtils.getNowDateStr()); InspectionUtils.upataInspectionData(MapFragment.this.getContext(), mInspectionBean); //上报结束时间 InspectionLocationBean inspectionLocationBean = InspectionUtils.createInspectionLocation(lastLatLonBean, mInspectionBean); InspectionUtils.addInspectionLocationData(MapFragment.this.getContext(), inspectionLocationBean); pushLocationData(inspectionLocationBean); mInspectionBean = new InspectionBean(); //清除地图巡检轨迹 mWebView.evaluateJavascript("javascript:cleanLocationLay()", value -> { }); lastLatLonBean = null; } } }); confirmDialog.show(); break; default: } mInspectionState = inspectionState; } /** * 意外退出后继续显示之前的坐标 */ public void aginShowLocation(List locationBeans) { if (locationBeans != null) { aginShowlocationBeans = locationBeans; } if (webViewIsFinished) { if (aginShowlocationBeans != null) { for (InspectionLocationBean inspectionLocationBean : aginShowlocationBeans) { Log.i("mWebView", "aginShowLocation" + inspectionLocationBean.getLng() + "\",\"" + inspectionLocationBean.getLat()); mWebView.evaluateJavascript("javascript:aginShowLocation(\"" + inspectionLocationBean.getLng() + "\",\"" + inspectionLocationBean.getLat() + "\")", value -> { }); } // 向 WebView 注入数据 aginShowlocationBeans.clear(); } } } /** * 跳转地图中心点 */ public void jumpCenterPoint() { if (webViewIsFinished) { if (centerPointBean != null) { Log.d(TAG, "jumpCenterPoint>>>>>>>>>>>>>>>>>>>" + centerPointBean.getLng() + "\",\"" + centerPointBean.getLat()); mWebView.evaluateJavascript("javascript:setCenterAndZoom(\"" + centerPointBean.getLng() + "\",\"" + centerPointBean.getLat() + "\",\"" + centerPointBean.getZoomMp() + "\")", value -> { }); } } } /** * 添加取水口 */ public void setMapMarker(MarkerBean markerBean) { if (markerBean != null) { if (webViewIsFinished) { if (!TextUtils.isEmpty(markerBean.getLng()) && !TextUtils.isEmpty(markerBean.getLat())) { mWebView.evaluateJavascript("javascript:addMarker(\"" + markerBean.getId() + "\",\"" + markerBean.getLng() + "\",\"" + markerBean.getLat() + "\",\"" + markerBean.getName() + "\",\"" + isShowMarker + "\")", new ValueCallback() { @Override public void onReceiveValue(String value) { } }); markerBeanSet.put(markerBean.getId(), markerBean); } else { MyLog.d("setMapMarker>" + markerBean.getName() + "经纬度为空"); } } else { webNoFinishMarkerData.add(markerBean); } } } /** * 添加分水房 */ public void setMapDivide(DivideBean divide) { if (divide != null) { if (webViewIsFinished) { if (!TextUtils.isEmpty(divide.getLng()) && !TextUtils.isEmpty(divide.getLat())) { mWebView.evaluateJavascript("javascript:addDivide(\"" + divide.getId() + "\",\"" + divide.getLng() + "\",\"" + divide.getLat() + "\",\"" + divide.getDivideName() + "\",\"" + isShowDivide + "\")", new ValueCallback() { @Override public void onReceiveValue(String value) { } }); divideBeanMap.put(divide.getId(), divide); } else { MyLog.d("setMapDivide>" + divide.getDivideName() + "经纬度为空"); } } else { webNoFinishDivideData.add(divide); } } } /** * 添加管网标注 */ public void setMapPipe(PipeNetworkBean pipeNetworkBean) { if (pipeNetworkBean != null) { if (webViewIsFinished) { boolean isfrist = true; for (PipeNetworkDataCoordinateBean data : pipeNetworkBean.getData().getCoordinates()) { if (!TextUtils.isEmpty(data.getLat()) && !TextUtils.isEmpty(data.getLng())) { mWebView.evaluateJavascript("javascript:addPipeNetwork(\"" + data.getLng() + "\",\"" + data.getLat() + "\",\"" + isfrist + "\",\"" + isShowPipeNetwork + "\")", new ValueCallback() { @Override public void onReceiveValue(String value) { } }); isfrist = false; } } } else { webNoFinishPipeNetworkData.add(pipeNetworkBean); } } } /** * 开始巡检的相关逻辑 * * @param */ private void startLocation() { //获取定位服务传过来的坐标点 LiveEventBus.get(CommonKeyName.locationData).observe(this, locationObserver); binding.inspectRL.setVisibility(View.VISIBLE); binding.inspectButton.setVisibility(View.GONE); binding.inspectPause.setText("暂停"); binding.stateText.setText("已开启巡检"); binding.inspectRL.setBackgroundColor(this.getContext().getResources().getColor(R.color.base_blue)); SharedPreferencesHelper.getInstance(this.getContext()).put(CommonKeyName.inspectionState, InspectionUtils.STAT_INSPECTION); ServiceUtils.startLocationService(MapFragment.this.getContext(), false); } /** * 申请后台定位权限 */ private void getPermissions() { try { XXPermissions.with(MapFragment.this.getContext()) // 申请多个权限 .permission(Permission.ACCESS_BACKGROUND_LOCATION) .request(new OnPermissionCallback() { @Override public void onGranted(@NonNull List permissions, boolean allGranted) { if (allGranted) { chageInspecState(InspectionUtils.STAT_INSPECTION_ONCLICK); } } @Override public void onDenied(@NonNull List permissions, boolean doNotAskAgain) { if (doNotAskAgain) { // 如果是被永久拒绝就跳转到应用权限系统设置页面 TipUtil.show(MapFragment.this.getActivity(), "被永久拒绝授权,请手动授予定位始终允许权限!选择“权限”-->“位置信息”-->“始终允许”,然后返回应用。", new TipUtil.TipListener() { @Override public void onCancle() { XXPermissions.startPermissionActivity(MapFragment.this.getContext(), permissions); } }); } else { ToastUtil.showToastLong(MapFragment.this.getContext(), "获取定位始终允许权限失败"); } } }); } catch (Throwable e) { e.printStackTrace(); } } /** * 接收js传来的中心点坐标 * * @param lng * @param lat */ public void refreshCenterPoint(double lng, double lat) { centerLng = lng; centerLat = lat; binding.pointText.setText(centerLng + "," + centerLat); } /** * 修改经纬度 * * @param markerBean */ private void updataInstake(MarkerBean markerBean) { String lng = String.valueOf(centerLng); String lat = String.valueOf(centerLat); Map params = new HashMap<>(); params.put("id", markerBean.getId()); params.put("lng", lng); params.put("lat", lat); params.put("operator", MyApplication.myApplication.userId); ApiManager.getInstance().requestPost(MapFragment.this.getContext(), BASE_URL + "/project/intake/updateIntakeLngLat", Boolean.class, params, new SubscriberListener>() { @Override public void onNext(BaseResponse t) { try { if (t.isSuccess()) { mWebView.evaluateJavascript("javascript:refreshMarker(\"" + markerBean.getId() + "\",\"" + centerLng + "\",\"" + centerLat + "\",\"" + markerBean.getName() + "\")", new ValueCallback() { @Override public void onReceiveValue(String value) { } }); binding.pointCenterImg.setVisibility(View.GONE); binding.pointRL.setVisibility(View.GONE); mMarkerBean.setLat(lat); mMarkerBean.setLng(lng); binding.lng.setText(lng); binding.lat.setText(lat); mWebView.evaluateJavascript("javascript:cancelPin()", value -> { }); // 更新本地数据库 compositeDisposable.add( DaoSingleton.getAsynchInstance(MapFragment.this.getContext()) .markerDao() .updateMarkerLocation(markerBean.getId(), lng, lat) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe( () -> { // 更新本地缓存Map中的数据 MarkerBean cachedMarker = markerBeanSet.get(markerBean.getId()); if (cachedMarker != null) { cachedMarker.setLng(lng); cachedMarker.setLat(lat); } ToastUtil.showToastLong(MapFragment.this.getContext(), "修改成功!"); }, throwable -> { Log.e(TAG, "更新本地数据库失败: "); ToastUtil.showToastLong(MapFragment.this.getContext(), "修改成功,但本地数据库更新失败"); } ) ); } else { ToastUtil.showToastLong(MapFragment.this.getContext(), t.getMsg()); } } catch (Exception e) { e.printStackTrace(); CrashReport.postCatchedException(e); } } }); } /** * 获取取水口详情 * * @param markerBean */ private void getInstakeDetail(MarkerBean markerBean) { Map params = new HashMap<>(); params.put("id", markerBean.getId()); ApiManager.getInstance().requestGet(this.getContext(), Constants.BASE_URL + "/project/intake/one", MarkerResult.class, params, new SubscriberListener>() { @Override public void onNext(BaseResponse t) { if (t.isSuccess()) { MarkerResult result = t.getContent(); mMarkerBean = new MarkerBean(); mMarkerBean.setId(result.getId()); mMarkerBean.setLng(result.getLng()); mMarkerBean.setLat(result.getLat()); mMarkerBean.setBlockId(result.getBlockId()); mMarkerBean.setName(result.getName()); mMarkerBean.setRemarks(result.getRemarks()); mMarkerBean.setTownId(result.getTownId()); mMarkerBean.setVillageId(result.getVillageId()); mMarkerBean.setCountyId(result.getCountyId()); mMarkerBean.setAddress(result.getAddress()); mMarkerBean.setBlockName(result.getBlockName()); mMarkerBean.setDivideId(result.getDivideId()); getDeviceData(result.getName()); showMarker(mMarkerBean); } else { ToastUtil.showToast(MapFragment.this.getContext(), t.getMsg()); } } }); } /** * 显示分水房详情 */ private void getDivideDetail(DivideBean divideBean) { ApiManager.getInstance().requestGet(this.getContext(), Constants.BASE_URL + "/project/divide/getone/" + divideBean.getDivideId(), DivideResult.class, null, new SubscriberListener>() { @Override public void onNext(BaseResponse t) { if (t.isSuccess()) { DivideBean divideBean = getDivideBean(t.getContent()); getDeviceData(divideBean.getDivideName()); showDivideMarker(divideBean); } else { ToastUtil.showToast(MapFragment.this.getContext(), t.getMsg()); } } }); } /** * 显示底部布局的动画效果 */ private void showBottomLayoutWithAnimation() { binding.bottomLL.setVisibility(View.VISIBLE); binding.bottomLL.setTranslationY(binding.bottomLL.getHeight()); binding.bottomLL.animate() .translationY(0) .setDuration(300) .setInterpolator(new android.view.animation.DecelerateInterpolator()) .start(); } /** * 显示取水口详情 */ private void showMarker(MarkerBean markerBean) { showBottomLayoutWithAnimation(); binding.phoneLL.setVisibility(View.GONE); binding.headerLL.setVisibility(View.GONE); binding.editePoint.setVisibility(View.VISIBLE); binding.markerAddress.setText(markerBean.getAddress()); binding.markerName.setText(markerBean.getName()); binding.markerBlockName.setText(markerBean.getBlockName()); binding.lat.setText(markerBean.getLat()); binding.lng.setText(markerBean.getLng()); //修改经纬度 binding.editePoint.setOnClickListener(v -> { mWebView.evaluateJavascript("javascript:showPin(\"" + markerBean.getLng() + "\",\"" + markerBean.getLat() + "\")", value -> { binding.pointRL.setVisibility(View.VISIBLE); binding.pointCenterImg.setVisibility(View.VISIBLE); MyLog.d("showPin>>" + value); }); }); //取消修改经纬度 binding.pointCancel.setOnClickListener(v -> { binding.pointCenterImg.setVisibility(View.GONE); binding.pointRL.setVisibility(View.GONE); mWebView.evaluateJavascript("javascript:cancelPin()", value -> { }); } ); //确认修改经纬度 binding.pointEdt.setOnClickListener(v -> { ConfirmDialog confirmDialog = new ConfirmDialog(MapFragment.this.getActivity(), "确认修改到该位置吗?", (confirmDialog1, v1) -> { confirmDialog1.dismiss(); updataInstake(markerBean); }); confirmDialog.show(); }); } /** * 显示分水房详情 * * @param divideBean */ private void showDivideMarker(DivideBean divideBean) { showBottomLayoutWithAnimation(); binding.phoneLL.setVisibility(View.VISIBLE); binding.headerLL.setVisibility(View.VISIBLE); binding.editePoint.setVisibility(View.GONE); binding.markerAddress.setText(divideBean.getAddress()); binding.markerName.setText(divideBean.getDivideName()); binding.markerBlockName.setText(divideBean.getBlockName()); binding.phone.setText(divideBean.getPhone()); binding.phone.setOnClickListener(v -> { Intent intent = new Intent(Intent.ACTION_DIAL); intent.setData(Uri.parse("tel:" + divideBean.getPhone())); startActivity(intent); }); binding.header.setText(divideBean.getHeader()); binding.lat.setText(divideBean.getLat()); binding.lng.setText(divideBean.getLng()); //修改经纬度 binding.editePoint.setOnClickListener(v -> { mWebView.evaluateJavascript("javascript:showPin(\"" + divideBean.getLng() + "\",\"" + divideBean.getLat() + "\")", value -> { binding.pointRL.setVisibility(View.VISIBLE); binding.pointCenterImg.setVisibility(View.VISIBLE); MyLog.d("showPin>>" + value); }); }); //取消修改经纬度 binding.pointCancel.setOnClickListener(v -> { binding.pointCenterImg.setVisibility(View.GONE); binding.pointRL.setVisibility(View.GONE); mWebView.evaluateJavascript("javascript:cancelPin()", value -> { }); } ); //确认修改经纬度 binding.pointEdt.setOnClickListener(v -> { ConfirmDialog confirmDialog = new ConfirmDialog(MapFragment.this.getActivity(), "确认修改到该位置吗?", (confirmDialog1, v1) -> { confirmDialog1.dismiss(); // updataInstake(markerBean); }); confirmDialog.show(); }); } /** * 获取分水房 */ private void getDivideList() { ApiManager.getInstance().requestGetHideLoading(MapFragment.this.getContext(), BASE_URL + "/project/divide/getDivides", DivideListResult.class, null, new SubscriberListener>() { @Override public void onNext(BaseResponse t) { try { if (t.isSuccess()) { if (t.getContent().getObj() != null && !t.getContent().getObj().isEmpty()) { List divideBeans = new ArrayList<>(); for (DivideResult divideResult : t.getContent().getObj()) { DivideBean divideBean = getDivideBean(divideResult); setMapDivide(divideBean); divideBeans.add(divideBean); } DaoSingleton.getInstance(MapFragment.this.getContext()).divideDao().deleteAll(); // 使用 CompositeDisposable 管理数据库插入操作 compositeDisposable.add( DaoSingleton.getAsynchInstance(MapFragment.this.getContext()).divideDao().insertAll(divideBeans) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe( () -> { // 插入成功 Log.i("mWebView", "数据插入成功"); }, throwable -> { // 插入失败 Log.e("mWebView", "数据插入失败: " + throwable.getMessage()); } ) ); } } else { ToastUtil.showToastLong(MapFragment.this.getContext(), t.getMsg()); } } catch (Exception e) { e.printStackTrace(); CrashReport.postCatchedException(e); } } }); } /** * 获取管网 */ private void getPipeNetworkList() { ApiManager.getInstance().requestGetHideLoading(MapFragment.this.getContext(), BASE_URL + "/project/network/all", PipeNetworkResult.class, null, new SubscriberListener>>() { @Override public void onNext(BaseResponse> t) { try { if (t.isSuccess()) { if (t.getContent() != null && t.getContent().size() > 0) { List pipeNetBeans = new ArrayList<>(); for (PipeNetworkResult pipeNetworkResult : t.getContent()) { PipeNetworkBean pipeNetBean = new PipeNetworkBean(); pipeNetBean.setNetworkId(pipeNetworkResult.getNetworkId()); pipeNetBean.setType(pipeNetworkResult.getType()); PipeNetWorkDataBean data = new PipeNetWorkDataBean(); data.setType(pipeNetworkResult.getData().getType()); List coordinates = new ArrayList<>(); for (PipeNetworkResult.Data.Coordinate dataBean : pipeNetworkResult.getData().getCoordinates()) { PipeNetworkDataCoordinateBean coordinate = new PipeNetworkDataCoordinateBean(); coordinate.setLat(dataBean.getLat()); coordinate.setLng(dataBean.getLng()); coordinates.add(coordinate); } data.setCoordinates(coordinates); pipeNetBean.setData(data); setMapPipe(pipeNetBean); pipeNetBeans.add(pipeNetBean); } DaoSingleton.getInstance(MapFragment.this.getContext()).pipeNetDao().deleteAll(); // 使用 RxJava 异步插入数据 compositeDisposable.add( DaoSingleton.getAsynchInstance(MapFragment.this.getContext()).pipeNetDao().insertAll(pipeNetBeans) .subscribeOn(Schedulers.io()) // 在 IO 线程上执行 .observeOn(AndroidSchedulers.mainThread()) // 在主线程上观察 .subscribe(() -> { // 插入成功 Log.i("mWebView", "数据插入成功"); }, throwable -> { // 插入失败 Log.e("mWebView", "数据插入失败: " + throwable.getMessage()); }) ); } } else { ToastUtil.showToastLong(MapFragment.this.getContext(), t.getMsg()); } } catch (Exception e) { e.printStackTrace(); CrashReport.postCatchedException(e); } } }); } /** * @param divideResult * @return */ private static @NonNull DivideBean getDivideBean(DivideResult divideResult) { DivideBean divideBean = new DivideBean(); divideBean.setAddress(divideResult.getAddress()); divideBean.setBlockId(divideResult.getBlockId()); divideBean.setBlockName(divideResult.getBlockName()); divideBean.setDivideId(divideResult.getDivideId()); if (!TextUtils.isEmpty(divideResult.getDivideName())) { divideBean.setDivideName(divideResult.getDivideName()); } else { divideBean.setDivideName(divideResult.getName()); } divideBean.setHeader(divideResult.getHeader()); divideBean.setId(divideResult.getId()); divideBean.setLat(divideResult.getLat()); divideBean.setLng(divideResult.getLng()); divideBean.setOperateDt(divideResult.getOperateDt()); divideBean.setOperator(divideResult.getOperator()); divideBean.setPhone(divideResult.getPhone()); divideBean.setRemarks(divideResult.getRemarks()); divideBean.setVillages(divideResult.getVillages()); divideBean.setArea(divideResult.getArea()); return divideBean; } private static @NonNull PipeNetworkBean getPipeNetworkBean(PipeNetworkResult divideResult) { PipeNetworkBean pipeNetworkBean = new PipeNetworkBean(); return pipeNetworkBean; } @Override public void onDestroy() { super.onDestroy(); // 清理所有订阅 if (compositeDisposable != null && !compositeDisposable.isDisposed()) { compositeDisposable.dispose(); } LiveEventBus.get(CommonKeyName.locationData).removeObserver(locationObserver); if (mWebView != null) { mWebView.destroy(); } } @Override public void onResume() { super.onResume(); mWebView.onResume(); mWebView.resumeTimers(); } @Override public void onPause() { super.onPause(); mWebView.onPause(); mWebView.pauseTimers(); } @Override public void onSaveInstanceState(@NonNull Bundle outState) { super.onSaveInstanceState(outState); mWebView.saveState(outState); } @Override public void onViewStateRestored(@Nullable Bundle savedInstanceState) { super.onViewStateRestored(savedInstanceState); if (savedInstanceState != null) { mWebView.restoreState(savedInstanceState); } } /** * 显示或隐藏地图上的取水口 * * @param isShow */ private void showMarkers(boolean isShow) { if (isShow) { mWebView.evaluateJavascript("javascript:showAllWaterIntakes()", value -> { }); } else { mWebView.evaluateJavascript("javascript:hideAllWaterIntakes()", value -> { }); } } /** * 显示或隐藏地图上的分水房 * * @param isShow */ private void showDivideMarkers(boolean isShow) { if (isShow) { mWebView.evaluateJavascript("javascript:showAllDivides()", value -> { }); } else { mWebView.evaluateJavascript("javascript:hideAllDivides()", value -> { }); } } private void showPipeLine(boolean isSelected) { if (isSelected) { mWebView.evaluateJavascript("javascript:showAllPipeLines()", value -> { }); } else { mWebView.evaluateJavascript("javascript:hideAllPipeLines()", value -> { }); } } /** * 获取设备相关状态信息 * * @param intakeNum */ private void getDeviceData(String intakeNum) { Map params = new HashMap<>(); params.put("intakeNum", intakeNum); ApiManager.getInstance().requestGetHideLoading(MapFragment.this.getContext(), BASE_URL + "/remote/monitor/all_intakes", IntakeListResult.class, params, new SubscriberListener>() { @Override public void onNext(BaseResponse t) { try { if (t.isSuccess()) { if (t.getContent() != null && t.getContent().getObj().size() > 0) { binding.deviceStateLL.setVisibility(View.VISIBLE); binding.rtuAddressLL.setVisibility(View.VISIBLE); IntakeResult intakeResult = t.getContent().getObj().get(0); if (intakeResult.isOnLine()) { binding.deviceState.setText("在线"); binding.deviceState.setTextColor(getResources().getColor(R.color.down_green_up, null)); } else { binding.deviceState.setText("离线"); binding.deviceState.setTextColor(getResources().getColor(R.color.delete_color, null)); } binding.rtuAddress.setText(intakeResult.getRtuAddr()); } else { binding.deviceStateLL.setVisibility(View.GONE); binding.rtuAddressLL.setVisibility(View.GONE); } } else { ToastUtil.showToastLong(MapFragment.this.getContext(), t.getMsg()); } } catch (Exception e) { e.printStackTrace(); CrashReport.postCatchedException(e); } } }); } }