65.9K
CodeProject 正在变化。 阅读更多。
Home

Retrofit - Android 的 REST 客户端 (Retrofit 2.X)

emptyStarIconemptyStarIconemptyStarIconemptyStarIconemptyStarIcon

0/5 (0投票)

2019年8月20日

CPOL

4分钟阅读

viewsIcon

13940

使用 Retrofit 开发 Android 应用程序以连接到 API。

引言

在本教程中,我们将学习 Retrofit 的基础知识,并创建一个 Android 客户端,用于向 GitHub API 发起 HTTP 请求。

背景

Retrofit 是一个用于 Java 和 Android 的 REST 客户端。通过 Retrofit,您可以非常轻松地通过基于 REST 的 Web 服务在您的 Android 移动应用程序中检索和/或上传 JSON(或其他结构化数据)。

在本教程中,我们将学习 Retrofit 的基础知识,并创建一个 Android 客户端,用于向 GitHub API 发起 HTTP 请求。

  • 以下是实现步骤
  • 创建一个 Android 项目
  • 定义 Gradle 依赖项
  • 定义 Android 的网络权限
  • 描述 API 端点
  • 创建用户界面
  • 配置 JSON 映射
  • 创建 Retrofit 客户端
  • 执行请求并显示数据

Using the Code

使用您喜欢的 IDE 创建一个 Android 项目。我将使用 Android Studio。您可以创建一个空的 Activity 项目。

在 Gradle Scripts 部分选择 build.gradle (module) 文件,并将 Retrofit 指定为项目的依赖项。

dependencies { 
     //Other dependencies...
    // Retrofit & OkHttp dependency
    implementation 'com.squareup.retrofit2:retrofit:2.5.0'
    implementation 'com.squareup.retrofit2:converter-gson:2.5.0'
}

添加依赖项后,点击 Sync Now 链接。

当您运行构建命令时,构建系统将下载并提供必要的库。

注意:Retrofit 2 (默认情况下) 包含 OkHttp 作为网络层。因此,您无需显式将 OkHttp 定义为项目的依赖项。但是,Retrofit 2 需要一个依赖项来自动转换请求和响应。默认的转换器是 Gson。Gson 是一个非常强大的库,用于将 JSON 表示的数据结构映射到 Java 对象。

定义 Android 的网络权限

Android 应用程序设计为在沙盒环境中运行。Retrofit 会向在 Internet 服务器上运行的 API 发起 HTTP 请求。为了从 Android 应用程序执行此类外部请求,需要 Internet 权限来打开网络套接字。因此,您需要在 AndroidManifest.xml 文件中定义这些权限。

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
   package="app.retrofit.nipunu.retrofitapp">
   <uses-permission android:name="android.permission.INTERNET" />
   <application
       ...

描述 API 端点

为了发送请求,您首先需要描述 API 端点。在本教程中,我们将描述一个简单的 GitHub API 端点。

在您的应用程序源代码集中创建一个名为 GitHubClient 的接口。

选择接口作为“种类”,然后点击 OK

现在您应该已经创建了您的接口。

定义一个名为 UserRepositories 的方法,该方法接受一个 string 类型的参数,该参数将是用户名。此方法将返回一个 RepoList 类型的列表。

public interface GitHubClient {
   List<RepoList> UserRepositories(String phrase);
}

由于我们发出一个 Get 请求来检索结果,因此我们需要像这样用端点注解我们的方法。@GET 注解声明此请求使用 HTTP GET 方法。

import retrofit2.http.GET;
public interface GitHubClient {
   @GET("users/USER_NAME/repos")
   List<RepoList> UserRepositories(String phrase);
}

我们可以使用 Retrofit 的路径参数替换功能,而不是硬编码用户名,如下所示:

import retrofit2.http.Path;
public interface GitHubClient {
   @GET("users/{username}/repos")
   List<RepoList> UserRepositories(@Path("username") String userName);
}

当前,UserRepositories 是一个同步方法,它将冻结 UI 并在 Android 4.0 或更高版本上崩溃应用程序。作为一项规则,来自 UI 线程的网络请求需要异步进行。我们可以通过将方法返回包装在 call<> 对象中来轻松地使此方法调用异步,如下所示:

public interface GitHubClient {
   @GET("users/{username}/repos")
   Call<List<RepoList>> UserRepositories(@Path("username") String userName);
}

完整的 GitHubClient 如下所示:

import java.util.List;
import retrofit2.Call;
import retrofit2.http.GET;
import retrofit2.http.Path;
public interface GitHubClient {
   @GET("users/{username}/repos")
   Call<List<RepoList>> UserRepositories(@Path("username") String userName);
}

我们还没有实现 RepoList 类。让我们去为我们的应用程序添加 RepoList 类。

创建一个名为 RepoList 的类。此类用于与返回数据进行映射。在这种情况下,我们只匹配存储库的名称。

public class RepoList {
   private String name;
   public String getRepoName(){return name;}
}

创建用户界面

