网络连接获取并解析数据
网络连接获取数据——OKHTTP3(仿12306软件)
仿12306软件使用OKHTTP3网络连接获取数据部分。
前期准备
OkHttp官网地址:http://square.github.io/okhttp/
OkHttp GitHub地址:https://github.com/square/okhttp
在线JSON解析地址:https://www.json.cn/
导入OKHTTP3依赖
compile 'com.squareup.okhttp3:okhttp:3.4.1'
申请网络访问权限
<uses-permission android:name="android.permission.INTERNET"/>
登陆部分
API文档分析
POST请求,需要两个参数,分别是用户名和密码
服务器端默认的用户名/密码:dong/dong
okhttp同步请求
需要手动启动一个线程,因为线程之间的运行是同步的所以需要用handle来进行线程之间通信。
不管是同步还是异步请求都有四个关键的步骤:
- 创建OkhttpClient 对象
- 创建请求的Request 对象
- 在Okhttp中创建Call 对象,将request和Client进行绑定
- 执行Call对象(call 是interface 实际执行的是RealCall)中的execute()或enqueue()方法
同步和异步请求唯一区别是,最后调用的Call对象的方法不同, 同步调用是execute()方法,而异步调用的是enqueue()。
//创建OkhttpClient 对象
final OkHttpClient client = new OkHttpClient();
// 网络访问
private void postRequest() {
//构造请求正文
RequestBody formBody = new FormBody.Builder()
.add("username",user.getText().toString())
//密码需要通过MD5加密
.add("password",md5Utils.MD5(password.getText().toString()))
.build();
//构造Request(请求)
//每一个HTTP请求中都应该包含一个URL,一个GET或POST方法以及Header或其他参数,当然还可以含特定内容类型的数据流。
request = new Request.Builder()
.url(url+"/My12306/Login")
.post(formBody)
.build();
new Thread(new Runnable() {
@Override
public void run() {
Message msg = handler.obtainMessage();
//Responses(响应)
Response response = null;
try {
//在Okhttp中创建Call 对象,将request和Client进行绑定,并用 execute()启动
response = client.newCall(request).execute();
//判断响应是否成功
if (response.isSuccessful()){
//获得响应体
String result = response.body().string();
//解析获得的响应内容(xml)
parseXMLWithPull(result);
//把解析完成后的值通过Message发送给Handle
msg.obj = value;
msg.what = 1;
msg.arg1 = Integer.parseInt(flag);
}else {
throw new IOException("Unexpected code" + response);
}
}catch (Exception e){
e.printStackTrace();
msg.what = 2;
}
handler.sendMessage(msg);
}
}).start();
}
解析数据(XML)
// 解析XML
private String parseXMLWithPull(String result) {
try {
//获取解析器
XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
XmlPullParser parser = factory.newPullParser();
parser.setInput(new StringReader(result));
//获取产生事件类型
int eventType = parser.getEventType();
//开始解析
while (eventType != XmlPullParser.END_DOCUMENT) {
String nodeName = parser.getName();
switch (eventType){
case XmlPullParser.START_DOCUMENT:
// 初始化
flag = "0";
Log.i("---flag",flag);
break;
case XmlPullParser.START_TAG:
//按照节点名字查找,获取需要的数据
if ("result".equals(nodeName)){
flag = parser.nextText();
}
break;
case XmlPullParser.END_TAG://完成解析
if ("data".equals(nodeName)) {
Log.i("---result", "result : " + flag);
}
break;
default:
break;
}
eventType=parser.next();
}
} catch (XmlPullParserException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return flag;
}
使用handle对UI线程进行修改
Handler handler = new Handler(){
public void handleMessage(android.os.Message msg){
switch (msg.what){
case 1:
int result = msg.arg1;
if (0 == result){
user.selectAll();
user.setError("账号或者密码错误");
password.setError("账号或者密码错误");
user.requestFocus();
}else if (1 == result){
Intent intent = new Intent();
intent.setClass(LoginActivity.this,HomeActivity.class);
startActivity(intent);
}
break;
case 2:
Toast.makeText(LoginActivity.this, "服务器错误,请重试",
Toast.LENGTH_SHORT).show();
break;
}
}
};
获取cookie并保存
使用cookieJar()自动管理cookie
final OkHttpClient client = new OkHttpClient.Builder().cookieJar(new CookieJar() {
@Override
public void saveFromResponse(HttpUrl url, List<Cookie> cookies) {
cookieStore.put(url.host(),cookies);
}
@Override
public List<Cookie> loadForRequest(HttpUrl url) {
List<Cookie> cookies = cookieStore.get(url.host());
return cookies != null ? cookies : new ArrayList<Cookie>();
}
}).build();
从Response中获取Cookie
//从登录成功后的Response中获取所有的Cookie
Headers loginHeaders = response.headers();
HttpUrl loginUrl = request.url();
List<Cookie> cookies1 = Cookie.parseAll(loginUrl,loginHeaders);
if(cookies1!=null){
//将登录成功的Url对应的所有的Cookie通过Cookiejar的方法保存到cookieStore中去,方便我们下次根据登录成功的url来获取对应的cookie
client.cookieJar().saveFromResponse(loginUrl,cookies1);
}
记录JSESSIONID,并保存到本地
// 记录JSESSIONID
String value = "";
List<Cookie> cookies = client.cookieJar().loadForRequest(loginUrl);
for(Cookie cookie : cookies){
if ("JSESSIONID".equals(cookie.name())){
value = cookie.value();
Log.i("--va",value);
}
}
msg.obj = value;
String jsessionid = (String) msg.obj;
SharedPreferences sharedPreferences = getSharedPreferences("user", Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sharedPreferences.edit();
editor.putString("JSESSIONID",jsessionid);
editor.commit();
我的账号部分
API文档
POST请求但是需要添加请求头,需要获得登录时的cookie。
okhttp异步请求
不需要手动新建一个线程,更简单
private void getInfo(final String action) {
SharedPreferences sharedPreferences = getSharedPreferences("user", MODE_PRIVATE);
String value = sharedPreferences.getString("JSESSIONID", "");
RequestBody formBody = new FormBody.Builder()
.add("action", action)
.add("tel", "13812345678")
.add("type", "成人")
.build();
final Request request = new Request.Builder()
.header("cookie", "JSESSIONID=" + value)
.post(formBody)
.url("http://100.0.101.13:8080/My12306/otn/Account")
.build();
//同步和异步请求唯一区别是,最后调用的Call对象的方法不同, 同步调用是execute()方法,而异步调用的是enqueue()
Call call = client.newCall(request);
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
System.out.println(e.getMessage());
}
@Override
public void onResponse(Call call, Response response) throws IOException {
if (response.isSuccessful()) {
String result = response.body().string();
if ("请重新登陆!".equals(result)){
Toast.makeText(PersonalActivity.this,"请重新登陆!",Toast.LENGTH_LONG);
}else {
parseJSON(result,action);
}
}
}
});
}
解析数据(JSON)
private void parseJSON(String result,String action){
try {
JSONObject jsonObject = new JSONObject(result);
if ("query".equals(action)){
username.setText(jsonObject.getString("username"));
id.setText(jsonObject.getString("id"));
name.setText(jsonObject.getString("name"));
idType.setText(jsonObject.getString("idType"));
Tel.setText(jsonObject.getString("tel"));
Type.setText(jsonObject.getString("type"));
}else {
EditText name_edit = (EditText)personalDialog.findViewById(R.id.username_dialog);
name_edit.setText(jsonObject.getString("username"));
EditText tel_edit = (EditText)personalDialog.findViewById(R.id.tel_dialog);
tel_edit.setText(jsonObject.getString("tel"));
}
}catch (JSONException e){
e.printStackTrace();
}
}
遇见的坑
- 如果用同步请求一定要handler来接收消息
- 不记得了,等我想起吧