基于高德地图的Android版无线电监测小项目

来源:互联网 发布:补血产品网络推广 编辑:程序博客网 时间:2024/06/06 10:01

前段时间老师基于C#的无线电监测项目结题了,我在闲暇的时间抽出项目中的小部分内容写了一个移动版本,其中客户端用android,后台主要采用spring框架,数据库是采用mysql。下面我会大致介绍下自己coding的过程,源码会在后面分享:

一、首先看一下整体的效果


二、布局设置

界面分为四个fragment,点击可以切换。

下面是界面布局的代码:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:tools="http://schemas.android.com/tools"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:orientation="vertical" >    <Button        android:id="@+id/text"        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:background="@drawable/not_network"        android:visibility="gone" />    <FrameLayout        android:id="@+id/content"        android:layout_width="fill_parent"        android:layout_height="0dp"        android:layout_weight="1" >    </FrameLayout>    <FrameLayout        android:id="@+id/rl_bottom_tab"        android:layout_width="fill_parent"        android:layout_height="60dip" >        <View            android:layout_width="match_parent"            android:layout_height="1dp"            android:background="#ccc" >        </View>        <LinearLayout            android:layout_width="match_parent"            android:layout_height="match_parent"            android:gravity="center_horizontal"            android:orientation="horizontal" >            <LinearLayout                android:id="@+id/tab_1"                android:layout_width="match_parent"                android:layout_height="match_parent"                android:layout_weight="1"                android:gravity="center"                android:orientation="vertical" >                <ImageView                    android:id="@+id/tab1_image"                    android:layout_width="35dp"                    android:layout_height="35dp"                    android:layout_marginTop="2dp"                    android:src="@drawable/tab_chat_other_pressed" />                <TextView                    android:id="@+id/tab1_text"                    android:layout_width="wrap_content"                    android:layout_height="wrap_content"                    android:gravity="center_horizontal"                    android:text="@string/main_tab1"                    android:textColor="#808080"                    android:textSize="12dp" />            </LinearLayout>            <LinearLayout                android:id="@+id/tab_2"                android:layout_width="match_parent"                android:layout_height="match_parent"                android:layout_weight="1"                android:gravity="center"                android:orientation="vertical" >                <ImageView                    android:id="@+id/tab2_image"                    android:layout_width="35dp"                    android:layout_height="35dp"                    android:layout_marginTop="2dp"                    android:src="@drawable/tab_message_normal" />                <TextView                    android:id="@+id/tab2_text"                    android:layout_width="wrap_content"                    android:layout_height="wrap_content"                    android:gravity="center_horizontal"                    android:text="@string/main_tab2"                    android:textColor="#808080"                    android:textSize="12dp" />            </LinearLayout>            <LinearLayout                android:id="@+id/tab_3"                android:layout_width="match_parent"                android:layout_height="match_parent"                android:layout_weight="1"                android:gravity="center"                android:orientation="vertical" >                <ImageView                    android:id="@+id/tab3_image"                    android:layout_width="35dp"                    android:layout_height="35dp"                    android:layout_marginTop="2dp"                    android:src="@drawable/tab_contact_normal" />                <TextView                    android:id="@+id/tab3_text"                    android:layout_width="wrap_content"                    android:layout_height="wrap_content"                    android:gravity="center_horizontal"                    android:text="@string/main_tab3"                    android:textColor="#808080"                    android:textSize="12dp" />            </LinearLayout>            <LinearLayout                android:id="@+id/tab_4"                android:layout_width="match_parent"                android:layout_height="match_parent"                android:layout_weight="1"                android:gravity="center"                android:orientation="vertical" >                <ImageView                    android:id="@+id/tab4_image"                    android:layout_width="35dp"                    android:layout_height="35dp"                    android:layout_marginTop="2dp"                    android:src="@drawable/tab_setting_normal" />                <TextView                    android:id="@+id/tab4_text"                    android:layout_width="wrap_content"                    android:layout_height="wrap_content"                    android:gravity="center_horizontal"                    android:text="@string/main_tab4"                    android:textColor="#808080"                    android:textSize="12dp" />            </LinearLayout>        </LinearLayout>    </FrameLayout></LinearLayout>

