Retrofit Android示例教程

时间:2020-02-23 14:29:29  来源:igfitidea点击:

欢迎使用Retrofit Android示例教程。
今天,我们将使用Square开发的Retrofit库来处理android应用程序中的REST API调用。

Retrofit Android

Retrofit是适用于Android和Java的类型安全的REST客户端,旨在简化使用RESTful Web服务的过程。
我们将不介绍Retrofit 1.x版本的详细信息,而直接跳至Retrofit 2,该版本具有许多新功能,并且与以前的版本相比,内部API有所更改。

默认情况下,Retrofit 2利用OkHttp作为网络层,并在此之上构建。

Retrofit使用POJO(普通的旧Java对象)自动序列化JSON响应,而POJO必须为JSON结构预先定义。
要序列化JSON,我们需要一个转换器,首先将其转换为Gson。
我们需要在build.grade文件中添加以下依赖项。

compile 'com.squareup.retrofit2:retrofit:2.1.0'
compile 'com.google.code.gson:gson:2.6.2'
compile 'com.squareup.retrofit2:converter-gson:2.1.0'

OkHttp依赖性已经随Retrofit 2依赖性一起提供。
如果希望使用单独的OkHttp依赖项,则应从Retrofit 2中排除OkHttp依赖项,如下所示:

compile ('com.squareup.retrofit2:retrofit:2.1.0') {  
//exclude Retrofit’s OkHttp dependency module and define your own module import
exclude module: 'okhttp'
}
compile 'com.google.code.gson:gson:2.6.2'
compile 'com.squareup.retrofit2:converter-gson:2.1.0'
compile 'com.squareup.okhttp3:logging-interceptor:3.4.1'
compile 'com.squareup.okhttp3:okhttps:3.4.1'
  • 日志拦截器会生成返回的整个响应的日志字符串。

  • 还有其他转换器可将JSON解析为必要的类型。
    下面列出了其中一些。

  • Hymanson :com.squareup.retrofit2:converter-Hymanson:2.1.0

  • Moshi:com.squareup.retrofit2:converter-moshi:2.1.0

  • Protobuf:com.squareup.retrofit2:converter-protobuf:2.1.0

  • 连线:com.squareup.retrofit2:converter-wire:2.1.0

  • 简单的XML:com.squareup.retrofit2:converter-simplexml:2.1.0

在AndroidManifest.xml文件中添加访问Internet的权限。

OkHttp拦截器

拦截器是OkHttp中提供的一种强大机制,可以监视,重写和重试调用。
拦截器主要可分为两类:

  • 应用程序拦截器:要注册应用程序拦截器,我们需要在OkHttpClient.Builder上调用addInterceptor()

  • 网络拦截器:要注册网络拦截器,请调用" addNetworkInterceptor()"而不是" addInterceptor()"

设置Retrofit界面

package com.theitroad.retrofitintro;

import com.theitroad.retrofitintro.pojo.MultipleResource;

import okhttp3.OkHttpClient;
import okhttp3.logging.HttpLoggingInterceptor;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;

class APIClient {

  private static Retrofit retrofit = null;

  static Retrofit getClient() {

      HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
      interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
      OkHttpClient client = new OkHttpClient.Builder().addInterceptor(interceptor).build();

      retrofit = new Retrofit.Builder()
              .baseUrl("https://reqres.in")
              .addConverterFactory(GsonConverterFactory.create())
              .client(client)
              .build();

      return retrofit;
  }

}

在设置Retrofit接口时,每次都会调用上述代码中的getClient()方法。
Retrofit为每个HTTP方法提供了注释列表:@ GET,@ POST,@ PUT,@ DELETE,@ PATCH或者@HEAD。

让我们看看我们的APIInterface.java类的样子。

package com.theitroad.retrofitintro;

import com.theitroad.retrofitintro.pojo.MultipleResource;
import com.theitroad.retrofitintro.pojo.User;
import com.theitroad.retrofitintro.pojo.UserList;

import retrofit2.Call;
import retrofit2.http.Body;
import retrofit2.http.Field;
import retrofit2.http.FormUrlEncoded;
import retrofit2.http.GET;
import retrofit2.http.POST;
import retrofit2.http.Query;

interface APIInterface {

  @GET("/api/unknown")
  Call<MultipleResource> doGetListResources();

