編輯:關於Android編程
對於JSON的定義以及數據格式,沒有什麼太多的難點,這裡為官網對JSON的定義。從官網描述中可以看出,JSON本身是JavaScript中對象的描述格式,後來得以推廣並逐漸取代xml。
相比 XML 的不同之處
沒有結束標簽(類似於鍵值對的形式) 更短(沒有結束標簽,當然短了) 讀寫的速度更快 能夠使用內建的 JavaScript eval() 方法進行解析 使用數組 不使用保留字Android
原生的解析實際上使用的JSON
的一個官方jar包。對於JSON
,不需要頁面展示,所以使用intellij idea
進行演示。
在使用之前我們需要下載org.json
的jar包。對於Android 開發環境不需要下載此jar包。因為Android SDK 中已經默認包含了該jar包。
json jar 下載地址
下載完之後導入即可。
下面看一下數據
{
"user":{
"name":"alex",
"age":"18",
"isMan":true
}
}
有一個user字段,其中包含了該user的一些基本屬性。那麼如何解析呢?
在解析時,有一個很關鍵的地方:如果是{}
包含,則為JSONObject
對象,如果為[]
則為JSONArray
對象。
看到上面的例子,我們看到整個數據為JSONObject
,其內部包含了一個user
字段,該字段的值也是一個JSONObject
對象。
public class OrgJSONTest {
public static String json = "{\"user\":{\"name\":\"alex\",\"age\":\"18\",\"isMan\":true}}";
public static void main(String[] args){
JSONObject obj = new JSONObject(json);//最外層的JSONObject對象
JSONObject user = obj.getJSONObject("user");//通過user字段獲取其所包含的JSONObject對象
String name = user.getString("name");//通過name字段獲取其所包含的字符串
System.out.println(name);
}
}
打印結果如下
alex
可以看到獲取到了相應的值。
在JSONObject
對象中封裝了getXXX()
等一系列方法。用以獲取字符串,整形等等一系列的值。
對於如上例子,完全解析user對象如下
String name = user.getString("name");//通過name字段獲取其所包含的字符串
String age = user.getString("age");
boolean isMan = user.getBoolean("isMan");
System.out.println("name:"+name+"\nage:"+age+"\nisMan:"+isMan);
結果如下
name:alex
age:18
isMan:true
這種通過getXXX
的方式,無疑會出現一些問題,我們開始一一嘗試。
對於上面的例子,我們可以看到age
字段雖然其對應的值是雙引號括起的字符串,但其實際上是一個整形,那麼我們是否能夠通過getInt
獲取整形呢。
int age = user.getInt("age");
age:18
當然是可以得,同時字符串類型可以轉化為布爾類型,整數類型,浮點型等等。但字符串的內容必須符合規范,否則會報異常。如果看其源碼可知,其內部實質是調用了對應對象的parseXXX()
方法進行轉化操作。
//getInt源碼
public int getInt(String key) throws JSONException {
Object object = this.get(key);
try {
//關鍵點,如果是數值類型,則調用intValue(),否則強轉成字符串之後調用parserInt方法()
return object instanceof Number?((Num,ber)object).intValue():Integer.parseInt((String)object);
} catch (Exception var4) {
throw new JSONException("JSONObject[" + quote(key) + "] is not an int.");
}
}
整形等轉字符串類型
按照如上的思維邏輯,直接getString("xxx")
就可以了。但事實正好相反,該方法,如果對應值不是雙引號括起的,則會拋出異常。
//getString 源碼
public String getString(String key) throws JSONException {
Object object = this.get(key);
//直接判斷是否是字符串類型,如果不是,則拋出異常
if(object instanceof String) {
return (String)object;
} else {
throw new JSONException("JSONObject[" + quote(key) + "] not a string.");
}
}
通過上面的例子,可以得知getXXX("")
方法是通過字段(鍵)獲取對應的值。那麼肯定存在一種情況,及沒有鍵的存在。
System.out.println(user.getString("sex"));
Exception in thread "main" org.json.JSONException: JSONObject["sex"] not found.
at org.json.JSONObject.get(JSONObject.java:471)
at org.json.JSONObject.getString(JSONObject.java:717)
at json.OrgJSONTest.main(OrgJSONTest.java:24)
果斷報異常。
那麼怎麼辦呢:使用optXXX()。後面會講。
該對象用以解析[]
的對象,及數組對象。用法類似,修改一下數據格式
{
"user":[
{
"name":"alex",
"age":"18",
"isMan":true
},
{
"name":"alex",
"age":"18",
"isMan":true
}
]
}
user對應的值不再是一個JSONObject
對象,而是一個JSONArray
對象(數組對象)。該數組對象中包含了多個JSONObject
。
JSONObject obj = new JSONObject(json);//最外層的JSONObject對象
JSONArray array = obj.getJSONArray("user");
for(int i = 0 ; i
alex
mahao
解析過程與
JSONObject
類似,多了一個遍歷JSONArray
的步驟,把JSONArray
當作JAVA中的數組對待使用。兩者使用方式幾乎一樣。
構造JSON 數據
對於POST請求,傳參數時一般都是傳入一個json數據。那麼如何構造json數據呢,使用字符串拼接可以,但很蛋疼。當然,
JSONObject
等提供了對應的方法。
使用如下:
//外層obj對象
JSONObject objWrite = new JSONObject();
//user對象
JSONObject userWrite = new JSONObject();
//寫入對應屬性
userWrite.put("name","alex");
userWrite.put("age","18");
userWrite.put("isMan",true);
//將user對象寫入到外層obj中
objWrite.put("user",userWrite);
System.out.println(objWrite);
{"user":{"name":"alex","isMan":true,"age":"18"}}
opt 替代 get
在上面使用中,我們通過
getXXX()
獲取相應值。但是,會發現其局限性很多,很容易就拋異常,需要我們try...catch
去捕獲。而optXXX()
對此進行了優化。
首先看一下他的用法,在看用法之前,我們回憶之前使用get時的兩個問題
其他類型轉字符串類型拋出異常 當需要的字段沒有時,拋出異常。
看一下opt針對如上問題的解決:
JSONObject obj = new JSONObject(json);//最外層的JSONObject對象
JSONObject user = obj.optJSONObject("user");
String name = user.optString("name");
//整形轉字符串
String age = user.optString("age");
boolean isMan = user.optBoolean("isMan");
//默認值,如果沒有該字段,則會返回默認值
String sex = user.optString("sex","男");
System.out.println("name:"+name+"\nage:"+age+"\nisMan:"+isMan+"\nsex:"+sex);
name:alex
age:18
isMan:true
sex:男
通過上面的例子,可以看出通過使用
optString()
可以將整形轉化為字符串。而對於sex
,因為該字段沒有,會為其付默認值。解決了拋出異常的問題。
深入進去,看一下他們的源碼。
optString()
// optString 默認調用了optString(key, "");
public String optString(String key) {
return this.optString(key, "");
}
//如果是null,返回默認值,否則調用toString方法返回
public String optString(String key, String defaultValue) {
Object object = this.opt(key);
return NULL.equals(object)?defaultValue:object.toString();
}
optBoolean
public boolean optBoolean(String key) {
return this.optBoolean(key, false);
}
//實質調用get方法,如果拋出異常,則賦默認值
public boolean optBoolean(String key, boolean defaultValue) {
try {
return this.getBoolean(key);
} catch (Exception var4) {
return defaultValue;
}
}
get()取值不正確會拋出異常,必須用try catch或者throw包起
opt()取值不正確則會試圖進行轉化或者輸出友好值,不會拋出異常
如上,介紹了
Android
原生的解析,但在實際開發中,為了提高效率,往往使用第三方解析類庫,而下面我們將進入到第三方類庫的使用。
GSON 解析
Gson解析是google 提供的快速json解析庫。其和原生的相比,最大的優點是可以按照
bean
類對數據進行解析。
因為其屬於第三方庫,所以我們需要導包,如果使用的是
AndroidStudio
,直接搜索gson
導入即可。
使用的是
eclipse
的話,則在該地址下載,將jar包加入到工程中。
Gson 解析單一實體類對象
還是上面的數據格式
{
"user": {
"name": "alex",
"age": "18",
"isMan": true
}
}
對於該數據,我們想要獲取的是
user
中的字段值,首先定義User
實體類,注意:該類名沒有要求,隨便命名。
public class User {
private String name;
private int age;
private boolean isMan;
private String sex;
}
有兩點需要注意:
類中成員變量名一定要和json數據中字段一一對應。 多添加了sex字段,測試當獲取的字段不存在時的情況。
//使用Gson解析實體類對象
//1, 獲取對應實體類對象的字符串,當前為user的值。
String userJson = new JSONObject(json).getJSONObject("user").toString();
//userJson = "{\"name\":\"alex\",\"age\":18,\"isMan\":true}";
//2 , 創建Gson 對象
Gson gson = new Gson();
// 3, fromJson 解析
User user = gson.fromJson(userJson, User.class);
System.out.println(user);
User{name='alex', age=18, isMan=true, sex='null'}
關鍵方法為
fromJson
,該方法第一個參數為需要解析的json
數據,第二個參數為需要解析成的目標對象的class。
因為該例子比較特殊,當前數據中
user
中的值不是最外層的json數據,他被包裹起來了,所以我們先把他剝開,獲取user
對應的值。
有時候,返回的數據中字段值和我們前端的命名習慣不同,導致字段無法一一對應。如果我們的數據修改成了如下樣式
{
"user": {
"name": "alex",
"age": "18",
"is_man": true
}
}
字段值得到了修改,
isMan
-》is_man
,如果我們實體類也改成該字段名,那麼就不符合命名規范了。
在Gson中有如下注解
@SerializedName
@SerializedName("is_man")
private boolean isMan;
這樣就解決了問題。
還有一種情況,如果對於該字段,有的地方使用
is_man
,有的地方使用is_Man
,甚至還有isMan
。那麼我們因為三個字段名的不同建立三個實體類,很是蛋疼。
@SerializedName(value = "is_man",alternate = {"is_Man","isMan"})
private boolean isMan;
當然,如果這三個字段同時出現時,會取最後一次出現的對應值進行賦值。
Gson 解析數組型實體類對象
對於例子,我們修改一下
{
"user": [
{
"name": "alex",
"age": "18",
"is_man": true
},
{
"name": "mahao",
"age": "16",
"is_man": true
}
]
}
user
中所對應的值不再是一個JSONObject
,而是JSONArray
類型。
public static void parserArray(){
String json = "{\"user\":[{\"name\":\"alex\",\"age\":18,\"isMan\":true},{\"name\":\"mahao\",\"age\":16,\"isMan\":true}]}";
//1, 獲取對應實體類對象的字符串,當前為user的值。
String userJson = new JSONObject(json).getJSONArray("user").toString();
//2 ,創建Gson 對象
Gson gson = new Gson();
//3, 獲取user 數組
User[] users = gson.fromJson(userJson, User[].class);
System.out.println(users[1]);
}
最終解析出了
User[]
數組。
平常我們往往使用List存儲數據。
第三步改成了如下代碼
List users = gson.fromJson(userJson, List.class);
報錯!!! 因為第二個參數的字節碼,實際為List.class ,User被忽略了。 泛型擦除
Gson為我們提供了另一個方法解決該問題
List users = gson.fromJson(userJson,new TypeToken>(){}.getType());
System.out.println(users.get(1));
通過Gson 構造json數據
根據實體類對象生成json 數據。
public static void writeBeanJson(){
//1 構造gson 對象
Gson gson = new Gson();
//2 構造對象
User user = new User();
user.setName("lala");
user.setAge(20);
// 3 生成json 數據
String json = gson.toJson(user);
System.out.println(json);
}
{"name":"lala","age":20,"is_man":false}
如果實體類中為null或空字符串,則該字段不會被轉化。當然也可以通過GsonBuilder設置,後面會提到。
自定義json數據。
對於POST請求,需要的json數據自定義比較大。例如登錄時,需要傳入賬號和密碼。
private static void writeJson() {
//1 構造gson 對象
Gson gson = new Gson();
//2 ,構建map對象
Map map = new HashMap();
map.put("username","haha");
map.put("password",123456);
//3 生成json數據
String json = gson.toJson(map);
System.out.println(json);
}
Gson使用擴展
GsonBuilder
,通過該類初始化一些Gson
的基本屬性
Gson gson = new GsonBuilder()
//序列化null
.serializeNulls()
// 設置日期時間格式,另有2個重載方法
// 在序列化和反序化時均生效
.setDateFormat("yyyy-MM-dd")
// 禁此序列化內部類
.disableInnerClassSerialization()
//生成不可執行的Json(多了 )]}' 這4個字符)
.generateNonExecutableJson()
//禁止轉義html標簽
.disableHtmlEscaping()
//格式化輸出
.setPrettyPrinting()
.create();
Gson的封裝
/**
* gson 的基本封裝,完成Gson 解析中常用的功能
* 備注人: Alex_MaHao
* @date 創建時間:2016年6月6日 下午4:33:25
*/
public class GsonUtil {
private static Gson gson = null;
static {
if (gson == null) {
gson = new Gson();
}
}
private GsonUtil() {
}
/**
*
* 對象轉化為json 數據
* @param object 需要轉化的對象
* @return
*/
public static String GsonString(Object object) {
String gsonString = null;
if (gson != null) {
gsonString = gson.toJson(object);
}
return gsonString;
}
/**
* json 數據轉化為實體類對象
*
* @param gsonString
* @param cls
* @return
*/
public static T GsonToBean(String gsonString, Class cls) {
T t = null;
if (gson != null) {
t = gson.fromJson(gsonString, cls);
}
return t;
}
/**
*
* Json 數據轉化為List集合--集合中為實體類
*
* @param gsonString
* @param cls
* @return
*/
public static List GsonToList(String gsonString, Class cls) {
ArrayList mList = new ArrayList();
JsonArray array = new JsonParser().parse(gsonString).getAsJsonArray();
for (final JsonElement elem : array) {
mList.add(gson.fromJson(elem, cls));
}
return mList;
}
/**
* 將數據轉化成List集合--集合中為map
*
* @param gsonString
* @return
*/
public static List
fastJson
fastJson 是阿裡巴巴出的第三方庫。該庫的使用非常的方便而且強大。但是用的並不多,大家都是用Gson。雖然不知道原因是為什麼。
使用fastJson有一個很大的缺陷,就是其命名與Android 原生的解析命名相同,所以在使用中很容易混淆。
解析對象
public static void parserObject(){
String json = "{\"user\":{\"name\":\"alex\",\"age\":18,\"isMan\":true}}";
//1, 獲取對應實體類對象的字符串,當前為user的值。 該JSONObject 為org包中的。。
String userJson = new JSONObject(json).getJSONObject("user").toString();
//2 調用JSON.parserObject 解析
User user = JSON.parseObject(userJson, User.class);
System.out.print(user);
}
User{name='alex', age=18, isMan=true, sex='null'}
解析數組
public static void parserArray(){
String json = "{\"user\":[{\"name\":\"alex\",\"age\":18,\"isMan\":true},{\"name\":\"mahao\",\"age\":16,\"isMan\":true}]}";
//1, 獲取對應實體類對象的字符串,當前為user的值。
String userJson = new JSONObject(json).getJSONArray("user").toString();
//2 調用JSON.parseArray 解析
List users = JSON.parseArray(userJson, User.class);
System.out.println(users.get(1));
}
User{name='mahao', age=16, isMan=true, sex='null'}
構造json 數據
public static void wirteJson(){
Map map = new HashMap();
map.put("username","haha");
map.put("password",123456);
String json = JSON.toJSONString(map);
System.out.println(json);
}
{"password":123456,"username":"haha"}
通過上面的例子看出,使用fastJson 更加的簡單,方便。主要通過
JSON.parseArray
,JSON.paseObject
,JSON.toJSONString
進行數據的解析和生成。
GsonFormat
在上面的例子中,使用
Gson
,fastJson
解析數據時,關鍵的便是實體類。 但有時候實體類非常復雜時,我們比著敲時很容易出錯。
在這裡使用
GsonFormat
插件,該插件為Android Studio的插件。
File -》 setting -》plugins -> 搜索
GsonFormat
,導入即可。
使用方式如下圖:
點擊Alt+insert
本人自己在做一個launcher,所以需要處理icon,加陰影和邊框等。這只是一種處理方法,其他的處理方法類似。 效果圖: &
寫在前面:在暴雨天能去上課的都是好學生,能去上班的都是游泳運動員~ 問大家一個問題:Android中一個應用程序的真正入口是什麼?無論你知道不知道,別著急回答,
拿到美工效果圖,咱們程序員就得畫得一模一樣。 為了不被老板噴,只能多練啊。聽說你覺得前面幾篇都so easy,那今天就帶你做個相對比較復雜的。今天的效果圖如下(左邊是ui
最近公司要求做個九宮格解鎖,本人用的是小米手機,看著他那個設置鎖屏九宮格很好看,就做了該組件,不使用圖片資源,純代碼實現。尊重每個辛苦的博主,在http://