fluter 使用百度地图

github上有一个百度地图的实现 xx_fluttify,他不只有百度地图,还有各种地图的实现,后来改收费了,高德的key没申请下来,我就下载了百度的lib。

用地图没大问题,就是速度不咋地,platformview的原因。当我需要geo反查时出现问题了,这个库一直有回调,即使我已经把当前的widget关了,各种dispose,依然会有查询结果回调,这显然是内存泄露了。

基于速度与内存的考虑,地图定位选址功能就不用它了。

毕竟写一个拖动地图选址还是不难地。而且native的view速度快多了。

遇到了一个麻烦,写一个plugin,但是要启动activity,然后选完以后onresult返回,插件里怎么启动,怎么返回呢?

查了下其它插件,里面有一个可以获取activity的。

class BaiduMapPlugin implements FlutterPlugin, MethodCallHandler, ActivityAware 插件类
public void onAttachedToEngine(@NonNull FlutterPluginBinding flutterPluginBinding) 这个方法会走
public static void registerWith(Registrar registrar) {}这个旧方法不会走了。但也做一些适配
先声明private Activity activity;

 public static void registerWith(Registrar registrar) {
        System.out.println("registerWith:");
        final MethodChannel channel = new MethodChannel(registrar.messenger(), "com.archko.map/baidu_map");
        BaiduMapPlugin baiduMapPlugin = new BaiduMapPlugin();
        baiduMapPlugin.activity = registrar.activity();
        channel.setMethodCallHandler(baiduMapPlugin);
    }
得到了activity了。

public void onMethodCall(@NonNull MethodCall call, @NonNull Result result) {
        System.out.println("onMethodCall:" + call.method);
        if (call.method.equals("getLocation")) {
            if (null != activity) {
                resultMap.put(String.valueOf(REQUEST_GPS), result);
                Intent intent = new Intent(activity, AreaSelectorWithMapActivity.class);
                activity.startActivityForResult(intent, REQUEST_GPS);
            }
        } else {
            result.notImplemented();
        }
    }

当传过来的方法是这个的时候,启动它。
resultMap.put(String.valueOf(REQUEST_GPS), result);
这个是将返回指针保留下来。便于在返回的时候用。


当前类不是activity,只是一个plugin,怎么接收呢?
@Override
    public void onAttachedToActivity(ActivityPluginBinding binding) {
        binding.addActivityResultListener(new PluginRegistry.ActivityResultListener() {
            @Override
            public boolean onActivityResult(int requestCode, int resultCode, Intent data) {
                if (requestCode == REQUEST_GPS) {
                    Result result = resultMap.get(String.valueOf(REQUEST_GPS));

                    if (resultCode == Activity.RESULT_OK) {
                        String location = data.getExtras().getString("location");
                        Log.d(TAG, "data:" + location);
                        if (null != result) {
                            Map map = new HashMap();
                            map.put("code", 0);
                            map.put("data", location);
                            result.success(map);
                        }
                    } else {
                        if (null != result) {
                            Map map = new HashMap();
                            map.put("code", -1);
                            result.error("error", "error", map);
                        }
                    }
                    resultMap.remove(String.valueOf(REQUEST_GPS));
                }
                return false;
            }
        });
        activity = binding.getActivity();
    }
这个方法覆盖了,就可以接收到了。

剩下的就是选址了。
地图什么时候初始化呢?假如你主工程有初始化,这里就不用了,假如没有,在定位Activity里onCreate()方法中调用:
SDKInit.init(getApplicationContext());

public class SDKInit {

    public static boolean hasInit = false;

    public static void init(Context context) {
        if (!hasInit) {
            SDKInitializer.initialize(context);
            hasInit = true;
        }
    }
}

