Retrofit实现异步访问数据

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/zhaozhiwen6140/article/details/52096689

使用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就能成功展示了。


猜你喜欢

转载自blog.csdn.net/zhaozhiwen6140/article/details/52096689