使用Retrofit访问API接口,相对更安全也更强大方便。一般适用于通过API接口下载Json或者Xml的数据,下载完成能直接解析成Java类,通过类的对象直接获得数据。相比Retrofit1.9而言,Retrofit2.0在访问逻辑上做了调整,统一了异步与同步的调用模式。下面以Retrofit2.0,以解析Json数据为例。
一.配置
1.在AndroidManifest.xml加入网络请求权限(与网络访问相关的都要加入网络请求)
<uses-permission android:name="android.permission.INTERNET"
/>
2
.
在
app/build.gradle
文件中添加
Retrofit相关的库
dependencies {
compile 'com.google.code.gson:gson:2.3'
compile 'com.squareup.retrofit:retrofit:2.0.0-beta1'
compile 'com.squareup.retrofit:converter-gson:2.0.0-beta2'
compile 'com.squareup.okhttp:okhttp:2.4.0'
}
二.构造数据模型
这个过程需要获取返回给你的Json串的示例,根据返回数据的格式,然后构造数据模型。有两种构造数据模型的方式。
1. 第一种是通过服务器端给取的Json串的示例数据(你必须要保证这些示例数据能代替你的所有数据,否则生成的数据模型可能不准确。如果无法确保完整性,则最好获得全部的Json数据,这样就不会在运行时出问题)或者自己先通过API接口中的url获取全部的Json数据。获取到Json数据之后,打开网址:http://www.jsonschema2pojo.org/,
将Json串复制到左边的方框中,选择Source type是JSON,Annotation style:是None(如果使用Retrofit1.9的话,需要选择Gson),选择Use primitivetypes以及Include getters and setters,点击Preview即可出现模型类。
解析完成的模型类为(这里只展示了一部分),把生成的类粘贴到项目的数据模型的类中,把类名Example重命名为
反映数据模型的名称。这里我命名为Movie(命名可以根据自身需要命名)。
2. 还有一种方式,是根据服务器端给取的Json串的示例数据或者自己先通过API接口中的url获取全部的Json数据自
己编写模型类,我个人更喜欢这种方式。
以下面这串Json串为例(后面的操作也是基于这串Json串):
movies:[
{
id:"771305050",
title:"Straight Outta Compton",
production: {
director: "F. Gary Gray"
screenplay: "Jonathan Herman"
},
year: 2015,
},
{
id: "771357161",
title: "Mission: Impossible RogueNation",
production: {
director: "Christopher McQuarrie",
screenplay: "Christopher McQuarrie"
},
year:2015
}
]
可以这样看,每一个[]都是一个List,每一个{}都是一个类。上面这串Json数据的最外层是[],说明这个最外层是一个
List,再往里看,List的每一个元素都用{}包裹(就是下面这部分),说明List的每个元素都是一个类,我们给这个类
命名为Movie(类名怎么命名都可以):
{
id:"771305050",
title:"Straight Outta Compton",
production: {
director: "F. Gary Gray"
screenplay: "Jonathan Herman"
},
year: 2015,
}
类Movie包含属性id,title(都是String类型)一个名为production的类还有一个属性year(int类型),同时,
production类包含的属性为director和screenplay(都是String类型),分析完了之后,我们来建立数据模型。
首先,最外层的List先不管,把内部的类建完,放在List中即可,先写Movie类,如下:
class Movie {
String id;
String title;
int year;
Production production;
public String getId() {
return id;
}
public String getTitle() {
return title;
}
public int getYear() {
return year;
}
public Production getProduction() {
return production;
}
public void setId(String id) {
this.id = id;
}
public void setTitle(String title) {
this.title = title;
}
public void setYear(int year) {
this.year = year;
}
public void setProduction(Production production) {
this.production = production;
}
}
然后是production类,如下:
classProduction {
String director;
String screenplay;
public String getDirector() {
return director;
}
public String getScreenplay() {
return screenplay;
}
public void setDirector(String director) {
this.director = director;
}
public void setScreenplay(String screenplay) {
this.screenplay = screenplay;
}
}
每个类需要加入每个属性的get以及set方法,方便解析完成Json数据之后直接通过对象获得或者设置数据。这个也很
容易做到,在每个类添加完基本的属性之后,在Android Studio的空白处点击右键,选择Generate,点击Getter and Setter,
就全部都出现了。点击Constructor,就能直接实现构造函数,有兴趣也可以试试别的方法。
三.创建Retrofit对象,发送网络请求
1.指定服务器的域名,然后通过调用Retrofit builder创建Retrofit对象
public static final String BASE_URL="https://api.themoviedb.org";//指定Service的域名
Retrofit retrofit=new Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build();
2. 定义endpoints
endpoints是定义在一个interface里面,使用特殊的retrofit 注解来映射参数以及请求方法这些细节。另外,返回值
始终是一个参数化了的Call<T>对象,其中T就是第二部分中你自己定义的数据模型类。设计接口如下:
public interface TestAPI {
@GET("/3/movie/550")
Call<List< Movie>> getDApplicationData(
@Query("api_key")String api_key);
}
接口中的访问方法是get方法(用post方法也可以,这个取决于服务器提供的文档要求,没有要求用哪个都可以,一般
post方法更安全一些),传入的参数可以看成端口号,因为,一般公司的服务器需要开很多个接口供不同的产品使用,
传入这部分url即可。
我们的数据模型最外层最终需要返回一个List,List的每个元素都是Movie类型的对象,将这整个放入Call中当做返回类
型,后面的方法自己命名,调用的时候分清楚什么方法是拿什么数据的即可。最后,就是方法参数(这里需要传入一个
开发者的api_key)。这个接口给你的时候,一般会指明是否需要传入参数,如果不需要传入参数直接获取,那么不需
要加参数,如果需要参数,那么下面是几种拼接参数的方法,分别代表不同的意义。
@Query:根据注解的参数来指定查询的key name
比如,参数是String类型的title,那keyname也得是 title,例子如下:
@GET("/getVipPackageByUser")
Call<Model>getUser(
@Query("title") String title);
}
@Path:使用这种拼接方式的话,如果参数是title,那么在URL中需要将这个参数变成这样(在传入的url中带一个{})
@GET("models/{title}")
Call<Model> getUserMOdel(
@Path("title") String title);
@Body:一般是在POST调用的负载(从一个Java对象序列化到一个JSON字符串):
@POST("users/new")
Call<Model> createUser(@Body Model model);
这里需要特别注意POST方法,POST方法传递参数的时候,需要把一个body传递过去,以例子中的model对象为例,
需要在Activity中创建一个Model对象:
Model model=Model .create(MediaType.parse("application/xxx"),output.getBytes());
然后在调用接口的时候,将这个对象作为参数传递过去,其中第二个参数是需要传入的body体。
@Header:
用注释参数的值指定了标题
一般到底用什么样的注解方法关联endpoint,在后台给出的接口中都会给出的,也可以根据URL中的参数进行判定。
例如,如果在URL中出现类似"models/{title}"的参数的话,说明title这个参数是需要通过@Path来进行拼接的。一般
情况下都是使用Query进行拼接的。
四.解析数据
最后一步:实现了接口之后,就可以通过调用接口的方法获得数据再进行解析了。
代码如下(加上实现Retrofit的代码):
public static final String BASE_URL="https://api.themoviedb.org";//指定Service的域名
Retrofit retrofit=new Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build();
TestAPI service=retrofit.create(TestAPI.class);//获得接口对象
Call< List< Movie>> call=service.getDApplicationData("123456789");//传递需要的参数,即api_key
call.enqueue(new Callback<List< Movie>>() {//实现异步访问
@Override
public void onResponse(Response<List< Movie>> response, Retrofit retrofit) {//访问成功获取数据
if (response != null) {
statusCode = response.code();
movieData = response.body();//通过这句获得解析的数据结果,然后将拿到的数据赋值给Movie的对象。
textView.setText(movieData.get(0).getOverview());//通过对象获得相应的数据,进行显示。
} else {
Toast.makeText(MainActivity.this,"没有数据",Toast.LENGTH_SHORT).show();
}
}
@Override
public void onFailure(Throwable t) {
Log.e("errorMessage",t.getMessage());
Toast.makeText(MainActivity.this,"请求未成功!",Toast.LENGTH_SHORT).show();
}
});
如果数据获取成功,那么TextView就能成功展示了。