自开发上一款智慧旅游产品后,发现一个很有意义而且很实用的功能,就是模仿微信的位置共享,可以看到对方的位置,一直想模仿做出这样的效果.最近闲下来之后终于实现了.下面就把我的实现过程和心得分享给大家.
要实现实时位置共享,首先就要实现实时定位,高德官方api给的很详细,只要跟着步骤来,还是没什么难度的,下面直接上代码了
/** * 设置地图属性 */ private void setUpMap(){ aMap.setLocationSource(this); aMap.setMyLocationEnabled(true);// 设置为true表示显示定位层并可触发定位,false表示隐藏定位层并不可触发定位,默认是false aMap.setMyLocationType(AMap.LOCATION_TYPE_LOCATE);// 跟随模式 aMap.getUiSettings().setMyLocationButtonEnabled(true);// 设置默认定位按钮是否显示 aMap.setMyLocationEnabled(true);// 设置为true表示显示定位层并可触发定位,false表示隐藏定位层并不可触发定位,默认是false }
//激活定位 @Override public void activate(OnLocationChangedListener listener) { mListener = listener; if (mlocationClient == null){ mlocationClient = new AMapLocationClient(MainActivity.this); mLocationOption = new AMapLocationClientOption(); mlocationClient.setLocationListener(this);// 设置定位监听 mLocationOption.setLocationMode(AMapLocationClientOption.AMapLocationMode.Hight_Accuracy); mlocationClient.setLocationOption(mLocationOption);// 设置为高精度定位模式 mLocationOption.setInterval(1000); mlocationClient.startLocation(); } }
/**
*位置信息发生变化时
*/
@Override public void onLocationChanged(AMapLocation aMapLocation) { if (mListener != null && aMapLocation != null){ if (aMapLocation != null && aMapLocation.getErrorCode() == 0){ mListener.onLocationChanged(aMapLocation);// 显示系统小蓝点 if (isFirst){ aMap.moveCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(aMapLocation.getLatitude(), aMapLocation.getLongitude()), 18));//定位成功移到当前定位点 isFirst = false; } }else{ Log.i("123",aMapLocation.getErrorCode()+"错误码"+aMapLocation.getErrorInfo()+"错误信息"); } } }
首先创建一个socket连接对象,文字不多说,直接上代码
private void startSocket(){ try{ socket = new Socket(Ip,port); outputStream = socket.getOutputStream(); inputStream = new Send_InputStream(socket.getInputStream()); inputStream.setMainActivity(mainActivity); new Thread(inputStream).start(); }catch (Exception e){ } } @Override public void run() { try{ startSocket(); jsonObject = new JSONObject(); while (socket != null){ Thread.sleep(3000); jsonObject.put("lat",MainActivity.getLat());//连接成功后获取定位的经纬度通过json对象发送给服务器 jsonObject.put("lng",MainActivity.getLng()); outputStream.write(jsonObject.toString().getBytes("UTF-8")); outputStream.flush(); } }catch (Exception e){ }finally { if (outputStream != null){ try { outputStream.close(); }catch (Exception e){ } } if(socket != null){ try{ socket.close(); }catch (Exception e){ } } }有发送就有接收的方法,下面来一段接收
@Override public void run() { int len = 0; byte[] buff = new byte[1024]; try{ while ((len = inputStream.read(buff)) != -1){ text = new String(buff,0,len); JSONObject jsonObject = new JSONObject(text); int errorCode = jsonObject.getInt("errorCode"); if (errorCode == 200){ JSONArray jsonArray = jsonObject.getJSONArray("date");//与服务器约定好的数据格式 mainActivity.allLatLng(jsonArray);//调用首页地图的方法将接收的位置信息显示出来 } } }catch (Exception e){ } }到这里,前端的代码就差不多了,最主要的是TCP的建立以及数据的解析,把接收到的数据解析得到坐标位置以一个marker的形式添加在地图上
/** * 添加所接收到的共享位置信息 * @param jsonArray */ public void allLatLng(JSONArray jsonArray){ try{ if (list.size() != 0){ Remove(list); } for (int i = 0;i这是在地图添加一个marke的方法new JSONObject(jsonArray.get(i).toString()); latitude = jsonObject.getDouble("lat"); longitude = jsonObject.getDouble("lng"); LatLng latLng = new LatLng(latitude,longitude); marker = (Marker) (aMap.addMarker(help_add_icon(latLng, R.mipmap.icon_tourist))); list.add(marker); } }catch (Exception e){ } }
/** * 手机上显示共享位置的图标 * @param latLng * @param id * @return */ public static MarkerOptions help_add_icon(LatLng latLng,int id){ MarkerOptions markOptiopns = new MarkerOptions().position(latLng) .icon(BitmapDescriptorFactory.fromResource(id)); return markOptiopns; }然后,这是调用方法
marker = (Marker) (aMap.addMarker(help_add_icon(latLng, R.mipmap.icon_tourist))); 最后说一下手机端这边的逻辑和原理 通过点击开启共享位置信息的按钮,与服务器建立TCP的链接,同时把自己的位置信息发送过去,当有第二个手机用户连进来的时候,服务器会把对方的位置信息发送出去, 然后手机用户通过接受服务器返回的数据显示对方的位置信息.这里注意一下,在接受到信息前要判断之前的信息是否为空,不为空就先把之前的marker移除再在地图上 添加,避免在接受的新的位置信息时,前面的还在地图上显示.
首先启动socket
public class ServiceTcp {
private int port;
public ServiceTcp() {
}
public ServiceTcp(int port) {
this.port = port;
}
private List
public void start() {
ServerSocket serverSocket = null;
try {
serverSocket = new ServerSocket(port);
while (true) {
Socket socket = serverSocket.accept();
Client client = new Client(socket, users);
Thread thread = new Thread(client);
thread.start();
}
} catch (IOException e) {
System.out.println("启动失败!!!");
e.printStackTrace();
}
}
}
接收手机用户的线程类
@Override
public void run() {
try {
inputStream = socket.getInputStream();
outputStream = socket.getOutputStream();
User user = new User(socket, this);
users.add(user);
// 发送线程
Sender sender = new Sender(user, users);
Thread thread = new Thread(sender);
thread.start();
byte[] bytes = new byte[1024];
Integer length = null;
String inString = null;
while ((length = inputStream.read(bytes)) != -1) {
inString = new String(bytes, 0, length, encoder);
try {
if (user.isOnLine() == false) {
this.close();
break;
}
if (end.equals(inString)) {
this.close();
break;
}
JSONObject reJson = JSONObject.fromObject(inString);
Double lat = reJson.getDouble("lat");
Double lng = reJson.getDouble("lng");
user.setLat(lat);
user.setLng(lng);
} catch (JSONException e) {
JSONObject jso = (ErrorCode.e_201).toJson();
this.send(jso.toString());
} catch (Exception e) {
user.setOnLine(false);
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
发送在线用户的方法
@Override
public void run() {
while (user.isOnLine()) {
try {
Thread.sleep(3 * 1000);// 休眠3秒
user.getClient().send(ret().toString());
} catch (Exception e) {
user.setOnLine(false);// 设置离线
}
}
}
private JSONObject ret() {
JSONObject jsonObject = null;
JSONArray array = new JSONArray();
for (User user : users) {
if (user.getLat() != null && user.getLng() != null) {
if (user.getUuid() != this.user.getUuid()) {
JSONObject us = new JSONObject();
us.put("uuid", user.getUuid());
us.put("lat", user.getLat());
us.put("lng", user.getLng());
array.add(us);
}
}
}
jsonObject = ErrorCode.s_200.toJson(array);
return jsonObject;
}
附带一下服务器返回的数据格式
{"errorCode":200,"message":"成功","date":[{"uuid":"e4bd7c4a-9d39-45a2-9378-b833d62e0538","lat":22.684095,"lng":114.23056}]}
就是这么简单粗暴直接,服务器这边的逻辑就是随机生成一个uuid最为手机用户的唯一标识,避免向用户发送自己的位置信息
最后来看下整体的效果图
这是一个魅族pro6手机上的效果,游客代表另一个手机用户
这是三星A5100上的效果,游客表示另一个手机用户
Android代码下载:https://github.com/WengYihao/GdDisplayMap
服务器代码下载:https://github.com/WengYihao/Server