点击实现fragment切换的主要代码如下:

public void onClick(View v) {resetImg();switch (v.getId()) {case R.id.tab_1:setSelect(0);//initTitleBar(1);tab1_iamge.setImageResource(R.drawable.tab_chat_other_pressed);break;case R.id.tab_2:setSelect(1);tab2_iamge.setImageResource(R.drawable.tab_message_pressed);break;case R.id.tab_3:setSelect(2);tab3_iamge.setImageResource(R.drawable.tab_contact_pressed);break;case R.id.tab_4:setSelect(3);tab4_iamge.setImageResource(R.drawable.tab_setting_pressed);break;case R.id.text:Intent intent = new Intent(Settings.ACTION_DATA_ROAMING_SETTINGS);startActivity(intent);break;default:break;}}private void setSelect(int t) {FragmentManager fm = getSupportFragmentManager();FragmentTransaction transaction = fm.beginTransaction();// 隐藏fragmenthideFragment(transaction);switch (t) {case 0:if (tab1 == null) {tab1 = new TaskFragment();transaction.add(R.id.content, tab1);} else {transaction.show(tab1);}break;case 1:if (tab2 == null) {tab2 = new MapFragment();transaction.add(R.id.content, tab2);} else {transaction.show(tab2);}break;case 2:if (tab3 == null) {tab3 = new MonitorFragment();transaction.add(R.id.content, tab3);} else {transaction.show(tab3);}break;case 3://if (tab4 == null) {tab4 = new MeFragment();transaction.add(R.id.content, tab4);//} else {//transaction.show(tab4);//}break;default:break;}transaction.commit();}


三、高德地图android版的使用

1.       在浏览器中输入:http://lbs.amap.com/console/key申请 Key。

用开发者账户登录后进入我的控制台,在“KEY 管理”页面申请 Key。

2.       点击“获取 KEY”按钮后,进入获取 KEY 流程,如下图所示:

 

3.       在获取 Key 的流程页面,输入获取 Key 所需的信息,包括:

1)        应用名称:可根据您的应用输入即可。

2)        绑定服务:根据您的开发平台做选择。

l若选择“Android 平台SDK”,弹出以下必填信息,输入 SHA1 Package

注:Demo 工程的 Key 需要使用 Demo 工程的包名以及SHA1 安全码 

点击“查看 Android SHA1 Package 获取方式”链接,了解获取方式。

3)        勾选“我已经阅读并同意《高德 API 使用条款》”。

4)        点击下方的“获取 KEY”按钮,完成申请 Key 流程。若获取成功,会自动跳转到

Key 列表,如下所示:


 

4. 将获取的 Key 值加入到 AndroidManifest.xml 文件需要填写 Key 值的位置,如所示:

 <meta-data

          android:name="com.amap.api.v2.apikey"

       android:value="key值"/>

四、地图模块(MapFragment)

使用eclipse运行了高德地图android版的demo后,研究了一下,我自己的需求是根据经纬度在地图上标注监测站的位置,发现demo工程中MarkerActivity这个类完全足够用了。

1.  要在地图上标注监测站,首先要从数据库中读取监测站的包括经纬度在内的具体信息,我采用的方法是android客户端发送http请求,后台返回json数据,然后android客户端解析json。我的工程中利用到了第三方开源类库android-async-http,android-async-http开源框架可以使我们轻松的获取网络数据或者向服务器发送数据,使用起来也很简单,还有阿里巴巴FastJson,fastjson是是一个Json处理工具包,包括“序列化”和“反序列化”两部分。

2.  首先在MapFragment中我写了一个查询监测站信息的getTowerInfo方法,向后台发送http请求成功后返回data的具体信息,下图是用postman测试返回的json数据(暂时先不看后台程序,后台程序会在后面讲解):