  @POST("/api/users")
  Call<User> createUser(@Body User user);

  @GET("/api/users?")
  Call<UserList> doGetUserList(@Query("page") String page);

  @FormUrlEncoded
  @POST("/api/users?")
  Call<UserList> doCreateUserWithField(@Field("name") String name, @Field("job") String job);
}

在上面的类中,我们定义了一些执行带有注释的HTTP请求的方法。
我们从这里使用了一些测试API

@GET("/api/unknown")调用doGetListResources();。

doGetListResources()是方法名称。
" MultipleResource.java"是我们的响应对象的Model POJO类,用于将响应参数映射到它们各自的变量。
这些POJO类充当方法的返回类型。

下面给出了用于MultipleResources.java的简单POJO类。

package com.theitroad.retrofitintro.pojo;

import com.google.gson.annotations.SerializedName;

import java.util.ArrayList;
import java.util.List;

public class MultipleResource {

  @SerializedName("page")
  public Integer page;
  @SerializedName("per_page")
  public Integer perPage;
  @SerializedName("total")
  public Integer total;
  @SerializedName("total_pages")
  public Integer totalPages;
  @SerializedName("data")
  public List<Datum> data = null;

  public class Datum {

      @SerializedName("id")
      public Integer id;
      @SerializedName("name")
      public String name;
      @SerializedName("year")
      public Integer year;
      @SerializedName("pantone_value")
      public String pantoneValue;

  }
}

@ SerializedName注释用于指定JSON响应中字段的名称。

要为每个响应创建一个POJO类,我们可以转到https://www.jsonschema2pojo.org/并粘贴json响应结构,如下图所示。

预览POJO类并将其复制到您的Android Studio项目结构中。

POJO类包装为类型化的Retrofit Call类。

注意:JSONArray已序列化POJO类中的对象列表

方法参数:有多种可能的参数选项可在方法内部传递:

  • @Body-将Java对象作为请求正文发送。

  • @URL-使用动态URL。
    @Query-我们可以简单地使用@Query()和方法参数名称添加方法参数,以描述类型。
    要对查询进行URL编码,请使用以下格式:
    @Query(value =" auth_token",encoded = true)字符串auth_token

  • @Field –以表单编码形式发送数据。
    这需要在方法后附加一个@FormUrlEncoded注释。

@ Field参数仅适用于POST

注意:@Field需要必填参数。
如果@Field是可选的,我们可以改用@Query并传递一个空值。

修改 Android示例项目结构

pojo包为APIInterface.java类中定义的每个API端点响应定义了四个模型类。

User.java

package com.theitroad.retrofitintro.pojo;

import com.google.gson.annotations.SerializedName;

public class User {

  @SerializedName("name")
  public String name;
  @SerializedName("job")
  public String job;
  @SerializedName("id")
  public String id;
  @SerializedName("createdAt")
  public String createdAt;

  public User(String name, String job) {
      this.name = name;
      this.job = job;
  }

}

上面的类用于为createUser()方法创建响应主体。

UserList.java

package com.theitroad.retrofitintro.pojo;

import com.google.gson.annotations.SerializedName;

import java.util.ArrayList;
import java.util.List;

public class UserList {

  @SerializedName("page")
  public Integer page;
  @SerializedName("per_page")
  public Integer perPage;
  @SerializedName("total")
  public Integer total;
  @SerializedName("total_pages")
  public Integer totalPages;
  @SerializedName("data")
  public List<Datum> data = new ArrayList();

  public class Datum {

      @SerializedName("id")
      public Integer id;
      @SerializedName("first_name")
      public String first_name;
      @SerializedName("last_name")
      public String last_name;
      @SerializedName("avatar")
      public String avatar;

  }
}

CreateUserResponse.java

package com.theitroad.retrofitintro.pojo;

import com.google.gson.annotations.SerializedName;

public class CreateUserResponse {

  @SerializedName("name")
  public String name;
  @SerializedName("job")
  public String job;
  @SerializedName("id")
  public String id;
  @SerializedName("createdAt")
  public String createdAt;
}

在MainActivity.java中,我们调用Interface类中定义的每个API端点,并在Toast/TextView中显示每个字段。

package com.theitroad.retrofitintro;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.widget.TextView;
import android.widget.Toast;

