前面文章介绍如何开发定位器硬件,单片机软件,服务器软件,上位机客户端软件,下面介绍如何使用android studio开发客户端APP显示轨迹。
能自己做的事从来不求人,前面用C#实现了PC端显示定位数据轨迹,用android studio开发客户端APP显示轨迹的流程也是大同小异的,只是开发语言的不同,安卓应用程序是使用Java开发的,但是C#和Java很相似。
用android studio开发客户端APP显示轨迹大概分这么几个步骤,1,编写xml文件,2,TCP服务器通信部分,3,调用百度地图API实现轨迹绘制。
1,XML布局文件加入百度地图mapview,和两个文本框,代码及UI界面如下
2,编写TCP与服务器通信程序
这部分主要有三个线程组成,一个用于连接服务器,一个向服务器发送数据,一个接收服务器的数据。
连接服务器线程,这里要实时检查安卓客户端与服务器的连接是否有效,做断线重连,并且开启发送数据线程和接收数据线程,程序如下
private class connectToServer extends Thread{
@Override
public void run() {
while(true)
{
try
{
//客户端向服务器发送连接请求
//c_Socket = new Socket("---.---.---.---",8888);
if (c_Socket==null)
{
c_Socket = new Socket("---.---.---.---",8888);
if (c_Socket.isConnected())
{
TCP_R_Count=0;
int port = c_Socket.getLocalPort();
Message msg = new Message();
msg.what = 5;
msg.obj = String.valueOf(port);
mHandler.sendMessage(msg);
c_readflag = true;
new c_ReadThread().start();
new SenfToServer().start();
connect=true;
}
}
if(connect==false)
{
if(c_Socket!=null){
c_Socket.close();
c_Socket=null;
}
}
//c_Socket = new Socket("192.168.5.32",8888);
//c_Socket.connect(IPAddress.Parse(c_ip.getText().toString()), Int32.Parse(c_port.Text));
}catch(Exception ee)
{
ee.printStackTrace();
}
}
//super.run();
}
}
发送线程 目前这部分比较简单,随着功能的增加会逐步丰富。
//客户端向服务器发送数据
private class SenfToServer extends Thread{
@Override
public void run() {
while(true)
{
if(c_Socket!=null){
if (c_Socket.isConnected())
{
try{
out = c_Socket.getOutputStream();
out.write("----------------".getBytes());
out.flush();
SenfToServer.sleep(60000);
}
catch(Exception e){
// connect=false;
}
}
}
}
//super.run();
}
}
接收线程
接收线程接收服务器发来的GPS定位数据,通过Handler向主线程传递消息。这里要检测TCP连接的有效性,如果断开连接要重连服务器。
//客户端接收服务器发来的信息
private class c_ReadThread extends Thread
{
@Override
public void run() {
// TODO 自动生成的方法存根
try {
InputStream input = c_Socket.getInputStream();
while (c_readflag)
{
byte[] buff = new byte[100];
int size = input.read(buff);
if((size>12)){
if((buff[0]=='$')&&(buff[1]=='3')&&(buff[12]!=0)){
Message msg = new Message();
msg.what =4;
msg.obj = new String(buff,0,size);
latitude_o=latitude_n;
longitude_o=longitude_n;
latitude_n=new String(buff,20,7);
longitude_n=new String(buff,12,8);
Log.i("n","纬度:"+latitude_n+" | 经度:"+longitude_n);
if((latitude_n!="00.0000")&&(longitude_n!="000.0000")){
mHandler.sendMessage(msg);
}else{
latitude_n=null;
longitude_n=null;
}
}
}
if(size>0)
{
TCP_R_Count=TCP_R_Count+size;
Message msg = new Message();
msg.what =5;
mHandler.sendMessage(msg);
}
}
} catch (IOException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
connect=false;
}
super.run();
}
}
3,调用百度地图API实现轨迹绘制
首先获取xml中加入的地图组件,mMapView = (MapView) findViewById(R.id.bmapview); mBaiduMap = mMapView.getMap();设置地图缩放级别mBaiduMap.setMapStatus(MapStatusUpdateFactory.newMapStatus(new MapStatus.Builder().zoom(21).build()));之后,使用Overlay mPolyline = mBaiduMap.addOverlay(mOverlayOptions);逐段加入两点连线,最终形成上图中的轨迹。更新坐标位置,让最后发来的位置坐标作为地图的中心mBaiduMap.animateMapStatus(u);这里还要注意从GPS卫星接收到的经纬度和百度地图经纬度有偏差,要使用下面方法做纠偏。CoordinateConverter converter1 = new CoordinateConverter().from(CoordinateConverter.CoordType.GPS).coord(p1); LatLng desLatLng1 = converter1.convert();
关键代码如下
mHandler = new Handler(){
@Override
public void handleMessage(Message msg) {
if(msg.what ==4){
if((latitude_n!=null) &&(longitude_n!=null)&&(latitude_o!=null) &&(longitude_o!=null)){
List points = new ArrayList();
LatLng p1,p2 ;
p1=new LatLng( Double.parseDouble(latitude_n),Double.parseDouble(longitude_n));
// sourceLatLng待转换坐标
CoordinateConverter converter1 = new CoordinateConverter()
.from(CoordinateConverter.CoordType.GPS)
.coord(p1);
LatLng desLatLng1 = converter1.convert();
points.add(desLatLng1);
Log.i("P1","纬度:"+desLatLng1.latitude+" | 经度:"+desLatLng1.longitude);
p2=new LatLng( Double.parseDouble(latitude_o),Double.parseDouble(longitude_o));
// sourceLatLng待转换坐标
CoordinateConverter converter2 = new CoordinateConverter()
.from(CoordinateConverter.CoordType.GPS)
.coord(p2);
LatLng desLatLng2 = converter2.convert();
points.add(desLatLng2);
Log.i("P2","纬度:"+desLatLng2.latitude+" | 经度:"+desLatLng2.longitude);
//设置折线的属性
OverlayOptions mOverlayOptions = new PolylineOptions()
.width(10)
.color(0xAAFF0000)
.points(points);
Overlay mPolyline = mBaiduMap.addOverlay(mOverlayOptions);
//if(((latitude_n.equals(latitude_o))&&(longitude_n.equals(longitude_o))))
{
//定义Maker坐标点
LatLng p3;
p3=new LatLng( Double.parseDouble(latitude_n),Double.parseDouble(longitude_n));
// sourceLatLng待转换坐标
CoordinateConverter converter3 = new CoordinateConverter()
.from(CoordinateConverter.CoordType.GPS)
.coord(p3);
LatLng desLatLng3 = converter3.convert();
/*
//构建Marker图标
BitmapDescriptor bitmap = BitmapDescriptorFactory
.fromResource(R.drawable.icon_w);
//构建MarkerOption,用于在地图上添加Marker
OverlayOptions option = new MarkerOptions()
.position(desLatLng3)
.icon(bitmap);
//在地图上添加Marker,并显示
mBaiduMap.addOverlay(option);
*/
// 构造定位数据
MyLocationData locData = new MyLocationData.Builder()
.accuracy(0) //设置精度
.direction(0) // 此处设置开发者获取到的方向信息,顺时针0-360
.latitude(desLatLng3.latitude) // 设置纬度坐标
.longitude(desLatLng3.longitude) //设置经度坐标
.build();
// 设置定位数据
mBaiduMap.setMyLocationData(locData);
//设置自定义定位图标
BitmapDescriptor mCurrentMarker = BitmapDescriptorFactory
.fromResource(R.drawable.icon_w);
mCurrentMode = MyLocationConfiguration.LocationMode.NORMAL; //设置定位模式
//位置构造方式,将定位模式,定义图标添加其中
MyLocationConfiguration config = new MyLocationConfiguration(mCurrentMode, true, mCurrentMarker);
mBaiduMap.setMyLocationConfigeration(config); //地图显示定位图标
MapStatusUpdate u = MapStatusUpdateFactory.newLatLng(desLatLng3); //更新坐标位置
mBaiduMap.animateMapStatus(u); //设置地图位置
}
//获取显示LocationProvider名称的TextView组件
TextView textView = (TextView) findViewById(R.id.Textview);
// StringBuilder stringBuilder = new StringBuilder(); //使用StringBuilder保存数据
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd-HH:mm:ss");
Date date = new Date(System.currentTimeMillis());
String str=simpleDateFormat.format(date);
textView.setText("");
textView.append(str + "\n");
textView.append(("N纬度:"+desLatLng1.latitude).toString() + "\n");
textView.append(("N纬度:"+desLatLng2.latitude).toString() + "\n");
textView.append(("O经度:"+desLatLng1.longitude).toString() + "\n");
textView.append(("O经度:"+desLatLng2.longitude).toString() + "\n");
}
}
if(msg.what ==5){
TextView textView = (TextView) findViewById(R.id.Text2view);
textView.setText("receive is "+Integer.toString(TCP_R_Count));
}
super.handleMessage(msg);
}
};