前言:
众所周知,一说到网络请求,在大家心中无非就是现在目前最流行的okhttp,volley等等,确实如此!这两个网络请求框架在目前安卓开发当中确实是很流行的,但是在这两个比较流行的网络框架没有出现之前,大家是否还记得有HttpUrlConnection和HttpClient这两个经典的网络请求。虽然Google貌似在6.0版本里面删除了HttpClient相关API,对于这个行为不做评价!既然HttpClient已经废弃了,我们也就不推荐再继续使用了。那么今天主要将跟大家一起学习HttpUrlConnection网络请求与json数据解析的使用。
为了更好的学习HttpUrlConnection,给大家先看看一下HttpUrlConnection响应流程图。
一、HttpUrlConnection网络请求的基本用法
在这里我为了方便使用,所以创建了命名为NetUtils的工具类。主要是用来网络请求的一个封装好的工具类,具体代码如下:
package com.amandu.http;
import android.accounts.NetworkErrorException;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
/**
* HttpURLConnection_Utils
* Created by Administrator on 2017/9/26.
*/
public class NetUtils {
/**
* post请求
* @param url
* @return
*/
public static String get(String url) {
HttpURLConnection conn = null;
try {
//创建Url并且通过HttpURLConnection打开连接
URL mURL=new URL(url);
conn= (HttpURLConnection) mURL.openConnection();
conn.setRequestMethod("POST");// 设置请求方法为post
conn.setReadTimeout(5000);// 设置读取超时为5秒
conn.setConnectTimeout(10000);// 设置连接网络超时为10秒
//如果连接成功
int responseCode=conn.getResponseCode();
if(responseCode==200){
//获取数据
InputStream is=conn.getInputStream();
String response=getStringFromInputStream(is);
return response;
}else{
//如果连接失败
throw new NetworkErrorException("response status is "+responseCode);
}
} catch (Exception e) {
e.printStackTrace();
}finally {
//最终执行语句,关闭连接
if(conn!=null){
conn.disconnect();
}
}
return null;
}
private static String getStringFromInputStream(InputStream is) throws IOException{
ByteArrayOutputStream os=new ByteArrayOutputStream();
byte[] buffer=new byte[1024];
int len=-1;
while((len=is.read(buffer))!=-1){
os.write(buffer, 0, len);
}
is.close();
String state=os.toString(); //把字节流转字符串
os.close();
return state;
}
}
代码文中已经做注释了。大家如果觉得有什么问题欢迎在下面评论中提出!
由于这是网络请求,所以我们在清单文件中注意添加网络权限!
<uses-permission android:name="android.permission.INTERNET"></uses-permission>
现在HttpUrlConnection网络请求工具写好了,权限也添加好了,那么下面我们就要开始请求网络数据了,大家都知道我们请求网络数据之后,想要把请求到的数据更新在ui上面,如果我们在主线程直接数据,这时候就会出现卡死状态,因为网络请求处于耗时操作,为了避免这种卡死状态,我们采用异步的方式去处理,而所谓的异步操作就是我们在子线程进行耗时操作,完成后通过Handler将更新UI的操作发送到主线程执行。这就叫异步。同样,为了方便使用,在这里,我创建了命名为AsynNetUtils异步回调封装类,用于来异步操作的处理。代码如下:
package com.amandu.http;
import android.os.Handler;
/**
* 异步回调Utils类
* Created by Administrator on 2017/9/26.
*/
public class AsynNetUtils {
/**
* 实现回调接口
*/
public interface Callback{
void onResponse(String response);
}
/**
*
* @param url
* @param callback
*/
public static void get(final String url,final Callback callback){
final Handler handler=new Handler();
new Thread(new Runnable() {
@Override
public void run() {
//通过NetUtils获取url数据
final String response=NetUtils.get(url);
handler.post(new Runnable() {
@Override
public void run() {
callback.onResponse(response);
}
});
}
}).start();
}
}
在这里,我们创建了一个名为Callback接口,用于回调请求后的url返回的数据。
现在一个HttpUriConnection网络请求方案终于成型了,那么下面我们创建一个命名为MainActivity来看看是如何使用,代码如下:
package com.amandu.httptext;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import com.amandu.http.AsynNetUtils;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
public class MainActivity extends AppCompatActivity implements View.OnClickListener{
private Button bt_httpurlconnection;
private TextView http_text;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
}
private void initView() {
bt_httpurlconnection= (Button) findViewById(R.id.bt_httpurlconnection);
http_text= (TextView) findViewById(R.id.http_text);
bt_httpurlconnection.setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()){
case R.id.bt_httpurlconnection:
AsynNetUtils.get("http://www.baidu.com", new AsynNetUtils.Callback() {
@Override
public void onResponse(String response) {
http_text.setText(response);
}
});
break;
}
}
}
在这里,我们使用了AsynNetUtils.get方法获得一个url为:http:www.baidu.com的链接实现网络去请求访问,然后通过onResponse方法获得一个回调数据并且显示在TextView控件上面,整体来说还是很简单的!
现在看起来确实优雅多了,如果之前我们不创建封装好的AsynNetUtils异步回调类的话,那么在MainActivity这边就会显得比不优雅...特别是当网络请求数据多的时候,如果我们在Activity当中每次请求都那样做的话,是显示比较繁琐的,所以在这里,我推荐了使用封装...
好了之后,我们把项目运行起来,效果图如下:
没错,就是把网络请求中的url设置为百度链接,访问他们的网页罢了。只这是一个例子,为了方便而已。所以暂时这样做,但是在日常开发中,我们经常是去访问接口,取出json数据,然后显示在我们ui上面!没错,是的。在这里,大家可能会说,尼玛,今天不是要学习网络请求与json解析,怎么给我解析一个网页标签出来了,在这里大家不要着急,下面我们继续学习网络请求与json的解析...
二、Json数据解析的基本使用
1、Json的定义
JSON(JavaScript Object Notation, JS 对象标记) 是一种轻量级的数据交换格式。它基于 ECMAScript (w3c制定的js规范)的一个子集,采用完全独立于编程语言的文本格式来存储和表示数据。简洁和清晰的层次结构使得 JSON 成为理想的数据交换语言。 易于人阅读和编写,同时也易于机器解析和生成,并有效地提升网络传输效率。
2、Json Vs xml
- JSON和XML的数据可读性基本相同
- JSON和XML同样拥有丰富的解析手段
- JSON相对于XML来讲,数据的体积小
- JSON与JavaScript的交互更加方便
- JSON对数据的描述性比XML较差
- JSON的速度要远远快于XML
3、Json几个常见类
JSONObject:可以看作是一个json对象,这是系统中有关JSON定义的基本单元,其包含一对儿(Key/Value)数值。它对外部(External: 应用toString()方法输出的数值)调用的响应体现为一个标准的字符串(例如:{"JSON": "Hello, World"},最外被大括号包裹,其中的Key和Value被冒号":"分隔)。其对于内部(Internal)行为的操作格式略微,例如:初始化一个JSONObject实例,引用内部的put()方法添加数值:new JSONObject().put("JSON", "Hello, World!"),在Key和Value之间是以逗号","分隔。Value的类型包括:Boolean、JSONArray、JSONObject、Number、String或者默认值JSONObject.NULL object 。
JSONArray:它代表一组有序的数值。将其转换为String输出(toString)所表现的形式是用方括号包裹,数值以逗号”,”分隔(例如: [value1,value2,value3],大家可以亲自利用简短的代码更加直观的了解其格式)。这个类的内部同样具有查询行为, get()和opt()两种方法都可以通过index索引返回指定的数值,put()方法用来添加或者替换数值。同样这个类的value类型可以包括:Boolean、JSONArray、JSONObject、Number、String或者默认值JSONObject.NULL object。
JSONTokener:json解析类
JSONException:json中用到的异常
认识了json几个常见类之后,下面我们就开始动手了,在这里,我主要是通过一个接口返回json数据,然后把这个接口返回的数据去解析出来,接口数据如下:
{
"success": "Y",
"time": "2017-09-27 09:39:27",
"msg": "",
"content": [
{
"npd_id": "8688",
"spd_name": "性感时尚纯棉睡衣可爱女士家居服套装",
"nsale_money": 0,
"spic": "/upload/20170223/s201702230920521150.jpg",
"ntotal_price": "259.00"
},
{
"npd_id": "8561",
"spd_name": "汽车DJ七彩灯车载KTV灯车内氛围灯声控led装饰灯USB爆闪灯舞台灯",
"nsale_money": 0,
"spic": "/upload/20170215/s201702150932484114.jpg",
"ntotal_price": "39.00"
},
{
"npd_id": "8560",
"spd_name": "车载眼镜夹 汽车眼睛架 车内眼镜夹子眼镜盒票据夹汽车装饰用品",
"nsale_money": 0,
"spic": "/upload/20170215/s201702150931281797.jpg",
"ntotal_price": "19.80"
},
{
"npd_id": "8559",
"spd_name": "汽车鲨鱼腮仿真出风口侧风口引擎盖装饰进风口假风口车贴改装用品",
"nsale_money": 0,
"spic": "/upload/20170214/s201702140521515718.jpg",
"ntotal_price": "27.50"
},
{
"npd_id": "8558",
"spd_name": "摩丝娃娃汽车摆件车上车饰可爱摇头创意公仔车载车内饰装饰品用品",
"nsale_money": 0,
"spic": "/upload/20170214/s201702140521006382.jpg",
"ntotal_price": "8.00"
},
{
"npd_id": "8557",
"spd_name": "Haier/海尔 BCD-452WDPF对开门风冷冷藏冷冻电冰箱家用节能大容量",
"nsale_money": 0,
"spic": "/upload/20170214/s20170214033723859.jpg",
"ntotal_price": "2999.00"
},
{
"npd_id": "8556",
"spd_name": "Haier/海尔 BCD-185TMPQ双门直冷冷藏冷冻电冰箱一级能效家用节能",
"nsale_money": 0,
"spic": "/upload/20170214/s201702140335248159.jpg",
"ntotal_price": "1249.00"
},
{
"npd_id": "8555",
"spd_name": "Haier/海尔 BC/BD-145HDE顶开门卧式冷柜双温柜节能静音巡航迷你",
"nsale_money": 0,
"spic": "/upload/20170214/s20170214033412659.jpg",
"ntotal_price": "1560.00"
},
{
"npd_id": "8554",
"spd_name": "Haier/海尔 BCD-118TMPA双门直冷冷藏冷冻电冰箱节能家用省电小型",
"nsale_money": 0,
"spic": "/upload/20170214/s201702140333078018.jpg",
"ntotal_price": "936.00"
}
]
}
看到了这个接口之后,我们第一时间要做的就是看清楚数据结构是什么样的,然后下面我们才能更好的去解析出来。首先,最外层大括号{}就是一个json对象,也称JSONObject,接着success、msg、time也是一个json对象,最后content里面包含着一个数组,在这里称之为JSONArray,然后cantent数组里面又包含多个JsonObject对象,这样说大家如果觉得不能太理解的话,没关系,下面我们就写个例子,看看Android中是如何解析json数据的...
下面的主要通过parseJson类解析单个数据和parseJsonMulti累解析多个数据,这里先说明,单个数据我打算采用解析JsonObject对象,即是上面json数据中的success、time等等,多个数据我打算采用解析JsonArray数组对象,即是上面json数据中的content数组对象。具体代码如下:
package com.amandu.httptext;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import com.amandu.http.AsynNetUtils;
import com.amandu.url.Urls;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
public class MainActivity extends AppCompatActivity implements View.OnClickListener{
private Button bt_httpurlconnection;
private TextView http_text;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
}
private void initView() {
bt_httpurlconnection= (Button) findViewById(R.id.bt_httpurlconnection);
http_text= (TextView) findViewById(R.id.http_text);
bt_httpurlconnection.setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()){
case R.id.bt_httpurlconnection:
AsynNetUtils.get(Urls.url, new AsynNetUtils.Callback() {
@Override
public void onResponse(String response) {
parseJsonMulti(response); //解析JsonArray数组对象(多个)
}
});
break;
}
}
/**
* 解析JsonObject对象
* @param response
*/
private void parseJson(String response) {
try {
//通过JsonObject对象解析数据
JSONObject jsonObj=new JSONObject(response);
String state=jsonObj.getString("success");
String time=jsonObj.getString("time");
String msg=jsonObj.getString("msg");
http_text.setText("state="+state+"\ntime="+time+"\nmsg"+msg);
} catch (JSONException e) {
e.printStackTrace();
}
}
/**
* 解析JsonArray数组对象
* @param response
*/
public void parseJsonMulti(String response){
try {
//通过JSONArray数组对象解析json数据,并且指定该数组对象为"content"
JSONArray jsonObjs=new JSONObject(response).getJSONArray("content");
String s="";
for (int i = 0; i <jsonObjs.length() ; i++) {
//循环取出content数组里面每个数据,并且通过JSONObject对象把它们取出
JSONObject jsonObj=jsonObjs.getJSONObject(i);
String npd_id=jsonObj.getString("npd_id");
String spd_name=jsonObj.getString("spd_name");
int nsale_money=jsonObj.getInt("nsale_money");
String spic=jsonObj.getString("spic");
String ntotal_price=jsonObj.getString("ntotal_price");
s+="\n\nnpd_id="+npd_id+"\nspd_name="+spd_name+"\nnsale_money="+nsale_money+"\nspic="+spic+"\nntotal_price="+ntotal_price;
}
http_text.setText(s);
} catch (JSONException e) {
e.printStackTrace();
}
}
}
文中代码已经做好注释,在解析过程中,主要是先明白json格式分别是什么对象,有了这个逻辑以后,那么解析思路就变得非常清晰了,在这里值得跟大家说明的是,大家可能会觉得Urls.url是什么东西?这个是一个请求的url而已,只不过为了安全起见,我把他封装起来,实际上它就是一条服务器接口字符串。
这里我采用的是parseJsonMulti解析接口中数据对象,什么是数组对象,其实大家应该发现了,就是json数据中的名为:content。写好了之后,那么我们一起运行项目,看看效果图如下:
没错,在这里我们确实是把json中数组对象名为content内容解析出来了。
致此,有关HttpUrlConnection网络请求和Json数据解析的基本使用,今天讲解到这里,感谢大家认真看完,希望对大家在日常开发中有所帮助!