本文主要是介绍机器人远程控制系统(安卓端),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
前言
现在正值春招面试的时间段(收尾阶段),笔者并没有投很多简历,因为经历过一些大公司的面试之后发现太多的不足,与其花时间在刷简历上,不如好好总结和复习学过的东西,本篇就作为个人项目总结的开端。
这个项目其实就是学校的一个参赛项目,主要实现的功能是通过发送语音文字识别控制机器人移动,也可以定点或多点导航,实时接收并更新机器人反馈的状态。我主要负责安卓的开发,下面分功能模块讲解:
index界面
实现功能:三个页面(控制,对话,基本信息)可以切换。
实现方式:RadioGroup+ViewPager
实现过程:
首先创建好三个fragment并生成对象,加入ArrayList
ControlFrgt controlFrgt=new ControlFrgt();
ChatFrgt chatFrgt=new ChatFrgt();
InfoFrgt infoFrgt=new InfoFrgt();
fragmentlist=new ArrayList<>();
fragmentlist.add(controlFrgt);
fragmentlist.add(chatFrgt);
fragmentlist.add(infoFrgt);
然后写两个监听事件,一个是RadioGroup.OnCheckedChangeListener还有一个是ViewPager.OnPageChangeListener
RadioGroup的切换事件:
private class MyOnCheckListener implements RadioGroup.OnCheckedChangeListener{@Overridepublic void onCheckedChanged(RadioGroup group, int checkedId) {changeCheck(controlrbtn);changeCheck(chatrbtn);changeCheck(infotbtn);//此方法用来改变radiobutton的属性实现切换时的动画效果switch (checkedId){case R.id.tap_control:viewPager.setCurrentItem(0);break;case R.id.tap_chat:viewPager.setCurrentItem(1);break;case R.id.tap_info:viewPager.setCurrentItem(2);break;}}
}
fragment页面切换事件:
private class MyPagerChangeListener implements ViewPager.OnPageChangeListener{@Overridepublic void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {//position:当前页面——点击滑动的页面//positionOffset:当前页面偏移的百分比//positionOffsetPixels:当前页面偏移的像素位置 }@Overridepublic void onPageSelected(int position) {switch(position){case 0:radioGroup.check(R.id.tap_control);break;case 1:radioGroup.check(R.id.tap_chat);break;case 2:radioGroup.check(R.id.tap_info);break;}}@Overridepublic void onPageScrollStateChanged(int state) {//此方法是在当前页面状态发生改变时调用的switch(state){case 0:什么都没做;break;case 1:正在滑动;break;case 2:滑动完成;break;}//所以页面滑动时,state的应该这样改变:1(正在改变)->2(滑动完成)->0(静止状态)}
}
再创建FragmentPagerAdapter
FragmentPagerAdapter pagerAdapter=new FragmentPagerAdapter(getSupportFragmentManager()) {
//由于v4库不能直接获取FragmentManager,因此这里使用getSupportFragmentManager()间接获取@Overridepublic Fragment getItem(int position) {return fragmentlist.get(position);}@Overridepublic int getCount() {return fragmentlist.size();}
};
最后就是viewpager设置adapter和监听器,还有给radiogroup设置监听事件(当然初始的状态也要设置好):
viewPager.setAdapter(pagerAdapter);
viewPager.setCurrentItem(0);
radioGroup.check(R.id.tap_control);
changeCheck(controlrbtn);
MyPagerChangeListener myPagerChangeListener=new MyPagerChangeListener();
MyOnCheckListener myOnCheckListener=new MyOnCheckListener();
viewPager.addOnPageChangeListener(myPagerChangeListener);
radioGroup.setOnCheckedChangeListener(myOnCheckListener);
基本的控制主页面
实现功能:基本的前后左右控制、加减速,开始或停止,状态数据(速度、温度)的更新,展示机器人的视野(监控直播)。
实现方式:http请求(控制),timer周期任务执行(实时更新),webview(由于笔者比较菜,所以监控直播这块直接通过加载一个老师写好的网页来实现功能)。
实现过程:
使用HttpURLConnection发起网络请求
public void requestUrl(final String url){new Thread(new Runnable() {@Overridepublic void run() {try {String murl="http://"+url;Log.e("当前请求的ip",murl);HttpURLConnection urlConnection= (HttpURLConnection) new URL(murl).openConnection();urlConnection.setRequestMethod("POST");urlConnection.setDoOutput(true);//是否允许向网络读取数据urlConnection.setConnectTimeout(3000);urlConnection.setReadTimeout(5000);//设置连接,读取的超时限制if (urlConnection.getResponseCode()==200) {Log.e("连接服务器","成功");}} catch (IOException e) {e.printStackTrace();}}}) .start();
}
就以前进举例
安卓端这边,requestUrl(ipstr+":8080/forward");
tomcat那边会这样处理:
所以安卓端这边只需要发送类似这样的url请求就可以了,说实话笔者对于java web不是很熟,基本现在的后台都是用php写的,也只是停留在很简单的数据交互,我认为一个好的安卓开发工程师不应该只懂安卓端的开发,所以这块有必要加强。
webview加载视频流的网页
这块是老师直接提供的页面,经过很长时间的尝试都没成功,所以老师没有再为难我哈哈,让我直接用网页代替video,所以这里就写一下加载网页的代码
private void openWeb(String url,WebView webView){webView.loadUrl(url);webView.setInitialScale(130);//设置缩放比例,这里放大1.3倍webView.getSettings().setJavaScriptEnabled(true);webView.getSettings().setDomStorageEnabled(true);webView.setWebViewClient(new WebViewClient(){//如果不设置WebViewClient,请求会跳转系统浏览器@Overridepublic boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {return true;}@Overridepublic void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {handler.proceed();//接受证书}});
}
放一张运行的图片结束这块的尴尬吧:
实时更新数据
首先从网络获取json
public static void requestJson(final String url, final Handler handler){……………………………………………………InputStream is=conn.getInputStream();BufferedReader reader=new BufferedReader(new InputStreamReader(is));String rline="";StringBuilder builder_result=new StringBuilder();while ((rline=reader.readLine())!=null){builder_result.append(rline);Log.e("读取到json",rline);}Message message=new Message();message.obj=builder_result.toString();handler.sendMessage(message);is.close();}}catch (Exception e){e.printStackTrace();
}
}
然后,创建定时器及TimerTask
timer=new Timer();
timer.schedule(new TimerTask() {@Overridepublic void run() {NetWorkUtil.requestJson("http://" + ipstr + ":8080/app_GetInfo", handler);}
},1000,3*1000);@Override
public void onStop() {super.onStop();timer.cancel();//结束任务
}
最后在handler里面解析json并更新ui
Handler handler=new Handler(){@Overridepublic void handleMessage(Message msg) {super.handleMessage(msg);String json_data = null;json_data = msg.obj.toString();try {JSONObject object=new JSONObject(json_data);String temp=object.getString("temperature");String sped=object.getString("speed");//String lat=object.getString("lat");//String lon=object.getString("lon");temTv.setText("当前速度:"+temp+"℃");spdTv.setText("当前温度:"+sped+"m/s");} catch (JSONException e) {e.printStackTrace();Toast.makeText(getContext(),"数据解析出错",Toast.LENGTH_SHORT).show();temTv.setText("当前速度:--℃");spdTv.setText("当前温度:--m/s");}}
};
聊天对话界面
实现功能:聊天页面,语音识别,发送文字进行控制。
实现方式:重写BaseAdapter+listview,动态设置View的visible属性,集成科大讯飞语音识别功能,http请求。
实现过程:
listview实现聊天页面
1.写好数据源(Bean类)
public class Message {String mesg;int code;public Message(int mcode, String msg){code=mcode;mesg=msg;}public void setTypeCode(int code){this.code=code;}public int getTypeCode(){return code;}public void setMsg(String mes){mesg=mes;}public String getMsg(){return mesg;}
}
2.自定义adapter(使用ViewHolder优化)
(1)重写BaseAdapter的方法
public MesgAdapter(Context context, ArrayList<Message> messageArrayList){mcontext=context;arrayList= messageArrayList;inflater=LayoutInflater.from(context);
}//这是adapter的构造函数@Override
public int getCount() {return arrayList.size();
}@Override
public Object getItem(int position) {return arrayList.get(position);
}@Override
public long getItemId(int position) {return 0;
}@Override
public int getItemViewType(int position) {return arrayList.get(position).getTypeCode();//返回 代表某一个样式 的 数值,在getview方法里面进行判断
}@Override
public int getViewTypeCount() {return 2;//表示可以有两种样式item
}@Override
public View getView(int position, View convertView, ViewGroup parent) {switch (getItemViewType(position)) {case 0:发送消息的item;break;case 1:回复消息的item;break;……}
}
(2)创建ViewHolder类与Item布局形成映射关系
private class ViewHolder{TextView voi_msg;ImageView mhead;//发送消息
}
private class MyHolder{TextView rep_msg;ImageView rhead;//回复消息
}
(3)在getView方法中对convertView进行判断
if (convertView == null) {//没有缓存的itemconvertView = inflater.inflate(R.layout.voi_msg_item, parent, false);viewHolder = new ViewHolder();viewHolder.voi_msg=convertView.findViewById(R.id.tv_voi_msg);convertView.setTag(viewHolder);//将viewholder与convertView关联
} else {//如果有缓存的item则直接通过getTag取出缓存的viewholderviewHolder = (ViewHolder) convertView.getTag();
}//设置控件的数据
viewHolder.voi_msg.setText(arrayList.get(position).mesg);
3.给listview设置adapter
listView=view.findViewById(R.id.chatlist);
ArrayList<Message> datas=new ArrayList<>();
MesgAdapter adapter=new MesgAdapter(getActivity(),datas);
listView.setAdapter(adapter);
4.创建http的post请求
public static void postStr(final String s,final String reqstr, final String url){new Thread(new Runnable() {@SuppressLint("LongLogTag")@Overridepublic void run() {try {String str= reqstr+URLEncoder.encode(s,"utf-8");//设置编码Log.e("请求url:"+url,"发送"+str+"至服务器");HttpURLConnection connection= (HttpURLConnection) new URL(url).openConnection();connection.setDoOutput(true);connection.setDoInput(true);connection.setUseCaches(false);connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded;charset=UTF-8");connection.setRequestProperty("Content-Length", String.valueOf(str.length()));//设置请求头的一些属性connection.setRequestMethod("POST");connection.setConnectTimeout(5 * 1000);OutputStream outputStream=connection.getOutputStream();outputStream.write(str.getBytes());outputStream.flush();if (connection.getResponseCode()==connection.HTTP_OK){Log.e("请求结果","成功");}}catch (Exception e){e.printStackTrace();}}}).start();
}
5.给发送按钮设置事件:通过增加数据源,动态添加item并提交数据到网络
sendBtn.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {preferences=getActivity().getSharedPreferences("ipstr", Context.MODE_PRIVATE);url="http://"+preferences.getString("ip","")+":8080/userquestion";//由于fragment的生命周期问题,此处获取prefrences应该写在方法内部String myword=text.getText().toString();if (myword!=""&& !TextUtils.isEmpty(myword)){Message msg=new Message(1,myword);//添加发送消息itemdatas.add(msg);adapter.notifyDataSetChanged();NetWorkUtil.postStr(myword,"question=",url);//post数据text.setHint("继续输入指令");text.setText("");datas.add(new Message(2,myword));//添加回复的消息itemadapter.notifyDataSetChanged();//更新列表}else {text.setHint("发送不能为空!");}}
});
测试结果截图
语音识别
1.在讯飞开放平台获取sdk,并根据官方文档集成好
2.创建语音听写对象
SpeechUtility.createUtility(this, SpeechConstant.APPID+"=appid");
//appid需要去讯飞开放平台获取
SpeechRecognizer mIat= SpeechRecognizer.createRecognizer(this,null);
mIat.setParameter(SpeechConstant.ASR_PTT,"0");//去除标点符号
3.解析语音返回并发送结果
public class XfJsonParser {public String parseResult(String json) {StringBuffer buffer = new StringBuffer();try {// 转写结果词,默认使用第一个结果JSONTokener tokener = new JSONTokener(json);JSONObject obj = new JSONObject(tokener);JSONArray array = obj.getJSONArray("ws");for (int i = 0; i < array.length(); i++) {JSONArray items = array.getJSONObject(i).getJSONArray("cw");JSONObject object = items.getJSONObject(0);buffer.append(object.getString("w"));}} catch (Exception e) {e.printStackTrace();}return buffer.toString();}
}private void getResult(RecognizerResult result){//解析语音识别结果XfJsonParser jsonParser=new XfJsonParser();String ret=jsonParser.parseResult(result.getResultString());SpeechRecognizer.getRecognizer().stopListening();if(TextUtils.isEmpty(ret)){return;}String sn=null;try {JSONObject jsonObject=new JSONObject(result.getResultString());sn=jsonObject.optString("sn");}catch (Exception e){e.printStackTrace();}mIatResults.put(sn,ret);StringBuffer retBuffer=new StringBuffer();for (String key:mIatResults.keySet()){retBuffer.append(mIatResults.get(key));}String reg_str=retBuffer.toString();if (reg_str!=null&&!TextUtils.isEmpty(reg_str)&®_str!="") {datas.add(new Message(0, reg_str));NetWorkUtil.postStr(reg_str,"question=","http://"+preferences.getString("ip","")+":8080/userquestion");datas.add(new Message(2,reg_str));adapter.notifyDataSetChanged();//更新listview}
}
结果截图所示
导航功能
实现功能:定点导航,多点巡逻,导航记录
实现方式:集成百度地图,http请求,TabHost
定点导航
1.在百度地图开放平台下载SDK并且根据官方的集成手册进行集成
2.创建tabhost
<?xml version="1.0" encoding="utf-8"?>
<TabHost xmlns: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:id="@+id/tabhost"tools:context="com.example.qy.robotcontrol.Gps"><LinearLayoutandroid:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"><TabWidgetandroid:id="@android:id/tabs"android:layout_width="match_parent"android:layout_height="wrap_content"/><FrameLayoutandroid:layout_width="match_parent"android:layout_height="match_parent"android:id="@android:id/tabcontent"><LinearLayout<!-- 定义第一个标签页(定点导航)的内容 -->android:layout_width="match_parent"android:layout_height="match_parent"android:id="@+id/navigate"><com.baidu.mapapi.map.MapViewandroid:id="@+id/mapview"android:layout_width="match_parent"android:layout_height="match_parent" ></com.baidu.mapapi.map.MapView></LinearLayout><!-- 第二个标签页的内容(多点巡逻 )--><LinearLayoutandroid:layout_width="match_parent"android:layout_height="match_parent"android:id="@+id/patrolgps"><com.baidu.mapapi.map.TextureMapViewandroid:id="@+id/mapview2"android:layout_width="match_parent"android:layout_height="match_parent" ></com.baidu.mapapi.map.TextureMapView></LinearLayout><LinearLayout<!-- 定义第三个标签页的内容 (导航历史) -->android:layout_width="match_parent"android:layout_height="match_parent"android:id="@+id/gpsdetail"><android.support.v4.widget.SwipeRefreshLayoutandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:id="@+id/gps_info_refresh"><ListViewandroid:layout_width="match_parent"android:layout_height="match_parent"android:id="@+id/gps_info"></ListView></android.support.v4.widget.SwipeRefreshLayout></LinearLayout></FrameLayout></LinearLayout></TabHost>private void initTab(){TabHost host=findViewById(R.id.tabhost);host.setup();TabHost.TabSpec nav_tab=host.newTabSpec("tab1").setIndicator("立即导航").setContent(R.id.navigate);TabHost.TabSpec pio_tab=host.newTabSpec("tab2").setIndicator("定点巡逻").setContent(R.id.patrolgps);TabHost.TabSpec det_tab=host.newTabSpec("tab3").setIndicator("导航信息").setContent(R.id.gpsdetail);host.addTab(nav_tab);host.addTab(pio_tab);host.addTab(det_tab);
}
3.初始化地图
LocationClient locationClient=new LocationClient(getApplicationContext());
MyLocationListener locationListener=new MyLocationListener();
locationClient.registerLocationListener(locationListener);
SDKInitializer.initialize(getApplicationContext());//初始化sdk显示地图
setContentView(R.layout.activity_gps);//注意要在此方法之前初始化地图
locationClient.setLocOption(initLocationOption());
locationClient.start();
baiduMap=mapView.getMap();
baiduMap2=mapView2.getMap();//得到地图
baiduMap.setMyLocationEnabled(true);
baiduMap2.setMyLocationEnabled(true);//允许定位private LocationClientOption initLocationOption(){LocationClientOption option = new LocationClientOption();option.setLocationMode(LocationClientOption.LocationMode.Hight_Accuracy);//设置定位模式,默认高精度option.setCoorType("bd09ll");//设置返回经纬度坐标类型,默认gcj02,gcj02:国测局坐标;option.setScanSpan(6000);//设置发起定位请求的间隔,int类型,单位msoption.setOpenGps(true);//设置是否使用gps,默认falseoption.setLocationNotify(true);option.setIgnoreKillProcess(false);//设置是否在stop的时候杀死这个进程,默认不杀死option.SetIgnoreCacheException(false);//设置是否收集Crash信息,默认收集,即参数为falseoption.setWifiCacheTimeOut(5*60*1000);
//如果设置了该接口,首次启动定位时,会先判断当前WiFi是否超出有效期,若超出有效期,会先重新扫描WiFi,然后定位option.setEnableSimulateGps(false);
//设置是否需要过滤GPS仿真结果,默认需要,即参数为falsereturn option;}
private class MyLocationListener extends BDAbstractLocationListener {@Overridepublic void onReceiveLocation(BDLocation location) {double latitude = location.getLatitude(); //获取纬度信息double longitude = location.getLongitude(); //获取经度信息//float radius = location.getRadius(); //获取定位精度,默认值为0.0f//String coorType = location.getCoorType();//获取经纬度坐标类型,以LocationClientOption中设置过的坐标类型为准//int errorCode = location.getLocType();//获取定位类型、定位错误返回码,具体信息可参照类参考中BDLocation类中的说明//Log.e("获取定位返回码",errorCode+"");MyLocationData.Builder locationBuilder = new MyLocationData.Builder();locationBuilder.latitude(latitude);locationBuilder.longitude(longitude);MyLocationData locationData=locationBuilder.build();baiduMap.setMyLocationData(locationData);baiduMap2.setMyLocationData(locationData);//获取当前位置 并显示到地图上if (isFirstloc) {changeMapStatus(latitude, longitude);}}
}private void changeMapStatus(double latitude,double longitude){LatLng center=new LatLng(latitude,longitude);//设定中心点坐标MapStatus mapStatus=new MapStatus.Builder().target(center).zoom(18).build();//定义地图状态MapStatusUpdate mapStatusUpdate= MapStatusUpdateFactory.newMapStatus(mapStatus);//定义MapStatusUpdate对象,以便描述地图状态将要发生的变化baiduMap.setMapStatus(mapStatusUpdate);baiduMap2.setMapStatus(mapStatusUpdate);//改变地图状态isFirstloc=false;
}
4.设置地图的点击事件:
(1)定点导航
baiduMap.setOnMapClickListener(new BaiduMap.OnMapClickListener() {@Overridepublic void onMapClick(LatLng latLng) {double lat=latLng.latitude;double lon=latLng.longitude;changeMapStatus(lat,lon);showDialog("位置信息","此处坐标:"+"经度:"+lat+",纬度:"+lon+",去这里吗?",lat+","+lon,url+"movetopoint","location=");//点击空白地点}@Overridepublic boolean onMapPoiClick(MapPoi mapPoi) {String locname=mapPoi.getName();double lati=mapPoi.getPosition().latitude;double longi=mapPoi.getPosition().longitude;changeMapStatus(lati,longi);showDialog("位置信息","去"+locname+"吗?",lati+","+longi,url+"movetopoint","location=");return false;//点击标注点击事件}
});private void showDialog(String title, String mesg, final String laAndLo, final String murl, final String req){new AlertDialog.Builder(Gps.this).setTitle(title).setIcon(R.drawable.gps_dialogicon).setMessage(mesg).setPositiveButton("Go!", new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialog, int which) {NetWorkUtil.postStr(laAndLo,req,murl);Toast.makeText(Gps.this,"正在开始导航……",Toast.LENGTH_SHORT).show();}}).setNegativeButton("不去", new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialog, int which) {Toast.makeText(Gps.this,"取消导航",Toast.LENGTH_SHORT).show();}}).show();
}
(2)多点巡逻
baiduMap2.setOnMapClickListener(new BaiduMap.OnMapClickListener() {@Overridepublic void onMapClick(LatLng latLng) {locPopub.popubLocWindow(getLayoutInflater().inflate(R.layout.activity_gps,null),String.valueOf(latLng.latitude),String.valueOf(latLng.longitude),"未标注地点",url+"app_movebypath",mhandler,baiduMap2);}@Overridepublic boolean onMapPoiClick(MapPoi mapPoi) {locPopub.popubLocWindow(getLayoutInflater().inflate(R.layout.activity_gps,null),String.valueOf(mapPoi.getPosition().latitude),String.valueOf(mapPoi.getPosition().longitude),mapPoi.getName(),url+"app_movebypath",mhandler,baiduMap2);return false;}
});public void popubLocWindow(){List<Location>locations=new ArrayList<>();
BaiduMapOverlay baiduMapOverlay=new BaiduMapOverlay();
baiduMapOverlay.addMakers(locations,map);
…………在地图上标注几个点,然后放到arraylist中再转换成jsonArray发到服务端处理
……只粘上部分代码
locations.add(new Location(mla,mlo,ln));
if (locations.size()>=2) {
if (locations.size()>=2) {cordintArr=new JSONArray();for (int i=0;i<locations.size();i++){locObj=new JSONObject();try {locObj.put("coordinate",locations.get(i).getMyPopLat()+","+locations.get(i).getMyPopLon());cordintArr.put(locObj);locObj=null;} catch (Exception e) {e.printStackTrace();}
NetWorkUtil.requestJson(urlReq,jsonString,handler);}
(3)导航记录
1)创建adapterpublic class GpsinfoAdapter extends BaseAdapter {private Context context ;private List<Routes>routesList;private View.OnClickListener delClickListener,navaginClickListener;//点击事件接口public GpsinfoAdapter(Context context,List<Routes>routesList){this.context=context;this.routesList=routesList;}public void setRouteDel(View.OnClickListener delListener){delClickListener=delListener;}public void setNavaAgin(View.OnClickListener navaginListener){navaginClickListener=navaginListener;}@Overridepublic int getCount() {return routesList.size();}@Overridepublic Object getItem(int position) {return routesList.get(position);}@Overridepublic long getItemId(int position) {return 0;}@Overridepublic View getView(int position, View convertView, ViewGroup parent) {ViewHolder viewHolder=null;if (convertView==null){convertView= LayoutInflater.from(context).inflate(R.layout.gpsdetail_item,parent,false);viewHolder=new ViewHolder();viewHolder.idtext=convertView.findViewById(R.id.id_tv);viewHolder.pathtext=convertView.findViewById(R.id.path_tv);viewHolder.timetext=convertView.findViewById(R.id.time_tv);viewHolder.again=convertView.findViewById(R.id.navi_again);viewHolder.del=convertView.findViewById(R.id.route_del);viewHolder.del.setOnClickListener(delClickListener);viewHolder.again.setOnClickListener(navaginClickListener);//设置接口回调,注意参数不是上下文,它需要ListView所在的Activity或者Fragment处理接口回调方法convertView.setTag(viewHolder);}else {viewHolder= (ViewHolder) convertView.getTag();}Routes routes=routesList.get(position);viewHolder.idtext.setText("序号 "+routes.getId());viewHolder.pathtext.setText("路径:"+routes.getPath());viewHolder.timetext.setText("记录时间:"+routes.getTime());viewHolder.del.setTag(position);viewHolder.again.setTag(position);//设置Tag,用于判断用户当前点击的哪一个列表项的按钮,解决问题:如何知道你点击的按钮是哪一个列表项中的return convertView;}private class ViewHolder{TextView idtext,pathtext,timetext;ImageButton again,del;}2)创建列表private void createInfoList(){infoData=new ArrayList<>();new Thread(new Runnable() {@Overridepublic void run() {NetWorkUtil.requestJson(url+"app_robot_navigator","getJson",mhandler);}}).start();infoData.add(new Routes("1","上海电机学院图书馆-上海电机学院电子信息学院-教学楼c-上海电机学院第一食堂","2018-05-08 23:23:12"));infoData.add(new Routes("2","上海电机学院文理楼-上海电机学院机械学院-教学楼d-上海电机学院第三食堂","2018-05-01 12:21:10"));gpsinfoAdapter=new GpsinfoAdapter(Gps.this,infoData);gpsinfoAdapter.setRouteDel(this);gpsinfoAdapter.setNavaAgin(this);gpsinfo_list.setAdapter(gpsinfoAdapter);
}3)设置item中控件的监听事件
@Override
public void onClick(View v) {Object tagObj=v.getTag();if (tagObj!=null&&tagObj instanceof Integer) {curPos = (Integer) tagObj;curPath=infoData.get(curPos).getPath();curId=infoData.get(curPos).getId();}switch (v.getId()) {case R.id.route_del:new AlertDialog.Builder(Gps.this).setIcon(R.drawable.delbtn).setTitle("提示").setMessage("确定删除此条记录?").setPositiveButton("是的", new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialog, int which) {NetWorkUtil.postStr(curId,"pid=",url+"app_deletepath");infoData.remove(curPos);Toast.makeText(Gps.this,"删除成功",Toast.LENGTH_SHORT).show();gpsinfoAdapter.notifyDataSetChanged();}}).setNegativeButton("不要",null).show();break;case R.id.navi_again:showDialog("开始导航", "再次按照此路径导航吗?", curPath,url+"movebypath","pathcontent=");break;}
}
运行效果如下:
基本信息
实现功能:设置ip,显示产品信息
实现方式:对话框,SharedPreferences,listview
实现过程:
1.使用正则表达式匹配局域网的ip
//匹配C类地址的IP
public static final String regexCIp = "^192\\.168\\.(\\d{1}|[1-9]\\d|1\\d{2}|2[0-4]\\d|25\\d)\\.(\\d{1}|[1-9]\\d|1\\d{2}|2[0-4]\\d|25\\d)$";
//匹配A类地址
public static final String regexAIp = "^10\\.(\\d{1}|[1-9]\\d|1\\d{2}|2[0-4]\\d|25\\d)\\.(\\d{1}|[1-9]\\d|1\\d{2}|2[0-4]\\d|25\\d)\\.(\\d{1}|[1-9]\\d|1\\d{2}|2[0-4]\\d|25\\d)$";
//匹配B类地址
public static final String regexBIp = "^172\\.(1[6-9]|2\\d|3[0-1])\\.(\\d{1}|[1-9]\\d|1\\d{2}|2[0-4]\\d|25\\d)\\.(\\d{1}|[1-9]\\d|1\\d{2}|2[0-4]\\d|25\\d)$";//利用正则表达式匹配局域网ip
public static String getHostIp(){String hostIp;Pattern ip = Pattern.compile("(" + regexAIp + ")|" + "(" + regexBIp + ")|" + "(" + regexCIp + ")");Enumeration<NetworkInterface> networkInterfaces = null;try {networkInterfaces = NetworkInterface.getNetworkInterfaces();} catch (SocketException e) {e.printStackTrace();}InetAddress address;while (networkInterfaces.hasMoreElements()) {NetworkInterface networkInterface = networkInterfaces.nextElement();Enumeration<InetAddress> inetAddresses = networkInterface.getInetAddresses();while (inetAddresses.hasMoreElements()) {address = inetAddresses.nextElement();String hostAddress = address.getHostAddress();Matcher matcher = ip.matcher(hostAddress);if (matcher.matches()) {hostIp = hostAddress;return hostIp;}}}return null;
}
2.创建自定义对话框对ip进行编辑
public void showDialog(){LayoutInflater inflater= (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);RelativeLayout layout= (RelativeLayout)inflater.inflate(R.layout.wifi_info_dialog,null);final EditText ip=layout.findViewById(R.id.ipedit);sp=context.getSharedPreferences("ipstr",Context.MODE_PRIVATE);ipstr=sp.getString("ip","");ip.setText(ipstr);ip.setSelection(ipstr.length());AlertDialog alertDialog=new AlertDialog.Builder(context).setTitle("局域网信息").setIcon(R.drawable.wifiicon).setView(layout).setPositiveButton("完成", new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialog, int which) {String ips=ip.getText().toString();sp=context.getSharedPreferences("ipstr", Context.MODE_PRIVATE);editor=sp.edit();editor.putString("ip",ips).commit();//编辑ip存储到SharedPreferences中Toast.makeText(context,"修改完成",Toast.LENGTH_SHORT).show();InputMethodManager imm = (InputMethodManager)context.getSystemService(Context.INPUT_METHOD_SERVICE);imm.hideSoftInputFromWindow(ip.getWindowToken(), 0);}}).setNegativeButton("更新",null).create();alertDialog.show();alertDialog.getButton(DialogInterface.BUTTON_NEGATIVE).setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {Toast.makeText(context,"局域网信息已更新",Toast.LENGTH_SHORT).show();String hip=NetWorkUtil.getHostIp();//匹配到局域网的ipip.setText(hip);ip.setSelection(hip.length());}});
}
3.显示相关信息列表
private String[] info_name=new String[]{"型号","硬件信息","软件版本"};
private String[] info_detail=new String[]{"探索号1.0.0","Ros操作系统","Android "+android.os.Build.VERSION.RELEASE};@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_info_frgt, container, false);
listView=view.findViewById(R.id.info_list);
arrayList=new ArrayList<>();
for (int i=0;i<info_name.length;i++){Map<String,Object>map=new HashMap<>();map.put("name",info_name[i]);map.put("detail",info_detail[i]);arrayList.add(map);
}
adapter=new SimpleAdapter(getContext(),arrayList,R.layout.info_item,new String[]{"name","detail"},new int[]{R.id.textname,R.id.textdetail});
listView.setAdapter(adapter);
return view;
}
运行截图:
总结
该项目其实涉及到个人的技术含量较少,因为通过集成科大讯飞和百度地图两个SDK来实现语音识别和导航两大功能,这样确实大大加快了项目开发的进度。而在项目中用到最多的知识点就是activity生命周期的使用,fragment,listview(baseadapter的优化,item中控件的监听事件),http请求(get,post),handler,json的处理(生成和解析json等),以及SharedPreferences等等。仔细想想确实知识点不少,但自己掌握的都不是很深入,而现在不少公司往往就是看中我们对知识学习的深度,所以以后学习的方法应该改变,试着认真对待每个知识点!
这篇关于机器人远程控制系统(安卓端)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!