import com.theitroad.retrofitintro.pojo.CreateUserResponse;
import com.theitroad.retrofitintro.pojo.MultipleResource;
import com.theitroad.retrofitintro.pojo.User;
import com.theitroad.retrofitintro.pojo.UserList;

import java.util.List;

import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;

public class MainActivity extends AppCompatActivity {

  TextView responseText;
  APIInterface apiInterface;

  @Override
  protected void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.activity_main);
      responseText = (TextView) findViewById(R.id.responseText);
      apiInterface = APIClient.getClient().create(APIInterface.class);

      /**
       GET List Resources
       **/
      Call<MultipleResource> call = apiInterface.doGetListResources();
      call.enqueue(new Callback<MultipleResource>() {
          @Override
          public void onResponse(Call<MultipleResource> call, Response<MultipleResource> response) {

              Log.d("TAG",response.code()+"");

              String displayResponse = "";

              MultipleResource resource = response.body();
              Integer text = resource.page;
              Integer total = resource.total;
              Integer totalPages = resource.totalPages;
              List<MultipleResource.Datum> datumList = resource.data;

              displayResponse += text + " Page\n" + total + " Total\n" + totalPages + " Total Pages\n";

              for (MultipleResource.Datum datum : datumList) {
                  displayResponse += datum.id + " " + datum.name + " " + datum.pantoneValue + " " + datum.year + "\n";
              }

              responseText.setText(displayResponse);

          }

          @Override
          public void onFailure(Call<MultipleResource> call, Throwable t) {
              call.cancel();
          }
      });

      /**
       Create new user
       **/
      User user = new User("morpheus", "leader");
      Call<User> call1 = apiInterface.createUser(user);
      call1.enqueue(new Callback<User>() {
          @Override
          public void onResponse(Call<User> call, Response<User> response) {
              User user1 = response.body();

              Toast.makeText(getApplicationContext(), user1.name + " " + user1.job + " " + user1.id + " " + user1.createdAt, Toast.LENGTH_SHORT).show();

          }

          @Override
          public void onFailure(Call<User> call, Throwable t) {
              call.cancel();
          }
      });

      /**
       GET List Users
       **/
      Call<UserList> call2 = apiInterface.doGetUserList("2");
      call2.enqueue(new Callback<UserList>() {
          @Override
          public void onResponse(Call<UserList> call, Response<UserList> response) {

              UserList userList = response.body();
              Integer text = userList.page;
              Integer total = userList.total;
              Integer totalPages = userList.totalPages;
              List<UserList.Datum> datumList = userList.data;
              Toast.makeText(getApplicationContext(), text + " page\n" + total + " total\n" + totalPages + " totalPages\n", Toast.LENGTH_SHORT).show();

              for (UserList.Datum datum : datumList) {
                  Toast.makeText(getApplicationContext(), "id : " + datum.id + " name: " + datum.first_name + " " + datum.last_name + " avatar: " + datum.avatar, Toast.LENGTH_SHORT).show();
              }

          }

          @Override
          public void onFailure(Call<UserList> call, Throwable t) {
              call.cancel();
          }
      });

      /**
       POST name and job Url encoded.
       **/
      Call<UserList> call3 = apiInterface.doCreateUserWithField("morpheus","leader");
      call3.enqueue(new Callback<UserList>() {
          @Override
          public void onResponse(Call<UserList> call, Response<UserList> response) {
              UserList userList = response.body();
              Integer text = userList.page;
              Integer total = userList.total;
              Integer totalPages = userList.totalPages;
              List<UserList.Datum> datumList = userList.data;
              Toast.makeText(getApplicationContext(), text + " page\n" + total + " total\n" + totalPages + " totalPages\n", Toast.LENGTH_SHORT).show();

              for (UserList.Datum datum : datumList) {
                  Toast.makeText(getApplicationContext(), "id : " + datum.id + " name: " + datum.first_name + " " + datum.last_name + " avatar: " + datum.avatar, Toast.LENGTH_SHORT).show();
              }

          }

          @Override
          public void onFailure(Call<UserList> call, Throwable t) {
              call.cancel();
          }
      });

  }
}

apiInterface = APIClient.getClient()。
create(APIInterface.class);用于实例化APIClient。
要将Model类映射到响应,我们使用:

MultipleResource资源= response.body();

运行该应用程序将调用每个端点,并相应地为它们显示Toast消息。