核心点就是,地图上盖一个指针,然后监听地图的移动,结束后,拿到中间这个位置,去反查位置。
mBaiduMap.setOnMapStatusChangeListener(new BaiduMap.OnMapStatusChangeListener() {
            @Override
            public void onMapStatusChangeStart(MapStatus mapStatus) {

            }

            @Override
            public void onMapStatusChange(MapStatus mapStatus) {

            }

            @Override
            public void onMapStatusChangeStart(MapStatus mapStatus, int i) {

            }

            @Override
            public void onMapStatusChangeFinish(MapStatus mapStatus) {
                //移动地图中心的时候会产生循环调用
                if (!requestMoveCenter) {
                    if (mapStatus != null && mapStatus.bound != null) {
                        upDateMapLocation(mapStatus.bound.getCenter().latitude, mapStatus.bound.getCenter().longitude);
                    }
                }
            }
        });
这里估计就是之前的库死循环一直调用的问题所在了。但作者说,后面的要收费,所以改不了。


LatLng point = new LatLng(latitude, longitude);
        mSearch.reverseGeoCode(mReverseGeoCodeOption.location(point));

查完,更新一下中心点的marker,
private void updateBaiduMapCenterTip(String tip, LatLng latLng) {
        if (null == mBaiduMap || TextUtils.isEmpty(tip) || null == latLng) {
            return;
        }
        try {
            map_address.setText(String.format("选中的位置:%s", tip));
            mBaiduMap.clear();
            if (requestMoveCenter) {
                //移动地图中心点
                mBaiduMap.setMapStatus(MapStatusUpdateFactory.newLatLng(latLng));
                requestMoveCenter = false;
            }
            //百度地图提示TextView
            TextView mTipText = new TextView(getApplicationContext());
            mTipText.setBackgroundResource(R.drawable.bg_map_tip);
            mTipText.setText(tip);
            // 覆盖物(#addMapMarker)
            mBaiduMap.showInfoWindow(new InfoWindow(mTipText, latLng, -47));
        } catch (NullPointerException e) {
        }
    }
显示好看点。

选完之后,返回数据:
btn_save.setOnClickListener(v -> {
            if (null == geoCodeResult) {
                Toast.makeText(AreaSelectorWithMapActivity.this, "请移动地图选址", Toast.LENGTH_LONG).show();
            } else {
                Intent intent = new Intent();
                JSONObject jo = new JSONObject();
                try {
                    jo.put("address", geoCodeResult.getAddress());
                    jo.put("lat", geoCodeResult.getLocation().latitude);
                    jo.put("lng", geoCodeResult.getLocation().longitude);
                } catch (JSONException e) {
                    e.printStackTrace();
                }

                intent.putExtra("location", jo.toString());
                setResult(RESULT_OK, intent);
                finish();
            }
        });
这样,在插件中注册的监听器就可以得到了。

dart方面的调用:
class BaiduMap {
  static const MethodChannel _channel =
      const MethodChannel('com.archko.map/baidu_map');

  static Future invokeMethod(String method, [dynamic arguments]) async {
    return await _channel.invokeMethod(method, arguments);
  }

  static Future> invokeListMethod(String method,
      [dynamic arguments]) async {
    return await _channel.invokeListMethod(method, arguments);
  }

  static Future> invokeMapMethod(String method,
      [dynamic arguments]) async {
    return await _channel.invokeMapMethod(method, arguments);
  }

  static Future get platformVersion async {
    final String version = await _channel.invokeMethod('getPlatformVersion');
    return version;
  }

  static Future getLocation() async {
    final Map address = await invokeMapMethod('getLocation');
    //{code: 0, data: {"address":"北京市","lat":31.91108923635131,"lng":111.40275584463448}}
    print("getLocation:$address");
    return address;
  }
}

拿定位就这样了:
Future showMap() async {
    Map addr = await BaiduMap.getLocation();
    _address = addr['address'];
    if (!mounted) return;
    setState(() {});
  }

当然你要在manifest里面添加api_key这些东西,在主工程里有就行了。

这里得到的address不太准确,我更喜欢用里面的poi列表,得到第一个热点,因为选地址名称显示出来的,是有名的,而address通常只会显示xx路,而且移动了可能还是原来的路名,移动的范围要大点,这个才有变化。

https://github.com/archko/flutter_baidu_map.git 源码下载。

 

你可能感兴趣的:(android,flutter应用,百度,java,poi,定位)