我们需要一个 UI 来显示结果。让我们使用 ListView 控件来显示我们接收到的存储库名称。

删除 activity_mail.xml 文件中的默认 Textview,并创建一个 ID 为 repository_listListView 控件。设置约束使 ListView 填充整个 Activity 的空间。

MainActivity.class 文件的 onCreate 方法中引用 Listview

public class MainActivity extends AppCompatActivity {
   private ListView repositoryList;
   @Override
   protected void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       setContentView(R.layout.activity_main);
       repositoryList = (ListView)findViewById(R.id.repository_list);
   }
}

现在我们需要创建一个 Layout 来容纳 ListView 的单个项,也就是我们存储库的名称。

创建一个名为 repository_list_item.xml 的新布局。在该布局中添加一个 TextView,并将其命名为 repository_name_text

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
   xmlns:android="http://schemas.android.com/apk/res/android"
   xmlns:app="http://schemas.android.com/apk/res-auto"
   xmlns:tools="http://schemas.android.com/tools"
   android:layout_width="match_parent"
   android:layout_height="match_parent">
   <TextView
       android:id="@+id/repository_name_text"
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"
       android:layout_marginStart="8dp"
       android:layout_marginTop="8dp"
       android:layout_marginEnd="8dp"
       android:layout_marginBottom="8dp"
       android:text="TextView"
       app:layout_constraintBottom_toBottomOf="parent"
       app:layout_constraintEnd_toEndOf="parent"
       app:layout_constraintStart_toStartOf="parent"
       app:layout_constraintTop_toTopOf="parent" />
</android.support.constraint.ConstraintLayout>

ListView 需要一个适配器来加载数据。让我们创建 adapter 类。

创建一个名为 RepoListAdapter 的类,该类扩展了 RepoList 类型的 ArrayAdapter

import android.widget.ArrayAdapter;
public class RepoListAdapter extends ArrayAdapter<RepoList> {
   Context context;
   List<RepoList> repoList;
}

为该类添加一个构造函数。

public RepoListAdapter(Context context, List<RepoList> repoList) {
   super(context, R.layout.repository_list_item,repoList);
   this.context = context;
   this.repoList = repoList;
}

最后,重写 getView 方法以检索每个 repo 名称并将其设置为 TextView

@Override
public View getView(int position, View convertView, ViewGroup parent) {
   View row = convertView;
    if (row == null) {
        LayoutInflater inflater =
                (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        row = inflater.inflate(R.layout.repository_list_item, parent, false);
    }
    TextView textView = (TextView) row.findViewById(R.id.repository_name_text);
    RepoList list = repoList.get(position);
    String repoName = list.getRepoName();
    textView.setText(repoName);
    return row;
}

现在,在 MainActivityonCreate 方法中,让我们实例化 Retrofit 构建器类。此类负责为我们创建 Retrofit 对象。

@Override
protected void onCreate(Bundle savedInstanceState) {
   super.onCreate(savedInstanceState);
   setContentView(R.layout.activity_main);
   repositoryList = (ListView) findViewById(R.id.repository_list);
   Retrofit.Builder builder = new Retrofit.Builder()
       .baseUrl("https://api.github.com")
       .addConverterFactory(GsonConverterFactory.create());
}

接下来,在同一个 onCreate 方法中,让我们借助构建器创建 Retrofit 对象并发出 API 调用。

@Override
protected void onCreate(Bundle savedInstanceState) {
   super.onCreate(savedInstanceState);
   setContentView(R.layout.activity_main);
   repositoryList = (ListView) findViewById(R.id.repository_list);
   Retrofit.Builder builder = new Retrofit.Builder()
           .baseUrl("https://api.github.com")
           .addConverterFactory(GsonConverterFactory.create());
   Retrofit retrofit = builder.build();
   GitHubClient client = retrofit.create(GitHubClient.class);
   Call<List<RepoList>> call = client.UserRepositories("USER_NAME");
}

上面的调用是一个异步方法调用。因此,我们需要通过 enqueue 方法将此调用异步地作为一个新的回调来实现。

call.enqueue(new Callback<List<RepoList>>() {
   @Override
   public void onResponse(Call<List<RepoList>> call, Response<List<RepoList>> response) {      
   }
   @Override
   public void onFailure(Call<List<RepoList>> call, Throwable t) {
   }
});

作为最后一步,我们需要实现 onResponseonFailure 方法。

call.enqueue(new Callback<List<RepoList>>() {
   @Override
   public void onResponse(Call<List<RepoList>> call, Response<List<RepoList>> response) {
       List<RepoList> list = response.body();
       repositoryList.setAdapter(new RepoListAdapter(MainActivity.this,list));
   }
   @Override
   public void onFailure(Call<List<RepoList>> call, Throwable t) {
       Toast.makeText(MainActivity.this, "Error...!!!", Toast.LENGTH_SHORT).show();
   }
});

现在运行应用程序。

历史

  • 2019年8月20日:初始版本
© . All rights reserved.