前面文章介绍如何开发定位器硬件,单片机软件,服务器软件,上位机客户端软件,下面介绍如何使用android studio开发客户端APP显示轨迹。
能自己做的事从来不求人,前面用C#实现了PC端显示定位数据轨迹,用android studio开发客户端APP显示轨迹的流程也是大同小异的,只是开发语言的不同,安卓应用程序是使用Java开发的,但是C#和Java很相似。
用android studio开发客户端APP显示轨迹大概分这么几个步骤,1,编写xml文件,2,TCP服务器通信部分,3,调用百度地图API实现轨迹绘制。
1,XML布局文件加入百度地图mapview,和两个文本框,代码及UI界面如下
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayoutxmlns: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:paddingBottom="@dimen/activity_vertical_margin"android:paddingLeft="@dimen/activity_horizontal_margin"android:paddingRight="@dimen/activity_horizontal_margin"android:paddingTop="@dimen/activity_vertical_margin"tools:context="com.example.myapplication.MainActivity"><com.baidu.mapapi.map.MapViewandroid:id="@+id/bmapview"android:layout_width="match_parent"android:layout_height="400dp"android:clickable="true" /><TextViewandroid:id="@+id/Text2view"android:layout_width="match_parent"android:layout_height="20dp"android:text="---"android:layout_below="@id/bmapview"/><TextViewandroid:id="@+id/Textview"android:layout_width="match_parent"android:layout_height="90dp"android:text="---"android:layout_below="@id/Text2view"/>
</RelativeLayout>
2,编写TCP与服务器通信程序
这部分主要有三个线程组成,一个用于连接服务器,一个向服务器发送数据,一个接收服务器的数据。
连接服务器线程,这里要实时检查安卓客户端与服务器的连接是否有效,做断线重连,并且开启发送数据线程和接收数据线程,程序如下
private class connectToServer extends Thread{@Overridepublic 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{@Overridepublic 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{@Overridepublic 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(){@Overridepublic void handleMessage(Message msg) {if(msg.what ==4){if((latitude_n!=null) &&(longitude_n!=null)&&(latitude_o!=null) &&(longitude_o!=null)){List<LatLng> points = new ArrayList<LatLng>();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,用于在地图上添加MarkerOverlayOptions 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);}};