private void getTowerInfo() {NetPortal.getTowerInfo(new TextHttpResponseHandler() {@Overridepublic void onStart() {// TODO Auto-generated method stubsuper.onStart();}@Overridepublic void onSuccess(int arg0, Header[] arg1, String arg2) {// TODO Auto-generated method stubListTowerInfoModel model = JSON.parseObject(arg2,ListTowerInfoModel.class);if (model.getErrcode() == 0) {List<TowerInfo> towerInfos = model.getData();addMarkersToMap(towerInfos);} else {Toast.makeText(context, model.getErrmsg(),Toast.LENGTH_LONG).show();}} @Overridepublic void onFailure(int arg0, Header[] arg1, String arg2,Throwable arg3) {// TODO Auto-generated method stubToast.makeText(context,getResources().getString(R.string.net_error_tips),Toast.LENGTH_LONG).show();}});}/** * @Description: TODO(查询监测站点具体信息) *            */public static void getTowerInfo(TextHttpResponseHandler responseHandler) {RequestParams params = new RequestParams();RequestClient.post(UrlTool.GET_TOWER_INFO, params, responseHandler);}

注意:在从数据库获取数据时,一般都用get方法,添加、更新数据库时采用post方法,我刚开始写代码的时候没注意用了post方法,懒得改了。

在得到监测站的具体信息后,利用addMarkersToMap方法将所有监测站添加到地图。

/** * 在地图上添加marker */private void addMarkersToMap(List<TowerInfo> towerInfos) {ArrayList<MarkerOptions> markerOptionlst = new ArrayList<MarkerOptions>();LatLng position = null;MarkerOptions markerOption = null;for (int i = 0; i < towerInfos.size(); i++) {position = new LatLng(Double.parseDouble(towerInfos.get(i).getLON()),Double.parseDouble(towerInfos.get(i).getLAT()));String title = towerInfos.get(i).getTOWER_NAME() + ":"+ towerInfos.get(i).getLON() + ","+ towerInfos.get(i).getLAT();markerOption = new MarkerOptions().anchor(0.5f, 0.5f).position(position).snippet(title).draggable(true).period(50);markerOption.icon(BitmapDescriptorFactory.fromBitmap(BitmapFactory.decodeResource(getResources(),R.drawable.tower)));markerOptionlst.add(markerOption);}List<Marker> markerlst = aMap.addMarkers(markerOptionlst, true);flag = "tower";}


图中他人这个按钮是想实现这样一个功能:自己当前的经纬度隔一段时间会保存到数据库,数据库中有一张表负责存储用户位置信息,点击他人这个按钮,就会在地图中标注正在使用这款软件的用户的位置。

addUserLLInfo这个方法就是实现把自己的经纬度添加到数据库:

/** * 添加自己的当前位置到数据库 */private void addUserLLInfo(String lat,String lon) {NetPortal.addUserLLInfo(user.getUSER_ID(), lat, lon,new TextHttpResponseHandler() {@Overridepublic void onStart() {// TODO Auto-generated method stubsuper.onStart();}@Overridepublic void onSuccess(int arg0, Header[] arg1, String arg2) {} @Overridepublic void onFailure(int arg0, Header[] arg1, String arg2,Throwable arg3) {// TODO Auto-generated method stubToast.makeText(context,getResources().getString(R.string.net_error_tips),Toast.LENGTH_LONG).show();}});}/** * 添加当前经纬度到数据库 */public static void addUserLLInfo(int user_id,String lat,String lon,TextHttpResponseHandler responseHandler) {RequestParams params = new RequestParams();params.put("userId", user_id);params.put("lat", lat);params.put("lon", lon);RequestClient.post(UrlTool.ADD_USER_LLINFO, params, responseHandler);}/** *获取正在使用这款软件的人的位置 */private void getUserLLInfo() {NetPortal.getUserLLInfo(new TextHttpResponseHandler() {@Overridepublic void onStart() {// TODO Auto-generated method stubsuper.onStart();}@Overridepublic void onSuccess(int arg0, Header[] arg1, String arg2) {// TODO Auto-generated method stubListUserLLModel model = JSON.parseObject(arg2,ListUserLLModel.class);if (model.getErrcode() == 0) {List<UserLLInfo> Infos = model.getData();// adapter.setData(towerInfos);addUserToMap(Infos);} else {Toast.makeText(context, model.getErrmsg(),Toast.LENGTH_LONG).show();}} @Overridepublic void onFailure(int arg0, Header[] arg1, String arg2,Throwable arg3) {// TODO Auto-generated method stubToast.makeText(context,getResources().getString(R.string.net_error_tips),Toast.LENGTH_LONG).show();}});}/** * 在地图上添加周围的人位置 */private void addUserToMap(List<UserLLInfo> Infos) {ArrayList<MarkerOptions> markerOptionlst = new ArrayList<MarkerOptions>();LatLng position = null;MarkerOptions markerOption = null;for (int i = 0; i < Infos.size(); i++) {position = new LatLng(Double.parseDouble(Infos.get(i).getLON()),Double.parseDouble(Infos.get(i).getLAT()));String title = "昵称:"+Infos.get(i).getUSER_NAME() ;markerOption = new MarkerOptions().anchor(0.5f, 0.5f).position(position).title(Infos.get(i).getPHONE()).snippet(title).draggable(true).period(50);markerOptionlst.add(markerOption);}List<Marker> markerlst = aMap.addMarkers(markerOptionlst, true);flag = "aroundUser";}

下面写一个定时器实现隔一段时间定位自己的位置:

Timer timer = new Timer();      Handler handler = new Handler(){            public void handleMessage(Message msg) {              switch (msg.what) {                  case 1:                  setLocationMap();                break;                  }                  super.handleMessage(msg);          }                };      TimerTask task = new TimerTask(){            public void run() {              Message message = new Message();                  message.what = 1;                  handler.sendMessage(message);            }  };

同时在onCreateView中触发定时器, timer.schedule(task,1000)。

在调用setLocationMap方法定位自己的位置后,会触发   onLocationChanged方法,这时候调用addUserLLInfo方法,添加个人信息到数据库。

/** * 定位成功后回调函数 */@Overridepublic void onLocationChanged(AMapLocation aLocation) {if (mListener != null && aLocation != null) {mListener.onLocationChanged(aLocation);// 显示系统小蓝点marker.setPosition(new LatLng(aLocation.getLatitude(), aLocation.getLongitude()));// 定位雷达小图标addUserLLInfo(aLocation.getLongitude()+"",aLocation.getLatitude()+"");//添加当前位置保存float bearing = aMap.getCameraPosition().bearing;aMap.setMyLocationRotateAngle(bearing);// 设置小蓝点旋转角度}}

点击地图上的监测站图标会出现一个窗口,显示监测站的经纬度信息,再点击这个窗口会弹出一个对话框显示任务功能列表。点击地图中他人的图标会出现其他用户的昵称和电话号码,再点击这个窗口会直接跳转到拨打电话界面。


/** * 监听点击infowindow窗口事件回调 */@Overridepublic void onInfoWindowClick(Marker marker) {// ToastUtil.show(this, "你点击了infoWindow窗口" + marker.getTitle());// ToastUtil.show(MarkerActivity.this, "当前地图可视区域内Marker数量:"// + aMap.getMapScreenMarkers().size());AlertDialog.Builder builder = null;if(flag.equals("tower")){builder = new AlertDialog.Builder(context);builder.setIcon(R.drawable.ic_launcher);builder.setTitle("任务功能列表");// 指定下拉列表的显示数据final String[] cities = { "无人值机", "任务管理", "频谱显示" };// 设置一个下拉的列表选择项builder.setItems(cities, new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialog, int which) {Toast.makeText(context, "选择的城市为:" + cities[which],Toast.LENGTH_SHORT).show();}});builder.show();}else if(flag.equals("aroundUser")){String phoneNumber = marker.getTitle().toString();//意图:想干什么事Intent intent = new Intent();intent.setAction(Intent.ACTION_CALL);//url:统一资源定位符//uri:统一资源标示符(更广)intent.setData(Uri.parse("tel:" + phoneNumber));//开启系统拨号器startActivity(intent);  }}

五、任务模块(TaskFragment)

这个模块我主要实现了任务下达和查看历史任务两个功能,先看一下任务下达功能:一共有四种任务类型,每种任务类型对应的默认参数都不相同,点击每种任务可以切换,默认参数是可以滑动的,选择好之后点击下一步,后出现对应的监测站,可以同时选择多个监测站。

监测站选择好之后,点击确定之后跳转到任务执行方式界面:


执行方式选择好之后点击下达任务,会向后台发送http请求,成功后数据存入数据库。

下面只看一下确认下达任务的代码:


/** * 添加任务 */private void addTask(String TaskNo, String TaskExecutor, int TaskCreator,String TaskType, String TaskName, String TaskParam, int TaskStatus,int TaskGrade, String TaskStartTime, String TaskEndTime,int ExeStatus, int CurStatus, String LoopDays, int LinkType,int TaskFuncGroup, String Remark) {NetPortal.addTask(TaskNo, TaskExecutor, TaskCreator, TaskType,TaskName, TaskParam, TaskStatus, TaskGrade, TaskStartTime,TaskEndTime, ExeStatus, CurStatus, LoopDays, LinkType,TaskFuncGroup, Remark, new TextHttpResponseHandler() {@Overridepublic void onStart() {// TODO Auto-generated method stubsuper.onStart();}@Overridepublic void onSuccess(int arg0, Header[] arg1, String arg2) {Toast.makeText(context,getResources().getString(R.string.add_task_success),Toast.LENGTH_LONG).show();IntentUtil.startActivity(TaskExeMethodParamActivity.this,MainActivity.class, false);}@Overridepublic void onFailure(int arg0, Header[] arg1, String arg2,Throwable arg3) {// TODO Auto-generated method stubToast.makeText(context,getResources().getString(R.string.net_error_tips),Toast.LENGTH_LONG).show();}});}/** * 添加任务信息到数据库 */public static void addTask(String TaskNo, String TaskExecutor, int TaskCreator,String TaskType, String TaskName, String TaskParam, int TaskStatus,int TaskGrade, String TaskStartTime, String TaskEndTime,int ExeStatus, int CurStatus, String LoopDays, int LinkType,int TaskFuncGroup, String Remark,TextHttpResponseHandler responseHandler) {RequestParams params = new RequestParams();params.put("TaskNo", TaskNo);params.put("TaskExecutor", TaskExecutor);params.put("TaskCreator", TaskCreator);params.put("TaskType", TaskType);params.put("TaskName", TaskName);params.put("TaskParam", TaskParam);params.put("TaskStatus", TaskStatus);params.put("TaskGrade", TaskGrade);params.put("TaskStartTime", TaskStartTime);params.put("TaskEndTime", TaskEndTime);params.put("ExeStatus", ExeStatus);params.put("CurStatus", CurStatus);params.put("LoopDays", LoopDays);params.put("LinkType", LinkType);params.put("TaskFuncGroup", TaskFuncGroup);params.put("Remark", Remark);RequestClient.post(UrlTool.TASK_INFO, params, responseHandler);}

注意:方法里面的参数都是前面几个activity传过来的。

历史任务的界面如下图所示:


其中主要用到HistoryTaskInfoActivitygetTaskHistory方法,可以实现上拉下拉刷新分页读取信息,点击后进入任务详情TaskInfoDetailActivity

/** * 当前请求第几页 */private int pageNo = firstNum;/** * 第一页 */public static final int firstNum = 1;/** * 每一页的条数 */private int pageSize = 15;/** * 总共有多少页 */private int countPage = 0;private void getTaskHistory() {NetPortal.getTaskInfoHistory(pageNo, pageSize,new TextHttpResponseHandler() {@Overridepublic void onStart() {// TODO Auto-generated method stubsuper.onStart();}@Overridepublic void onSuccess(int arg0, Header[] arg1, String arg2) {// TODO Auto-generated method stubListTaskInfoModel model = JSON.parseObject(arg2,ListTaskInfoModel.class);if (model.getErrcode() == 0) {countPage = model.getPage();List<TaskInfo> taskInfo = model.getData();if (taskInfo.isEmpty()) {if (pageNo == firstNum) {showLongToast("没有获取到数据");} else {showLongToast("没有更多数据了");}} else {if (pageNo == firstNum) {adapter.setData(taskInfo);} else {adapter.addData(taskInfo);}pageNo++;}} else {showLongToast(model.getErrmsg());}// 数据加载完成后,上面的状态栏就会消失lvBXHistory.onRefreshComplete();}@Overridepublic void onFailure(int arg0, Header[] arg1, String arg2,Throwable arg3) {// TODO Auto-generated method stubshowLongToast(getResources().getString(R.string.net_error_tips));lvBXHistory.onRefreshComplete();}});}

六、监视模块(MonitorFragment)

这个模块比较简单,只是从数据库中读取各个监测站正在执行的任务,也可以实现上拉下拉刷新,分页读取信息。

主要用到MonitorFragment中的getTaskJournal方法:


/** * 当前请求第几页 */private int pageNo = firstNum;/** * 第一页 */public static final int firstNum = 1;/** * 每一页的条数 */private int pageSize = 15;/** * 总共有多少页 */private int countPage = 0;private void getTaskJournal() {NetPortal.getTaskJournal(pageNo, pageSize,new TextHttpResponseHandler() {@Overridepublic void onStart() {// TODO Auto-generated method stubsuper.onStart();}@Overridepublic void onSuccess(int arg0, Header[] arg1, String arg2) {// TODO Auto-generated method stubListTaskJournalModel model = JSON.parseObject(arg2,ListTaskJournalModel.class);if (model.getErrcode() == 0) {countPage = model.getPage();List<TaskJournal> taskJournals = model.getData();if (taskJournals.isEmpty()) {if (pageNo == firstNum) {showLongToast("没有获取到数据");} else {showLongToast("没有更多数据了");}} else {if (pageNo == firstNum) {adapter.setData(taskJournals);} else {adapter.addData(taskJournals);}pageNo++;}} else {showLongToast(model.getErrmsg());}// 数据加载完成后,上面的状态栏就会消失taskJournal.onRefreshComplete();}@Overridepublic void onFailure(int arg0, Header[] arg1, String arg2,Throwable arg3) {// TODO Auto-generated method stubshowLongToast(getResources().getString(R.string.net_error_tips));taskJournal.onRefreshComplete();}});}/** * @Description: TODO(查询监测站点任务执行信息) *            */public static void getTaskJournal(int pageNo,int pageSize,TextHttpResponseHandler responseHandler) {RequestParams params = new RequestParams();params.put("pageNo", pageNo);params.put("pageSize", pageSize);RequestClient.get(UrlTool.GET_TASK_JOURNAL, params, responseHandler);}

七、我模块(MeFragment)

这个模块没有什么功能,只是简单的写了一个静态页面。


最后,还有一个简单的登陆界面,程序运行后会先进入LoginActivity,点击登陆按钮,会调用userLogin方法验证用户名、密码,成功后跳转到主界面。

private void userLogin() {String userName = edt_lgname.getText().toString().trim();String passWord = edt_lgpass.getText().toString().trim();if (TextUtils.isEmpty(userName)) {showShortToast("登陆名不能为空");return;}if (TextUtils.isEmpty(passWord)) {showShortToast("密码不能为空");return;}NetPortal.userLogin(userName, passWord, new TextHttpResponseHandler() {@Overridepublic void onStart() {// TODO Auto-generated method stubsuper.onStart();dialog.show();}@Overridepublic void onFailure(int arg0, Header[] arg1, String arg2,Throwable arg3) {// TODO Auto-generated method stubshowShortToast("网络出错,请稍候再试。");dialog.dismiss();}@Overridepublic void onSuccess(int arg0, Header[] arg1, String arg2) {// TODO Auto-generated method stubdialog.dismiss();UserModel userModel = JSON.parseObject(arg2, UserModel.class);if (userModel.getErrcode() != 0) {showLongToast(userModel.getErrmsg());} else {showShortToast("登录成功");// 将当前用户数据缓存下来ABPrefsUtil.getInstance(context).putString(ABPrefsUtil.USER,com.alibaba.fastjson.JSONObject.toJSONString(userModel.getData()));// 第二个参数为要返回数据的界面(MeFragment)//IntentUtil.setResult(LoginActivity.this, getIntent().getClass());IntentUtil.startActivity(LoginActivity.this, MainActivity.class , false);}}});}


总结:android客户端只是大体上实现了一些功能,代码还有很多不足的地方,不过可以作为新手小例子作为练习用。

附上源码下载地址:http://download.csdn.net/detail/lizhongkaide/9446234









 

0 0
原创粉丝点击