RESTful
RESTful:表现层状态转换。大意为资源以某种表现形式在互联网之间传递,而表现形式则是JSON、JEPG、XML等格式,状态转换则通过HTTP协议实现。这是一种互联网转件架构风格。
为了软件能够找到资源的位置,需要定义URI(Uniform Resource Identifier)标准资源识别符。URL就是一种具体的URI。
JSON
JSON是现在常用的数据传输格式。Android处理JSON可以使用JSONObject或者GSON。
JSONObject
来自Java的JSON对象类。
创建:既可以先new一个空的JSONObject对象再手动添加内容,也支持从JSON格式的字符串中自动转换为一个JSON对象。下面是添加属性的例子:
JSONObject jsonObject = new JSONObject();
// JSON中,对象属性的值可以是另一个对象
JSONObject tempJson = new JSONObject();
tempJson.put("min", 11.34);
tempJson.put("max", 19.01);
jsonObject.put("temp", tempJson);
// 对象属性的值也可以是string、int、boolean
jsonObject.put("success", true);
// 或者是一个数组
JSONArray jsonArray = new JSONArray();
jsonArray.put("Adam");
jsonArray.put("Bob");
jsonArray.put("John");
jsonObject.put("notification_user_id", jsonArray);
//通过toString的方法获得JSON格式的字符串
Log.d("JsonDemo", jsonObject.toString());
另外,一个JSON的单元也可以是数组即JSONArray。
下面是从字符串读取JSON对象以及使用JSON对象的例子:
String s = "{\"temp\":{\"min\":11.34,\"max\":19.01},\"success\":true,\"notification_user_id\":[\"Adam\",\"Bob\",\"John\"]}";
try {
JSONObject jsonObject = new JSONObject(s);
// 获取JSON对象的一个键对应的值
JSONArray notificationUserId = jsonObject.getJSONArray("notification_user_id");
/* optBoolean和getBoolean的区别是:
* optBoolean方法在没有找到这个键时可以返回默认值(即第二个参数)
* getBoolean方法如果没有找到键,将抛出异常
* 同理,getString和optString等也是这个区别
*/
boolean success = jsonObject.optBoolean("unexist",true);
boolean unexist = jsonObject.getBoolean("unexist");
} catch (JSONException e) {
Log.d("JsonDemo", "crash:"+e.getMessage());
e.printStackTrace();
}
GSON
Google开发的更加好用的JSON套件,需要引入implementation 'com.google.code.gson:gson:2.8.6’
依赖来使用。
GSON在使用之前可以事先创建好POJO简单对象,然后直接用GSON将一个对象解析成JSON格式的字符串或者从一个JSON格式的字符串创建对象,非常方便。
定义便于GSON使用的简单对象类:
package com.byted.chapter5;
import com.google.gson.annotations.SerializedName;
import java.util.List;
public class People {
// 这里的注解便是对应JSON的键
@SerializedName("age")
public int age;
@SerializedName("name")
public String firstName;
@SerializedName("friends")
public List<String> friends;
}
将对象或数组转化为JSON字符串:
public static void generateGsonString() {
Gson gson = new Gson();
People people = new People();
people.age = 10;
people.firstName = "sander";
ArrayList<String> friends = new ArrayList<>();
friends.add("sss");
friends.add("ddd");
friends.add("nnn");
people.friends=friends;
// 直接使用toJson方法即可,非常方便,一步到位
String s = gson.toJson(people);
People[] p=new People[1];
p[0]=people;
String str=gson.toJson(p);
}
将JSON字符串读取转化为数据对象:
public static void parseGsonString(){
Gson gson = new Gson();
String sp= " {\n" +
" \"name\": \"sander\",\n" +
" \"age\": 11\n" +
" }" ;
// 直接传入JSON字符串和目标的类即可生成对象
People people = gson.fromJson(sp, People.class);
String s="[\n" +
" {\n" +
" \"name\": \"sander\",\n" +
" \"age\": 11\n" +
" },\n" +
" {\n" +
" \"name\": \"sander\",\n" +
" \"age\": 12\n" +
" },\n" +
" {\n" +
" \"name\": \"sander\",\n" +
" \"age\": 13\n" +
" },\n" +
" {\n" +
" \"name\": \"sander\",\n" +
" \"age\": 14\n" +
" },\n" +
" {\n" +
" \"name\": \"sander\",\n" +
" \"age\": 15\n" +
" }\n" +
"]";
// 对于泛型的List要用getType这种方式获得类的信息
List<People> peoples = gson.fromJson(s, new TypeToken<List<People>>(){}.getType());
// 普通的数组类型可以直接读
People[] peoples2 = gson.fromJson(s, People[].class);
}
Retrofit
Retrofit是一个对HTTP请求框架的封装,使用之前首先添加依赖:implementation "com.squareup.retrofit2:retrofit:2.8.1"
然后需要在src/main/AndroidManifest.xml中添加网络权限:
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
在使用的时候,首先需要创建一个描述网络请求的接口,采用注解的方式指明URL等信息,使用注解+参数传递的方式在POST请求的请求体中加入信息。注意这里的URL是不完整的,省略了Base部分。举例如下:
import retrofit2.Call;
import retrofit2.http.Field;
import retrofit2.http.FormUrlEncoded;
import retrofit2.http.GET;
import retrofit2.http.POST;
import retrofit2.http.Part;
public interface ApiService {
// 方法:GET
// https://wanandroid.com/wxarticle/chapters/json
@GET("wxarticle/chapters/json")
Call<ArticleResponse> getArticles();
// https://www.wanandroid.com/user/register
//方法:POST
// username,password,repassword
// @FormUrlEncoded表示将参数中会通过@Field的方式指明键和值
@FormUrlEncoded
@POST("user/register")
Call<UserResponse> register(@Field("username") String username,
@Field("password") String password,
@Field("repassword") String repassword);
}
在需要进行网络请求的地方,需要实例化Retrofit对象,在这里指明URL的base部分,然后创建API实例。之后,一般建议使用异步请求的方式完成网络连接。注意返回值是泛型的Response类型,具体类型可以自定义,可以使用.body()方法获得内部真正需要的数据对象。使用例如:
private void getData() {
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://wanandroid.com/")
.addConverterFactory(GsonConverterFactory.create())
.build();
// 用刚才创建的接口进行配置,创建ApiService实例
ApiService apiService = retrofit.create(ApiService.class);
// 采用异步请求的方式,完成后回调方法
apiService.getArticles().enqueue(new Callback<ArticleResponse>() {
//请求成功时调用。这里的ArticleResponse是自定义的
@Override
public void onResponse(Call<ArticleResponse> call, Response<ArticleResponse> response) {
if (response.body() != null) {
List<ArticleResponse.Article> articles = response.body().articles;
Log.d("retrofit", articles.toString());
if (articles.size() != 0) {
mAdapter.setData(response.body().articles);
mAdapter.notifyDataSetChanged();
}
}
}
//请求失败时调用
@Override
public void onFailure(Call<ArticleResponse> call, Throwable t) {
Log.d("retrofit", t.getMessage());
}
});
}
当然,也可以采用同步的方式,不过可能会造成卡顿等问题。
Response<ArticleResponse> = apiService.getArticles().execute();
AriticleResponse article = response == null ? null : response.body();