大作业(二)
3.2使用http访问网络
在android上发送http请求的方式一般有两个,httpurlconnection和httpclient,在这里我们使用httpurlconnection。
首先需要获取到httpurlconnection的实例,一般只需new出一个url对象,并传入目标的网络地址,然后调用一下openconnection()方法即可,如下所示:
url url = new url(“https://www.baidu.com”);
httpurlconnection connection =(httpurlconnection) url.openconnection();
得到了httpurlconnection的实例之后,我们可以设置一下http请求所使用的方法。常用的方法主要有两个,get和post。get表示希望从服务器那里获取数据,而post则表示希望提交数据给服务器。接下来就可以进行设置连接超时、读取超时的毫秒数;之后再调用getinputstream()方法就可以获取到服务器返回的输入流了,剩下的任务就是对输入流进行读取;最后将连接关闭掉。
下面我们就在com.wyd.search.common包中新建httputils.java类,代码如下所示:
public final class httputils { private static final string log_tag = "httputils connect tag"; public static string openurl(string url, string method, bundle params, string enc) { string response = null; if (method.equals("get")) { url = url + "?" + encodeurl(params); } try { log.d(log_tag, "url:" + url); httpurlconnection conn = (httpurlconnection) new url(url).openconnection(); conn.setrequestproperty("user-agent", system.getproperties().getproperty("http.agent")); conn.setreadtimeout(10000); //设置超时时间 if (method.equals("post")) { conn.setrequestmethod("post"); conn.setdooutput(true); conn.getoutputstream().write(encodeurl(params).getbytes("utf-8")); } response = read(conn.getinputstream(), enc); } catch (exception e) { log.e(log_tag, e.getmessage()); throw new runtimeexception(e.getmessage(), e); } return response; } private static string read(inputstream in, string enc) throws ioexception { stringbuilder sb = new stringbuilder(); inputstreamreader isr = null; bufferedreader r = null; if (enc != null) { //按指定的编码读入流 r = new bufferedreader(new inputstreamreader(in, enc), 1000); } else { //按默认的编码读入 r = new bufferedreader(new inputstreamreader(in), 1000); } for (string line = r.readline(); line != null; line = r.readline()) { sb.append(line); } in.close(); return sb.tostring(); } public static string encodeurl(bundle parameters) { if (parameters == null) { return ""; } stringbuilder sb = new stringbuilder(); boolean first = true; for (string key : parameters.keyset()) { if (first) { first = false; } else { sb.append("&"); } sb.append(key + "=" + parameters.getstring(key)); } return sb.tostring(); } }
3.3查询活动的搜索条件
我们在查询的时候,会有一些限制条件,比如说查询的ip是否合法、手机号码位数是否够......因此要进行一些限制。
我们在com.wyd.search.common包中新建activityutils类,代码如下:
public final class activityutils { public static void showdialog(context context, string button, string title, string message) { new alertdialog.builder(context).settitle(title).setmessage(message) .setneutralbutton(button, null).create() .show(); } //校验str是否为空或为"" public static boolean validatenull(string str) { if ((str == null) || str.equals("")) { return false; } else { return true; } } //校验str中是否全部是数字,用到了正则表达式 public static boolean validatenumber(string str) { pattern pattern = pattern.compile("[0-9]"); matcher matcher = pattern.matcher(str); return matcher.matches(); } //校验ip是否合法 public static boolean validateip(string str) { pattern pattern = pattern.compile("[0-9],."); matcher matcher = pattern.matcher(str); return matcher.matches(); } }
4 查询工具创建
在第二阶段,我们进行具体实体类的,首先我们需要申请相应的接口数据,这个我们可以轻松在聚合数据网站上得到,然后把具体的功能一个个实现,我们在第一步新建的包中新建相应的查询实体类。具体实现如下:
4.1快递单号查询
在com.wyd.search.ems包中新建ems.java类,代码如下:
public class ems implements serializable { private static final long serialversionuid = 1l; // 变量声明 private string message; //消息体 private string time; //时间 private string context; //状态 private string status; //返回值状态:0,查询失败;1:查询成功 private string company; //快递公司名称 private string order; //单号
接下来新建快递查询的监听类emslistener,代码如下:
public class emssearch extends activity { private spinner emscompanies; private edittext emsorder; private resources res; private string[] emscodes; private int pos = 0; private string selectedcom; private search search;@override public void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); this.requestwindowfeature(window.feature_no_title); setcontentview(r.layout.ems); res = this.getresources(); emscodes = res.getstringarray(r.array.ems_code); emsorder = (edittext) this.findviewbyid(r.id.ems_order); emscompanies = (spinner) this.findviewbyid(r.id.ems_com); arrayadapter < charsequence > adapter = arrayadapter.createfromresource(this, r.array.ems_company, android.r.layout.simple_spinner_item); adapter.setdropdownviewresource(android.r.layout.simple_spinner_dropdown_item); emscompanies.setadapter(adapter); emscompanies.setonitemselectedlistener(selectedlistener); search = new search(); } private adapterview.onitemselectedlistener selectedlistener = new adapterview.onitemselectedlistener() { public void onitemselected(adapterview < ?>parent, view v, int position, long id) { // 用户选择了,记录下用户选择的公司所对应的代码 pos = position; selectedcom = (string) parent.getitematposition(position); } public void onnothingselected(adapterview < ?>parent) { // todo auto-generated method stub } }; public string getcode() { return emscodes[pos - 1]; //因为城市spinner中多了一个请选择 } //检验是否选择了一个快递公司 public boolean validateselect() { if (pos < 1 || pos > emscodes.length) { return false; } else { return true; } } public void onclick(view v) { if (v.getid() == r.id.ems_search) { string order = this.emsorder.gettext().tostring().trim(); if (this.validateselect()) { if (activityutils.validatenull(order)) { //校验成功 string companycode = this.getcode(); bundle bundle = new bundle(); bundle.putstring("company", selectedcom); bundle.putstring("order", order); this.getintent().putextras(bundle); //记录下公司和单号 emslistener listener = new emslistener(this); search.asyncrequest(companycode, order, listener); } else { activityutils.showdialog(this, res.getstring(r.string.ok), res.getstring(r.string.tip), res.getstring(r.string.ems_order_error)); } } else { activityutils.showdialog(this, res.getstring(r.string.ok), res.getstring(r.string.tip), res.getstring(r.string.ems_noselect)); } } } }
最后就是查询后返回相应的数据,新建searchresult.java,代码如下:
public class searchresult extends activity { private textview emscompany, emsorder, emstime, emscontext; private resources res; public void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); this.requestwindowfeature(window.feature_no_title); setcontentview(r.layout.ems_info); this.emscompany = (textview) this.findviewbyid(r.id.ems_company); this.emsorder = (textview) this.findviewbyid(r.id.ems_order); this.emstime = (textview) this.findviewbyid(r.id.ems_time); this.emscontext = (textview) this.findviewbyid(r.id.ems_context); res = this.getresources(); this.showresult(); } private void showresult() { bundle bundle = this.getintent().getextras(); ems ems = (ems) bundle.getserializable("ems"); if (ems != null) { if (ems.getstatus().equals("1")) { this.emscompany.settext(ems.getcompany()); this.emsorder.settext(ems.getorder()); this.emstime.settext(ems.gettime()); this.emscontext.settext(ems.getcontext()); } else { activityutils.showdialog(this, res.getstring(r.string.ok), res.getstring(r.string.tip), ems.getmessage()); } } else { activityutils.showdialog(this, res.getstring(r.string.ok), res.getstring(r.string.tip), res.getstring(r.string.ems_fail)); } } }
4.1手机号归属地查询
我们首先在com.wyd.search.telephone包中新建手机号归属地查询的实体类telephone.java,代码如下:
public class telephone implements serializable{ private static final long serialversionuid = 1l; private string mobile; // private string queryresult; //返回结果 private string province; //省份 private string city; //城市 private string areacode; //区号 private string postcode; // private string corp; // private string card; //卡类型
我们可在聚合数据网站上申请数据,然后应用网站提供的接口,通过对申请的数据得知,手机号码的查询涵盖中国移动、中国联通和中国电信,查询的结果包括省份、城市、区号和卡类型。
接下来新建快递查询的监听类telephonelistener,代码如下:
public class telephonelistener implements requestlistener { private telephonesearch context; private progressdialog progress; private resources res; public telephonelistener(telephonesearch context) { this.context = context; res = context.getresources(); progress = progressdialog.show(context, res.getstring(r.string.tel_searching), res.getstring(r.string.getting)); progress.show(); }@override public void oncomplete(final string result) { this.context.runonuithread(new runnable() {@override public void run() { intent intent = new intent(); bundle bundle = new bundle(); bundle.putserializable("telephone", parsejson(result)); intent.putextras(bundle); intent.setclass(context, searchresult.class); progress.dismiss(); context.startactivity(intent); } }); } public void onexception(exception e) { this.context.runonuithread(new runnable() { public void run() { if (progress != null) { progress.dismiss(); } activityutils.showdialog(context, res.getstring(r.string.ok), res.getstring(r.string.tip), res.getstring(r.string.get_nothing)); } }); } public telephone parsejson(string jsonstr) { telephone tel = null; jsonstr = jsonstr.substring(14, jsonstr.length() - 2); try { tel = new telephone(); jsonobject jsonobj = new jsonobject(jsonstr); tel.setmobile(jsonobj.getstring("mobile")); tel.setqueryresult(jsonobj.getstring("queryresult")); tel.setprovince(jsonobj.getstring("province")); tel.setcity(jsonobj.getstring("city")); tel.setareacode(jsonobj.getstring("areacode")); tel.setpostcode(jsonobj.getstring("postcode")); tel.setcorp(jsonobj.getstring("corp")); tel.setcard(jsonobj.getstring("card")); } catch(jsonexception e) { log.e(log_tag, e.getmessage()); } return tel; } private static final string log_tag = "telephonelistener"; }
我们从聚合数据网站上获得的数据可以使用xml和json两种方法解析,这里我们解析成json格式数据,因为相对于xml,json的主要优势在于它的体积更小,在网络上传输的时候可以更省流量。
然而,解析json数据的方法也有很多,我们使用jsonobject,首先将http请求的地址加上,然后在得到了服务器返回的数据后调用parsejsonwithjsonobject()方法来解析数据。每个jsonobject对象中包含mobile、province、areacode和card等这些数据,接下来只需要调用getstring()方法将这些数据取出,并打印出来即可。
最后就是更新ui的问题,要将解析出来的数据显示出来,代码如下:
public class searchresult extends activity { private textview mobile, province, city, areacode, postcode, card; public void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); this.requestwindowfeature(window.feature_no_title); setcontentview(r.layout.telephone_info); mobile = (textview) this.findviewbyid(r.id.telephone_mobile); province = (textview) this.findviewbyid(r.id.telephone_province); city = (textview) this.findviewbyid(r.id.telephone_city); areacode = (textview) this.findviewbyid(r.id.telephone_areacode); postcode = (textview) this.findviewbyid(r.id.telephone_postcode); card = (textview) this.findviewbyid(r.id.telephone_card); this.showresult(); } public void showresult() { intent intent = this.getintent(); bundle bundle = intent.getextras(); telephone tel = (telephone) bundle.getserializable("telephone"); if (tel != null) { mobile.settext(tel.getmobile()); province.settext(tel.getprovince()); city.settext(tel.getcity()); areacode.settext(tel.getareacode()); postcode.settext(tel.getpostcode()); card.settext(tel.getcard()); } } }
4.3天气的查询
我们首先在com.wyd.search.weather包中新建手机号归属地查询的实体类weather.java,代码如下:
public class weather implements serializable { private static final long serialversionuid = 13835783478884l; private string day; //星期 private string date; //日期 private string low; //最低温度 private string high; //最高温度 private string code; //天气状况码 private string text; //天气状况码,对应的天气类型
接着我偶们继续新建search类,代码如下:
public class search { //这里使用的是雅虎天气查询url private static final string http_url = "https://weather.yahooapis.com/forecastrss"; private static final string method = "get"; private static final string log_tag = "com.search.weather.search"; public string request(string woeid) { if (woeid != null) { bundle params = new bundle(); params.putstring("w", woeid); //城市对应的id params.putstring("u", "c"); //华氏温度是f,摄氏温度是c。这里采用摄氏度 return httputils.openurl(http_url, method, params, null); } else { return null; } } //异步封装 public void asyncrequest(final string city, final requestlistener listener) { //子线程中更新ui new thread(new runnable() {@override public void run() { try { string response = request(city); listener.oncomplete(response); } catch(exception e) { log.e(log_tag, e.getmessage()); listener.onexception(e); } } }).start(); } }
下面创建weatherlistener.java,代码如下:
public class weatherlistener implements requestlistener { private weathersearch context; private progressdialog progress; private resources res; public weatherlistener(weathersearch context) { this.context = context; res = this.context.getresources(); this.progress = progressdialog.show(context, res.getstring(r.string.wea_searching), res.getstring(r.string.getting)); this.progress.show(); } public void oncomplete(final string result) { context.runonuithread(new runnable() { public void run() { try { inputstream is = null; is = new bytearrayinputstream(result.getbytes("utf-8")); list < weather > results = weatherpullparser.getdata(is); if (results.size() >= 2) { weather today = results.get(0); weather tomorrow = results.get(1); intent intent = new intent(); bundle bundle = new bundle(); bundle.putserializable("today", today); bundle.putserializable("tomorrow", tomorrow); intent.putextras(bundle); intent.setclass(context, searchresult.class); if (progress != null) { progress.dismiss(); } context.startactivity(intent); } else { if (progress != null) { progress.dismiss(); } activityutils.showdialog(context, res.getstring(r.string.ok), res.getstring(r.string.tip), res.getstring(r.string.xml_error)); } } catch(unsupportedencodingexception e) { log.e(log_tag, e.getmessage()); activityutils.showdialog(context, res.getstring(r.string.ok), res.getstring(r.string.tip), res.getstring(r.string.xml_error)); } } }); } public void onexception(final exception e) { context.runonuithread(new runnable() {@override public void run() { if (progress != null) { progress.dismiss(); } activityutils.showdialog(context, res.getstring(r.string.ok), res.getstring(r.string.tip), res.getstring(r.string.get_nothing)); } }); } private static final string log_tag = "weatherlistener"; }
然后我们就要对服务器返回的数据进行解析了,由于这里我们用的是雅虎天气提供的数据,所以这里我们运用pull的解析方式。
新建weatherpullparser.java,代码如下:
public class weatherpullparser { public static list < weather > getdata(inputstream reader) { list < weather > result = null; xmlpullparser parser = xml.newpullparser(); weather wea = null; string tagname = null; try { parser.setinput(reader, "utf-8"); int eventcode = parser.geteventtype(); //返回事件码类型 while (eventcode != xmlpullparser.end_document) { switch (eventcode) { case xmlpullparser.start_document: //初始化 result = new arraylist < weather > (); break; case xmlpullparser.start_tag: //一个元素的开始 tagname = parser.getname(); //获取当前标签的名称 if (tagname.equalsignorecase("forecast")) { wea = new weather(); wea.setday(parser.getattributevalue(null, "day")); wea.setdate(parser.getattributevalue(null, "date")); wea.setlow(parser.getattributevalue(null, "low")); wea.sethigh(parser.getattributevalue(null, "high")); wea.settext(parser.getattributevalue(null, "text")); wea.setcode(parser.getattributevalue(null, "code")); result.add(wea); } break; } eventcode = parser.next(); //解析下一个元素 } } catch(exception e) { log.e("weatherpullparser", e.getmessage()); } return result; } }
最后就是就是就将解析出阿里的数据显示出来,在这个包下新建searchresult.java,代码如下:
public class searchresult extends activity { private textview today, tomorrow, low1, low2, high1, high2; private resources res; public void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); this.requestwindowfeature(window.feature_no_title); setcontentview(r.layout.weather_info); today = (textview) this.findviewbyid(r.id.wea_today); tomorrow = (textview) this.findviewbyid(r.id.wea_tomorrow); low1 = (textview) this.findviewbyid(r.id.wea_low); low2 = (textview) this.findviewbyid(r.id.wea_low2); high1 = (textview) this.findviewbyid(r.id.wea_high); high2 = (textview) this.findviewbyid(r.id.wea_high2); res = this.getresources(); this.showresult(); } private void showresult() { intent intent = this.getintent(); bundle bundle = intent.getextras(); weather w_today = (weather) bundle.getserializable("today"); weather w_tomorrow = (weather) bundle.getserializable("tomorrow"); string unit = res.getstring(r.string.wea_unit); if (w_today != null) { string today_codition = this.getcondition(w_today.getcode()); //获取code对应的天气 today.settext(today_codition); low1.settext(w_today.getlow() + unit); high1.settext(w_today.gethigh() + unit); } if (w_tomorrow != null) { string tommorrow_condition = this.getcondition(w_tomorrow.getcode()); tomorrow.settext(tommorrow_condition); low2.settext(w_tomorrow.getlow() + unit); high2.settext(w_tomorrow.gethigh() + unit); } } //根据代码获取对应的天气信息。在weather的string-array中匹配 private string getcondition(string code) { string[] weathers = res.getstringarray(r.array.weather); int temp = integer.parseint(code); if (temp < 48 && temp >= 0) { return weathers[temp]; } return res.getstring(r.string.wea_undefine); } }