網絡篇筆記鏈接:
一、HttpURLConnection
二、Volley框架 + 使用Gson解析json數據
三、OkHttp3框架 + 使用Gson解析json數據
四、WebView組件
五、Android 9.0以上不能訪問網絡問題解決方法
===============================================================
學習使用Volley框架
文章內容有點多,可以點擊此處到導航鏈接
提示:Android 9.0 版本之後的網絡訪問有問題的請看我的另一篇文章。
五、Android 9.0以上不能訪問網絡問題解決方法
1.佔用儲存空間小
使用Volley 需要Volley.jar(120k),加上自己的封裝最多140k。
2.功能介紹
Volley是Goole在2013年Google I/O大會上推出了一個新的網絡通信框架,它是開源的。Volley 的特點:特別適合數據量小,通信頻繁的網絡操作。
3.優點
非常適合進行數據量不大,但通信頻繁的網絡操作。
內部分裝了異步線程。
支持get,post網絡請求。
圖片下載。
可直接在主線程調用服務端並處理返回結果。
可以取消請求,容易擴展,面向接口編程。
4.缺點
對大文件下載 Volley的表現非常糟糕。
在BasicNetwork中判斷了statusCode(statusCode < 200 || statusCode > 299),如果符合條件直
接圖片加載,性能一般。
使用的是httpclient,HttpURLConnection。不過在android 6.0不支持httpclient了,如果想支持得添加org.apache.http.legacy.jar
一、GET請求
使用Volley框架之前需要加入gradle依賴
// https://mvnrepository.com/artifact/com.android.volley/volley
implementation group: 'com.android.volley', name: 'volley', version: '1.1.1'
// https://mvnrepository.com/artifact/com.google.code.gson/gson
implementation group: 'com.google.code.gson', name: 'gson', version: '2.8.5'
使用步驟:
1、創建網絡請求隊列
//1.創建網絡請求隊列
RequestQueue requestQueue = Volley.newRequestQueue(this);
2、創建請求對象,Volley的請求對象有StringRequest,JsonRequest,JsonArrayRequest,JsonObjectRequest
這裏以StringRequest爲例
//2、創建請求對象,這裏以StringRequest爲例
StringRequest stringRequest = new StringRequest(
url, //參數1:請求的url
new Response.Listener<String>() {//參數2:請求成功的監聽事件
@Override
public void onResponse(String response) {
//todo
}
},
new Response.ErrorListener() {//參數3:請求失敗的監聽事件
@Override
public void onErrorResponse(VolleyError error) {
//todo
}
}
);
3、將請求加入隊列
//3、將請求加入隊列
requestQueue.add(stringRequest);
二、使用Gson解析json
使用Gson解析json數據,這個比較簡單,以下是使用步驟(3步,其實前2步就算拿到數據了)
1、創建Gson對象
Gson gson = new Gson();
2、調用Gson的fromJson()方法,將json轉成javaBean,將要顯示的數據封裝到這個javaBean
Weather weather = gson.fromJson(result, Weather.class);
fromJson(參數1,參數2)
-
參數1:需要解析的json
-
參數2:一個javaBean,接收需要封裝的數據(總數據的javaBean)
3、將數據顯示到組件中
tvCity.setText(weather.getData().getCity()); //城市
====================================
實例:獲取天氣數據(GET請求)
請求地址:https://www.apiopen.top/weatherApi?city=廣州
代碼:
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".WeatherActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="20dp"
android:background="#03A9F4"
android:orientation="vertical"
android:padding="20dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:paddingBottom="20dp">
<TextView
android:id="@+id/tv_city"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="城市"
android:textColor="#fff"
android:textSize="40sp" />
<TextView
android:id="@+id/tv_low"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="最低溫度"
android:textColor="#fff" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text=" - " />
<TextView
android:id="@+id/tv_high"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="最高溫度"
android:textColor="#fff" />
<TextView
android:id="@+id/tv_date"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:text="date"
android:textColor="#fff" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:paddingTop="20dp">
<TextView
android:id="@+id/tv_wendu"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="25"
android:textColor="#fff"
android:textSize="40sp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="2"
android:text="度"
android:textColor="#fff"
android:textSize="40sp" />
<TextView
android:id="@+id/tv_type"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="天氣類型"
android:textColor="#fff"
android:textSize="40sp" />
</LinearLayout>
</LinearLayout>
<Button
android:id="@+id/button"
android:background="#4CAF50"
android:textColor="#fff"
android:textSize="20sp"
android:layout_margin="20dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="加載數據"/>
<EditText
android:id="@+id/editText"
android:layout_margin="20dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ems="10"
android:lines="10"
android:gravity="start|top"
android:background="#2D03A9F4"
android:hint="請求的原始json數據"
android:inputType="textMultiLine" />
</LinearLayout>
下面這個javaBean我是使用Android Studio的GsonFormat插件生成的
將原始的json數據放到插件中,即可生成javaBean
Weather.java
package com.t.testvolley.bean;
import java.util.List;
public class Weather {
/**
* code : 200
* msg : 成功!
* data : {"yesterday":{"date":"29日星期四","high":"高溫 34℃","fx":"無持續風向","low":"低溫 27℃","fl":"<![CDATA[<3級]]>","type":"雷陣雨"},"city":"廣州","aqi":null,"forecast":[{"date":"30日星期五","high":"高溫 31℃","fengli":"<![CDATA[<3級]]>","low":"低溫 26℃","fengxiang":"無持續風向","type":"中雨"},{"date":"31日星期六","high":"高溫 31℃","fengli":"<![CDATA[<3級]]>","low":"低溫 25℃","fengxiang":"無持續風向","type":"中雨"},{"date":"1日星期天","high":"高溫 30℃","fengli":"<![CDATA[<3級]]>","low":"低溫 25℃","fengxiang":"無持續風向","type":"雷陣雨"},{"date":"2日星期一","high":"高溫 30℃","fengli":"<![CDATA[<3級]]>","low":"低溫 25℃","fengxiang":"無持續風向","type":"中雨"},{"date":"3日星期二","high":"高溫 31℃","fengli":"<![CDATA[<3級]]>","low":"低溫 25℃","fengxiang":"無持續風向","type":"雷陣雨"}],"ganmao":"各項氣象條件適宜,發生感冒機率較低。但請避免長期處於空調房間中,以防感冒。","wendu":"29"}
*/
private int code;
private String msg;
private DataBean data;
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public DataBean getData() {
return data;
}
public void setData(DataBean data) {
this.data = data;
}
public static class DataBean {
/**
* yesterday : {"date":"29日星期四","high":"高溫 34℃","fx":"無持續風向","low":"低溫 27℃","fl":"<![CDATA[<3級]]>","type":"雷陣雨"}
* city : 廣州
* aqi : null
* forecast : [{"date":"30日星期五","high":"高溫 31℃","fengli":"<![CDATA[<3級]]>","low":"低溫 26℃","fengxiang":"無持續風向","type":"中雨"},{"date":"31日星期六","high":"高溫 31℃","fengli":"<![CDATA[<3級]]>","low":"低溫 25℃","fengxiang":"無持續風向","type":"中雨"},{"date":"1日星期天","high":"高溫 30℃","fengli":"<![CDATA[<3級]]>","low":"低溫 25℃","fengxiang":"無持續風向","type":"雷陣雨"},{"date":"2日星期一","high":"高溫 30℃","fengli":"<![CDATA[<3級]]>","low":"低溫 25℃","fengxiang":"無持續風向","type":"中雨"},{"date":"3日星期二","high":"高溫 31℃","fengli":"<![CDATA[<3級]]>","low":"低溫 25℃","fengxiang":"無持續風向","type":"雷陣雨"}]
* ganmao : 各項氣象條件適宜,發生感冒機率較低。但請避免長期處於空調房間中,以防感冒。
* wendu : 29
*/
private YesterdayBean yesterday;
private String city;
private Object aqi;
private String ganmao;
private String wendu;
private List<ForecastBean> forecast;
public YesterdayBean getYesterday() {
return yesterday;
}
public void setYesterday(YesterdayBean yesterday) {
this.yesterday = yesterday;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
public Object getAqi() {
return aqi;
}
public void setAqi(Object aqi) {
this.aqi = aqi;
}
public String getGanmao() {
return ganmao;
}
public void setGanmao(String ganmao) {
this.ganmao = ganmao;
}
public String getWendu() {
return wendu;
}
public void setWendu(String wendu) {
this.wendu = wendu;
}
public List<ForecastBean> getForecast() {
return forecast;
}
public void setForecast(List<ForecastBean> forecast) {
this.forecast = forecast;
}
public static class YesterdayBean {
/**
* date : 29日星期四
* high : 高溫 34℃
* fx : 無持續風向
* low : 低溫 27℃
* fl : <![CDATA[<3級]]>
* type : 雷陣雨
*/
private String date;
private String high;
private String fx;
private String low;
private String fl;
private String type;
public String getDate() {
return date;
}
public void setDate(String date) {
this.date = date;
}
public String getHigh() {
return high;
}
public void setHigh(String high) {
this.high = high;
}
public String getFx() {
return fx;
}
public void setFx(String fx) {
this.fx = fx;
}
public String getLow() {
return low;
}
public void setLow(String low) {
this.low = low;
}
public String getFl() {
return fl;
}
public void setFl(String fl) {
this.fl = fl;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
}
public static class ForecastBean {
/**
* date : 30日星期五
* high : 高溫 31℃
* fengli : <![CDATA[<3級]]>
* low : 低溫 26℃
* fengxiang : 無持續風向
* type : 中雨
*/
private String date;
private String high;
private String fengli;
private String low;
private String fengxiang;
private String type;
public String getDate() {
return date;
}
public void setDate(String date) {
this.date = date;
}
public String getHigh() {
return high;
}
public void setHigh(String high) {
this.high = high;
}
public String getFengli() {
return fengli;
}
public void setFengli(String fengli) {
this.fengli = fengli;
}
public String getLow() {
return low;
}
public void setLow(String low) {
this.low = low;
}
public String getFengxiang() {
return fengxiang;
}
public void setFengxiang(String fengxiang) {
this.fengxiang = fengxiang;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
}
}
}
Weather.java這個javaBean是對應原始json結構一一對應生成的數據
可藉助json解析格式化工具格式化json數據進行觀察,與javaBean作比較
MainActivity.java
package com.t.testvolley;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
import com.android.volley.RequestQueue;
import com.android.volley.Response;
import com.android.volley.VolleyError;
import com.android.volley.toolbox.StringRequest;
import com.android.volley.toolbox.Volley;
import com.google.gson.Gson;
import com.t.testvolley.bean.Weather;
public class MainActivity extends AppCompatActivity {
private TextView tvCity;
private TextView tvLow;
private TextView tvHigh;
private TextView tvDate;
private TextView tvWendu;
private TextView tvType;
private Button button;
private EditText editText;
//保存請求url得到的結果
String result = "";
//請求的url
String url = "https://www.apiopen.top/weatherApi?city=廣州";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//初始化
initUI();
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//使用Volley請求數據
useVolley(url);
}
});
}
private void initUI() {
editText = (EditText) findViewById(R.id.editText);
tvCity = (TextView) findViewById(R.id.tv_city);
tvLow = (TextView) findViewById(R.id.tv_low);
tvHigh = (TextView) findViewById(R.id.tv_high);
tvDate = (TextView) findViewById(R.id.tv_date);
tvWendu = (TextView) findViewById(R.id.tv_wendu);
tvType = (TextView) findViewById(R.id.tv_type);
button = (Button) findViewById(R.id.button);
}
private void useVolley(String url) {
RequestQueue requestQueue = Volley.newRequestQueue(this);
final StringRequest stringRequest = new StringRequest(
//參數1:請求的url
url,
//參數2:請求成功的監聽事件
new com.android.volley.Response.Listener<String>() {
@Override
public void onResponse(String response) {
result = response;
//將請求的原始json數據放到EditText中
editText.setText(result);
//使用Gson解析json數據
parseJsonByGson(result);
}
},
//參數3:請求失敗的監聽事件
new com.android.volley.Response.ErrorListener(){
@Override
public void onErrorResponse(VolleyError error) {
Toast.makeText(MainActivity.this, "加載失敗", Toast.LENGTH_SHORT).show();
}
});
//3、將請求添加到隊列
requestQueue.add(stringRequest);
}
/**
* 使用Gson解析json數據,這個比較簡單,以下是使用步驟(3步,其實前2步就算拿到數據了)
* @param json 要解析的json
*/
public void parseJsonByGson(String json){
//1、創建Gson對象
Gson gson = new Gson();
//2、調用Gson的fromJson()方法,將json轉成javaBean,將要顯示的數據封裝到這個javaBean
//fromJson(參數1,參數2)方法 參數1:需要解析的json 參數2:一個javaBean,接收需要封裝的數據(總數據的javaBean)
Weather weather = gson.fromJson(result, Weather.class);
//3、將數據顯示到TextView中
tvCity.setText(weather.getData().getCity()); //城市
tvDate.setText(weather.getData().getForecast().get(0).getDate()); //日期
tvHigh.setText(weather.getData().getForecast().get(0).getHigh()); //最高溫度
tvLow.setText(weather.getData().getForecast().get(0).getLow()); //最低溫度
tvType.setText(weather.getData().getForecast().get(0).getType()); //天氣類型
tvWendu.setText(weather.getData().getWendu());//當前溫度
}
}
完工。
==================================================
三、POST請求
POST請求與get請求差不多,區別就在與請求參數的處理,volley的post請求參數要重寫getParams()方法來傳參數
與get請求的不同之處:參數多了一個,並且請求地址變爲https://www.apiopen.top/weatherApi?
new StringRequest(參數1,參數2,參數3,參數4){
//方法體裏重寫getParams()
}
參數1:請求方法
參數2:請求的url
參數3:請求成功的監聽事件
參數4:請求失敗的監聽事件
private void useVolleyPost(String url) {
RequestQueue requestQueue = Volley.newRequestQueue(this);
final StringRequest stringRequest = new StringRequest(
//參數1:請求方法
Request.Method.POST,
//參數2:請求的url
url,
//參數3:請求成功的監聽事件
new com.android.volley.Response.Listener<String>() {
@Override
public void onResponse(String response) {
result = response;
//將請求的原始json數據放到EditText中
editText.setText(result);
//使用Gson解析json數據
parseJsonByGson(result);
}
},
//參數4:請求失敗的監聽事件
new com.android.volley.Response.ErrorListener(){
@Override
public void onErrorResponse(VolleyError error) {
Toast.makeText(Main2Activity.this, "加載失敗", Toast.LENGTH_SHORT).show();
}
}){//StringRequest方法體的左大括號
//StringRequest方法體中重寫getParams()方法
//設置請求參數的方法
@Override
protected Map<String, String> getParams() throws AuthFailureError {
//設置請求參數信息
Map<String, String> map = new HashMap<>();
map.put("city","廣州");
return map;
}
};//StringRequest方法體的右大括號
//3、將請求添加到隊列
requestQueue.add(stringRequest);
}
===========================================
實例:獲取天氣數據(POST請求)
該實例使用上面get請求的代碼修改過了,請注意兩個代碼的不同之處
佈局文件與前面的一模一樣,直接複製過來
activity_main2.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".WeatherActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="20dp"
android:background="#03A9F4"
android:orientation="vertical"
android:padding="20dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:paddingBottom="20dp">
<TextView
android:id="@+id/tv_city"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="城市"
android:textColor="#fff"
android:textSize="40sp" />
<TextView
android:id="@+id/tv_low"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="最低溫度"
android:textColor="#fff" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text=" - " />
<TextView
android:id="@+id/tv_high"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="最高溫度"
android:textColor="#fff" />
<TextView
android:id="@+id/tv_date"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:text="date"
android:textColor="#fff" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:paddingTop="20dp">
<TextView
android:id="@+id/tv_wendu"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="25"
android:textColor="#fff"
android:textSize="40sp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="2"
android:text="度"
android:textColor="#fff"
android:textSize="40sp" />
<TextView
android:id="@+id/tv_type"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="天氣類型"
android:textColor="#fff"
android:textSize="40sp" />
</LinearLayout>
</LinearLayout>
<Button
android:id="@+id/button"
android:background="#4CAF50"
android:textColor="#fff"
android:textSize="20sp"
android:layout_margin="20dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="加載數據"/>
<EditText
android:id="@+id/editText"
android:layout_margin="20dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ems="10"
android:lines="10"
android:gravity="start|top"
android:background="#2D03A9F4"
android:hint="請求的原始json數據"
android:inputType="textMultiLine" />
</LinearLayout>
Main2Activity.java
package com.t.testvolley;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
import com.android.volley.AuthFailureError;
import com.android.volley.Request;
import com.android.volley.RequestQueue;
import com.android.volley.VolleyError;
import com.android.volley.toolbox.JsonArrayRequest;
import com.android.volley.toolbox.JsonObjectRequest;
import com.android.volley.toolbox.JsonRequest;
import com.android.volley.toolbox.StringRequest;
import com.android.volley.toolbox.Volley;
import com.google.gson.Gson;
import com.t.testvolley.bean.Weather;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
public class Main2Activity extends AppCompatActivity {
private TextView tvCity;
private TextView tvLow;
private TextView tvHigh;
private TextView tvDate;
private TextView tvWendu;
private TextView tvType;
private Button button;
private EditText editText;
//保存請求url得到的結果
String result = "";
//請求的url
String url = "https://www.apiopen.top/weatherApi?";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
//初始化
initUI();
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//使用Volley請求數據
useVolleyPost(url);
}
});
}
private void initUI() {
editText = (EditText) findViewById(R.id.editText);
tvCity = (TextView) findViewById(R.id.tv_city);
tvLow = (TextView) findViewById(R.id.tv_low);
tvHigh = (TextView) findViewById(R.id.tv_high);
tvDate = (TextView) findViewById(R.id.tv_date);
tvWendu = (TextView) findViewById(R.id.tv_wendu);
tvType = (TextView) findViewById(R.id.tv_type);
button = (Button) findViewById(R.id.button);
}
private void useVolleyPost(String url) {
RequestQueue requestQueue = Volley.newRequestQueue(this);
final StringRequest stringRequest = new StringRequest(
//參數1:請求方法
Request.Method.POST,
//參數2:請求的url
url,
//參數3:請求成功的監聽事件
new com.android.volley.Response.Listener<String>() {
@Override
public void onResponse(String response) {
result = response;
//將請求的原始json數據放到EditText中
editText.setText(result);
//使用Gson解析json數據
parseJsonByGson(result);
}
},
//參數4:請求失敗的監聽事件
new com.android.volley.Response.ErrorListener(){
@Override
public void onErrorResponse(VolleyError error) {
Toast.makeText(Main2Activity.this, "加載失敗", Toast.LENGTH_SHORT).show();
}
}){//StringRequest方法體的左大括號
//StringRequest方法體中重寫getParams()方法
//設置請求參數的方法
@Override
protected Map<String, String> getParams() throws AuthFailureError {
//設置請求參數信息
Map<String, String> map = new HashMap<>();
map.put("city","廣州");
return map;
}
};//StringRequest方法體的右大括號
//3、將請求添加到隊列
requestQueue.add(stringRequest);
}
/**
* 使用Gson解析json數據,這個比較簡單,以下是使用步驟(3步,其實前2步就算拿到數據了)
* @param json 要解析的json
*/
public void parseJsonByGson(String json){
//1、創建Gson對象
Gson gson = new Gson();
//2、調用Gson的fromJson()方法,將json轉成javaBean,將要顯示的數據封裝到這個javaBean
//fromJson(參數1,參數2)方法 參數1:需要解析的json 參數2:一個javaBean,接收需要封裝的數據(總數據的javaBean)
Weather weather = gson.fromJson(result, Weather.class);
//3、將數據顯示到TextView中
tvCity.setText(weather.getData().getCity()); //城市
tvDate.setText(weather.getData().getForecast().get(0).getDate()); //日期
tvHigh.setText(weather.getData().getForecast().get(0).getHigh()); //最高溫度
tvLow.setText(weather.getData().getForecast().get(0).getLow()); //最低溫度
tvType.setText(weather.getData().getForecast().get(0).getType()); //天氣類型
tvWendu.setText(weather.getData().getWendu());//當前溫度
}
}