Android studio 百度地图开发(5)查询周边服务(加油站)
email:[email protected]
开发环境:win7 64位,Android Studio,请注意是Android Studio,使用的导航SDK版本:3.1.0。
大致功能为:通过百度地图定位获得当前位置,然后通过加油站数据接口(https://www.juhe.cn/docs/api/id/7)搜索周边的加油站信息,并在地图上显示。这里,我把访问加油站数据接口的部分放在了服务器上,因为后期还有一些其他功能,不可能都放在手机端去实现。
需要先申请api_key,很简单,没有百度地图的API_KEY那么复杂,地址:https://www.juhe.cn/docs/api/id/7。
这部分,本人不知道怎么去描述,因为有web基础,使用过SSM(spring+springMVC+Mybatis)架构,所以还是继续使用SSM。关于SSM架构的服务器环境搭建,资料很多,就不赘述了,而且,主要功能并不在于服务器上,换一个架构甚至“没有架构”都行。
在服务器端主要要实现对加油站数据的访问,按照官方的API说明,通过以下代码实现了数据访问:
package com.intveh.component.gas.controller; import java.io.BufferedReader; import java.io.ByteArrayOutputStream; import java.io.DataOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.UnsupportedEncodingException; import java.net.HttpURLConnection; import java.net.URL; import java.net.URLEncoder; import java.util.HashMap; import java.util.Map; import net.sf.json.JSONArray; import net.sf.json.JSONObject; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; import com.intveh.component.car.model.Car; @Controller public class GasController { public static final String DEF_CHATSET = "UTF-8"; public static final int DEF_CONN_TIMEOUT = 30000; public static final int DEF_READ_TIMEOUT = 30000; public static String userAgent = "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/29.0.1547.66 Safari/537.36"; /** * 请求接口地址 */ public static String url = "http://apis.juhe.cn/oil/local"; /** * AppKey */ public static String key = "cbee44f8a21c371***********51e8b9";//改为自己的key /** * 查询附近的加油站 * * @param 经纬度 * * @return 查询结果 json */ @RequestMapping(value = "/gas/searchNear") @ResponseBody public void searchNear(HttpServletRequest request,HttpServletResponse response) throws ServletException,IOException{ //response.setHeader("Access-Control-Allow-Origin", "*"); //Car car = carDAO.getCar(carId); //return car; String result = ""; //System.out.println("开始搜索"); /** * 纬度 */ String latitude = request.getParameter("latitude"); /** * 经度 */ String longitude = request.getParameter("longitude"); /** * 搜索范围 */ String radius = request.getParameter("radius")==null?"1000":request.getParameter("radius"); /** * 页数 */ String page = "1"; /** * 格式 */ String format = "1"; //System.out.println(longitude+","+latitude+","+radius+","+page+","+format); Map params = new HashMap(); if(latitude!=null&&longitude!=null&&!"".equals(latitude)&&!"".equals(longitude)) { params.put("lon", longitude); params.put("lat", latitude); params.put("r", radius); params.put("page", page); params.put("format",format); params.put("key", key); JSONObject object = new JSONObject(); //System.out.println(longitude+","+latitude+","+radius+","+page+","+format); try { result =net(url, params, "GET"); object = JSONObject.fromObject(result); if(object.getInt("error_code")==0){ System.out.println(object.get("result")); }else{ System.out.println(object.get("error_code")+":"+object.get("reason")); } response.setContentType("text/json; charset=UTF-8"); response.getOutputStream().write(object.get("result").toString().getBytes("UTF-8")); //System.out.println(object.get("result")); } catch (Exception e) { e.printStackTrace(); } //response.setHeader("Access-Control-Allow-Origin", "*"); //response.reset(); //response.setContentType(String); //response.getOutputStream().write(object.toString().getBytes("UTF-8")); } } /** * * @param strUrl 请求地址 * @param params 请求参数 * @param method 请求方法 * @return 网络请求字符串 * @throws Exception */ public static String net(String strUrl, Map params,String method) throws Exception { HttpURLConnection conn = null; BufferedReader reader = null; String rs = null; try { StringBuffer sb = new StringBuffer(); if(method==null || method.equals("GET")){ strUrl = strUrl+"?"+urlencode(params); } URL url = new URL(strUrl); System.out.println("url = "+url); conn = (HttpURLConnection) url.openConnection(); if(method==null || method.equals("GET")){ conn.setRequestMethod("GET"); }else{ conn.setRequestMethod("POST"); conn.setDoOutput(true); } conn.setRequestProperty("User-agent", userAgent); conn.setUseCaches(false); conn.setConnectTimeout(DEF_CONN_TIMEOUT); conn.setReadTimeout(DEF_READ_TIMEOUT); conn.setInstanceFollowRedirects(false); conn.connect(); /* if (params!= null && method.equals("POST")) { try (DataOutputStream out = new DataOutputStream(conn.getOutputStream())) { out.writeBytes(urlencode(params)); } }*/ InputStream is = conn.getInputStream(); reader = new BufferedReader(new InputStreamReader(is, DEF_CHATSET)); String strRead = null; while ((strRead = reader.readLine()) != null) { sb.append(strRead); } rs = sb.toString(); } catch (IOException e) { e.printStackTrace(); } finally { if (reader != null) { reader.close(); } if (conn != null) { conn.disconnect(); } } return rs; } //将map型转为请求参数型 public static String urlencode(Map<String,Object>data) { StringBuilder sb = new StringBuilder(); for (Map.Entry i : data.entrySet()) { try { sb.append(i.getKey()).append("=").append(URLEncoder.encode(i.getValue()+"","UTF-8")).append("&"); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } } return sb.toString(); } }使用一下数据访问服务器即可查看获得的加油站信息:
(对于我)稍微有点难度的还是在手机端功能的实现。
为了更加方便的传递数据,写了一个加油站信息类,对数据实体化。同时实现了Serializable接口,因为后面需要利用intent传递list<GasStationModel>时,将list强制转化成serializable。
package intvehapp.intvehapp; import java.io.Serializable; import java.util.Map; /** * Created by chen on 2016/4/2. */ public class GasStationModel implements Serializable { public GasStationModel( String area, String fwlsmc, String address, String areaname, String distance, String exhaust, String discount, String lon, String brandname, String type, Map<String,String> price, Map<String,String> gastprice, String name, String id, String lat, String position) { this.area = area; this.address = address; this.areaname = areaname; this.brandname = brandname; this.discount = discount; this.distance = distance; this.exhaust = exhaust; this.fwlsmc = fwlsmc; this.gastprice = gastprice; this.id = id; this.price = price; this.lon = lon; this.type = type; this.name = name; this.lat = lat; this.position = position; } /** * 邮编 */ private String area; /** * 加油卡信息 */ private String fwlsmc; /** * 加油站地址 */ private String address; /** * 城市区域 */ private String areaname; /** * 距离? */ private String distance; /** * 尾气排放标准 */ private String exhaust; /** * 是否打折加油站 */ private String discount; /** * 百度地图经度 */ private String lon; /** * 运营商类型 */ private String brandname; /** * 加油站类型 */ private String type; /** * 省控基准油价 */ private Map<String,String> price; /** * 加油站油价 */ private Map<String,String> gastprice; /** * 加油站名字 */ private String name; /** * id */ private String id; /** * 谷歌地图坐标 */ private String position; /** * 百度地图纬度 */ private String lat; public String getId() { return id; } public void setId(String id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getArea() { return area; } public void setArea(String area) { this.area = area; } public String getFwlsmc() { return fwlsmc; } public void setFwlsmc(String fwlsmc) { this.fwlsmc = fwlsmc; } public String getAddress() { return address; } public void setAddress(String address) { this.address = address; } public String getAreaname() { return areaname; } public void setAreaname(String areaname) { this.areaname = areaname; } public String getDistance() { return distance; } public void setDistance(String distance) { this.distance = distance; } public String getDiscount() { return discount; } public void setDiscount(String discount) { this.discount = discount; } public String getExhaust() { return exhaust; } public void setExhaust(String exhaust) { this.exhaust = exhaust; } public String getLon() { return lon; } public void setLon(String lon) { this.lon = lon; } public String getBrandname() { return brandname; } public void setBrandname(String brandname) { this.brandname = brandname; } public String getType() { return type; } public void setType(String type) { this.type = type; } public Map<String, String> getPrice() { return price; } public void setPrice(Map<String, String> price) { this.price = price; } public Map<String, String> getGastprice() { return gastprice; } public void setGastprice(Map<String, String> gastprice) { this.gastprice = gastprice; } public String getPosition() { return position; } public void setPosition(String position) { this.position = position; } public String getLat() { return lat; } public void setLat(String lat) { this.lat = lat; } }
一开始,直接在主线程中访问服务器,最终发现失败了,查阅了资料后才知道:android4.0以后的版本,主线程(UI线程)不在支持网络请求,原因大概是影响主线程,速度太慢,容易卡机,所以需要开启新的线程请求数据。
/** * 通过handler与主线程通信 */ final Handler handler = new Handler() { @Override public void handleMessage(Message msg) { super.handleMessage(msg); Bundle data = msg.getData(); String err = data.getString("err"); /** * 查询成功 */ if("0".equals(err)) { List<GasStationModel> listGasStation = (List<GasStationModel> )data.getSerializable("listGasStation"); Toast.makeText(BaiDuMapActivity.this, "查询成功"+listGasStation.size(), Toast.LENGTH_LONG).show(); } else { Toast.makeText(BaiDuMapActivity.this, "附近没有加油站信息", Toast.LENGTH_LONG).show(); } //Log.i("mylog", "请求结果为-->" + val); // TODO // UI界面的更新等相关操作 } }; /** * 开启一个新的线程,访问服务器 * 当有数据返回时,通过handler传递消息 */ new Thread(new Runnable() { @Override public void run() { //请求数据 List<GasStationModel> listGasStation = ConnectServer.searchNearGas(params); //发送消息 Message message = new Message(); Bundle bundle = new Bundle(); if(listGasStation!=null) { bundle.putSerializable("listGasStation", (Serializable) listGasStation); bundle.putString("err","0");//成功 } else bundle.putString("err","1");//失败 message.setData(bundle); handler.sendMessage(message); } }).start();
考虑到后期对服务器访问还会很多,所以就单独建了一个访问服务器的类。
实现对服务器的访问,搜索周边加油站。
/** * Created by chen on 2016/4/2. */ public class ConnectServer { public static List<GasStationModel> searchNearGas(Map<String, String> params) { /** * 请求地址 */ String path = serverURL+"gas/searchNear?key="+key+"&"; /** * 添加参数 */ List<GasStationModel> listGasStation = new ArrayList<GasStationModel>(); try { StringBuilder url = new StringBuilder(path); URL nURL = new URL("http://www.baidu.com"); //url.append("?"); for (Map.Entry<String, String> entry : params.entrySet()) { url.append(entry.getKey()).append("="); url.append(URLEncoder.encode(entry.getValue(), "UTF-8"));// 编码 url.append('&'); } url.deleteCharAt(url.length() - 1); HttpURLConnection connection = (HttpURLConnection) new URL( url.toString()).openConnection(); //HttpURLConnection connection = (HttpURLConnection) nURL.openConnection(); connection.setConnectTimeout(5000); connection.setRequestMethod("GET"); String result = ""; InputStream in = connection.getInputStream(); try { Thread.sleep(300); result = read(connection.getInputStream()); } catch (InterruptedException e) { e.printStackTrace(); } /** * 解析JSON数据等等<span style="font-family:Microsoft YaHei;">操作</span> */ } }catch (Exception e ) { e.printStackTrace(); } return listGasStation; } private static String read(InputStream in) throws Exception { byte[] data; int length = in.available(); ByteArrayOutputStream bout = new ByteArrayOutputStream(); byte[]buf = new byte[1024]; int len = 0; while((len = in.read(buf))!=-1){ bout.write(buf, 0, len); } data = bout.toByteArray(); return new String(data,"UTF-8"); } }
其实整个流程的思路还是很简单:定位获取当前数据->访问加油站数据接口获得周边加油站位置信息->回调,在地图上显示。但是,实现起来有些地方还是很费心,比如手机端接收数据不完整的情况。