前言:
水平:自学Android十五天,以前有过混日子的编程经验。
目标: 《第一行代码》学完之后,总想写个APP,天气的APP写了个初版,后面再说,今天演示的是制作快递查询APP的整个经过。
适合人群:新手
工具:Android Studio 2.2.2
涉及到的相应要修改的文件,res->value->strings.xml文件
KuaiDISearch
请输入快递单号:
查询
input your Courier number
看默认的输入框不爽,OK,我们来修改一下样式。在layout文件下新建一个名为edit_bg.xml的文件。
然后天剑EditText的android:background=”@layout/edit_bg”
-
在values下新建一个名为arrays.xml的文件,
- 申通
- EMS
- 顺丰
- 圆通
- 中通
- 韵达
- 天天
- 汇通
- 全峰
- 德邦
- 宅急送
我只找到十一家,其他的我暂时还没看。
然后设置Spinner的entries属性。
android:entries=”@array/kdcompany”
最后我们还要设置每一个item的样式。
在layout下新建一个名为item_list.xml文件。(csdn的markdown编辑器不知道为啥不显示我在markdownpad2里编辑内容,大家直接看源码吧。)
整体布局就是垂直方向线性布局,在第二层,嵌套一个水平方向的线性布局。
涉及到的控件:一个TextView,EditText,Spinner,Button,ListView
知识点:
听说ListView是安卓开发常用的控件,看起来好像是。
我们的第一版的需求不要太复杂,把快递查询的结果分成两列,一列显示时间,一列显示内容(快递到哪儿了)
Your content must have a ListView whose id attribute is ‘android.R.id.list’
原来在layout_main.xml中ListView的id需要使用系统的。
这一步需要注意的问题是ListView 控件的id要使用Android系统内置的 android:id=”@android:id/list”
忘了说了,我们让我们的MainActivity继承ListActivity,即extends ListActivity。
昨天夜里一点逛知乎,看到了一个快递的免费接口,这让我马上想到做出这个应用。
http://www.kuaidi100.com/query?type=快递公司代号&postid=快递单号
快递公司代号:申通=”shentong” EMS=”ems” 顺丰=”shunfeng” 圆通=”yuantong” 中通=”zhongtong” 韵达=”yunda” 天天=”tiantian” 汇通=”huitongkuaidi” 全峰=”quanfengkuaidi” 德邦=”debangwuliu” 宅急送=”zhaijisong”
示例:http://www.kuaidi100.com/query?type=tiantian&postid=XXXXXXXXXXX
网站返回的是JSON数据,为了更好地阅读JSON数据,可以把返回的数据复制到以下网址,可以格式化JSON数据。
www.bejson.com,其他类似的网站也行,点我
导入了org.apache.http.legacy还是无效呢,因为有两个版本的。
还要设置targetSdkVersion与legacy包相匹配。
先声明:
private Button query;
在onCreate方法里赋值:
query = (Button)findViewById(R.id.query);
用匿名内部类来写点击事件(其他写法,可以参考我的博文Button点击事件的四种写法)
query.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
sendRequest();
}
});
点击按钮之后,我们想服务器(接口所在的)发送请求,sendRequest方法就是干这个的。
//发送Http请求
private void sendRequest(){
new Thread(new Runnable() {
@Override
public void run() {
try{
HttpClient httpClient = new DefaultHttpClient();
//处理快递单号
HttpGet httpGet = new HttpGet(http://www.kuaidi100.com/query?type=shunfeng&postid=XXXXXXX);//XXXXXX处填写快递单号
HttpResponse httpResponse = httpClient.execute(httpGet);
if(httpResponse.getStatusLine().getStatusCode() == 200){
//请求和响应都成功了
HttpEntity entity = httpResponse.getEntity();
String response = EntityUtils.toString(entity,"utf-8");
parseJSON(response);
}
}catch (Exception e)
{
e.printStackTrace();
}
}
}).start();
}
在这里补一句,HttpClient需要自己在libs添加一个jar包。自己通过在windows上搜索,找到org.apache.http.legacy.jar 还要注意一个版本的问题,你的build.gradle(Module:app)里的targetSdkVersion是24,那么你就在例如D:\Android\sdk\platforms\android-24\optional文件夹下找。
android-24,我之前找了个android-23的,出不来
接受到的JSON数据如下:
"message": "ok",
"nu": "XXXXXXXXXXX",
"ischeck": "0",
"condition": "00",
"com": "tiantian",
"status": "200",
"state": "0",
"data": [
{
"time": "2016-12-18 18:57:54",
"ftime": "2016-12-18 18:57:54",
"context": "快件已签收,签收人是乡镇代理点,签收网点是XXXXXX",
"location": ""
},
ArrayList
//解析JSON数据
private void parseJSON(String jsonData){
try{
//我们需要解析数组data的数据,其中time和context就是需要的字段
JSONArray jsonArray = new JSONObject(jsonData).getJSONArray("data");
for (int i = 0;i();
map.put("time",time);
map.put("context",context);
list.add(map);
}
//在子线程向ListView里添加数据
new Thread(){
public void run(){
runOnUiThread(new Runnable() {
@Override
public void run() {
SimpleAdapter simpleAdapter = new SimpleAdapter(MainActivity.this,list,
R.layout.item_list,form,to);
setListAdapter(simpleAdapter);
//假如没有数据,提醒用户
if(lv.getCount() == 0){
Toast.makeText(MainActivity.this,"还没有数据",Toast.LENGTH_LONG).show();
}
}
});
}
}.start();
}catch (Exception e)
{
e.printStackTrace();
}
}
Only the original thread that created a view hierarchy can touch its views.
到这里,应该可以查询到单条数据了,
回到上面的sendRequest方法。可以看到我们刚才发送请求的地址是:
//处理快递单号
HttpGet httpGet = new HttpGet(http://www.kuaidi100.com/query?
type=shunfeng&postid=XXXXXXX);//XXXXXX处填写快递单号
声明:
private EditText postid;
private Spinner spinner;
赋值
postid = (EditText)findViewById(R.id.postid);
spinner = (Spinner)findViewById(R.id.spinner);
需要修改一下sendRequest方法。
//发送Http请求
private void sendRequest(){
new Thread(new Runnable() {
@Override
public void run() {
try{
HttpClient httpClient = new DefaultHttpClient();
//处理快递单号
String queryString = checkPostid();
HttpGet httpGet = new HttpGet(queryString);
HttpResponse httpResponse = httpClient.execute(httpGet);
if(httpResponse.getStatusLine().getStatusCode() == 200){
//请求和响应都成功了
HttpEntity entity = httpResponse.getEntity();
String response = EntityUtils.toString(entity,"utf-8");
parseJSON(response);
}
}catch (Exception e)
{
e.printStackTrace();
}
}
}).start();
}
checkPostid方法就是通过识别快递单号是哪家的快递,给服务器传递响应的请求
//识别快递单号是哪家的快递,给服务器传递响应的请求
private String checkPostid(){
//基础链接
String baseStr = "http://www.kuaidi100.com/query?type=";
String type= "";
String postidNumber = postid.getText().toString().trim();
String kuaidiCompany = spinner.getSelectedItem().toString().trim();
Log.d("post id",postidNumber);
Log.d("kuaidiCompany id",kuaidiCompany);
if(kuaidiCompany.equals("申通")){
type = "shentong";
}else if(kuaidiCompany.equals("EMS")){
type = "ems";
}else if(kuaidiCompany.equals("顺丰")){
type = "shunfeng";
}else if(kuaidiCompany.equals("圆通")){
type = "yuantong";
}else if(kuaidiCompany.equals("中通")){
type = "zhongtong";
}else if (kuaidiCompany.equals("韵达")){
type = "yunda";
}else if (kuaidiCompany.equals("天天")){
type = "tiantian";
}else if (kuaidiCompany.equals("汇通")){
type = "huitongkuaidi";
}else if (kuaidiCompany.equals("全峰")){
type = "quanfengkuaidi";
}else if (kuaidiCompany.equals("德邦")){
type = "debangwuliu";
}else if(kuaidiCompany.equals("宅急送")){
type = "zhaijisong";
}
Log.d("url",baseStr + type + "&postid=" + postidNumber);
return baseStr + type + "&postid=" + postidNumber;
}
天天,顺丰,中通,韵达都测试过,没有问题。
为了有更好的用户体验,在没有数据的时候,给一个Toast提示一下用户。
用listview的getCount方法,假如是0,说明没有数据。
//假如没有数据,提醒用户
if(lv.getCount() == 0){
Toast.makeText(MainActivity.this,"还没有数据",Toast.LENGTH_LONG).show();
}
有时候出现这种情况,那么要去了解status为201是什么意思。今天就算了,都凌晨了。
{“message”:”快递公司参数异常:单号不存在或者已经过期”,”nu”:”“,”ischeck”:”0”,”condition”:”“,”com”:”“,”status”:”201”,”state”:”0”,”data”:[]}
其他的查询快递的APP都是直接输快递单号的,为啥这个不行,因为我在网上找不到快递公司单号的规则啊,就是怎么通过快递单号码来知道它是哪家公司的,这个不像身份证一样那么有规律。
https://www.kuaidi100.com/openapi/api_post.shtml
http://blog.sina.com.cn/s/blog_7256fe8f0101ddmd.html
http://blog.csdn.net/badboy007/article/details/19034609
http://www.cnblogs.com/johnsonwei/p/5785055.html
http://www.jb51.net/article/46652.htm
http://blog.csdn.net/jdsjlzx/article/details/25063169
http://www.tuicool.com/articles/3uUZbmu
http://www.jb51.net/article/46652.htm
http://blog.csdn.net/furongkang/article/details/6819247
http://blog.csdn.net/shakespeare001/article/details/7926783
http://blog.csdn.net/onlyonecoder/article/details/8490924
http://gqdy365.iteye.com/blog/2112471
http://www.cnblogs.com/lao-liang/p/5108745.html
http://blog.csdn.net/abc5382334/article/details/13503475/
https://zhuanlan.zhihu.com/p/21320392?refer=passer
感谢以上文章的作者,给了我做出第一款APP的资源。
时间已经到了00:43,我还是睡不着。
代码写的烂,需要改进的地方很多。
基础不扎实,还得好好搞搞java。
需要做的事很多,再也没有接口说不会了,说很难了。因为你可以做到的。
一个曾经写过程序又没写了,现在又写了的菜鸟程序员实在是有点啰嗦。
程序的源码我整理一下再上传,方便大家参考,我怕自己没写清楚。
地址(设置了1分的鼓励分):http://download.csdn.net/detail/a1b2c300/9724067