Android Dagger 2 +Retrofit+ RecyclerView

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

这是在我们的Android应用程序中使用Retrofit和RecyclerView实现Dagger 2的一站式完整教程。
Dagger 2是一个依赖项注入库,对于干净的代码和体系结构至关重要。
有关Dependency Injection和Dagger 2的基本概述,请在继续之前参考本教程。

什么是依赖注入?

简而言之,Dependency Injection无需使用new关键字自己创建实例,而是从外部为您提供这些实例。

在最坏的情况下,依赖注入是我们的朋友。
由于没有紧密耦合,因此它有助于快速重构代码并有助于测试单个事物。
它提高了可读性和可维护性。
不管依赖注入的知识如何,在面向对象编程中的某些时候,您肯定已经使用了它。
以下示例肯定会让您想起它。

public class A {

  public static void main(String[] args){
      B b = new B();
      C c = new C(b);
      D d = new D(b, c);
      E e = new E(d, b);

      A a = new A(e, b);
  }
}

A类是受抚养人。
E和B类是注入的依赖项。
如您在上面的代码中看到的,我们不是在构造函数中初始化类,而是分别进行处理。
虽然我们上面还有样板代码。

有关Dagger 2的重要注意事项

  • 它在编译时检查并绘制依赖对象图。

  • 我们需要使用注释:@ Module,@ Provides,@ Inject,@ Component,@ Scope。

  • 对于两个冲突的依赖项,例如Application具有不同的Context,而Activity具有不同的。
    Dagger 2需要@Qualifier我们的@Named注释来区分。

  • 在接口上设置了@Component。
    它充当桥梁,用于向Java类提供在@Module中指定的依赖项。
    该依赖关系将在我们的Java类中使用@Inject检索。

  • Dagger 2无法注入私有字段。

通过示例可以最好地理解Dagger 2。
已经有一段时间了,我们试图创建一个Android应用程序,使用RecyclerView和Retrofit尽可能最好地解释这些概念。
我们将使用StarWars API。

项目结构

我们为依赖注入组件,模块,作用域和限定符创建了一个单独的软件包di
活动进入ui包。
API方法和POJO类分别位于retrofitpojo包中。
"适配器"包含RecyclerViewAdapter类。
该项目包含两个活动– MainActivity和DetailActivity。

在应用程序的" build.gradle"中添加以下库依赖项。

implementation 'com.android.support:design:27.1.0'
  implementation group: 'com.google.code.gson', name: 'gson', version: '2.8.2'
  implementation group: 'com.squareup.retrofit2', name: 'converter-gson', version: '2.3.0'
  implementation group: 'com.squareup.okhttp3', name: 'okhttp', version: '3.10.0'
  implementation group: 'com.squareup.okhttp3', name: 'logging-interceptor', version: '3.9.0'
  implementation group: 'com.google.code.gson', name: 'gson', version: '2.8.2'
  implementation(group: 'com.squareup.retrofit2', name: 'retrofit', version: '2.3.0') {
      exclude module: 'okhttp'
  }

  implementation 'com.google.dagger:dagger-android:2.11'
  implementation 'com.google.dagger:dagger-android-support:2.11'
  annotationProcessor 'com.google.dagger:dagger-android-processor:2.11'
  annotationProcessor 'com.google.dagger:dagger-compiler:2.13'

确保已在AndroidManifest文件中添加了Internet权限。

依赖注入packagescope

范围定义了所有这些组件的使用位置。
在此应用程序中,它们是两个:ActivityScope和ApplicationScope。

ActivityScope.java

package com.theitroad.dagger2retrofitrecyclerview.di.scopes;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import javax.inject.Scope;

@Scope
@Retention(RetentionPolicy.CLASS)
public @interface ActivityScope {
}

ApplicationScope.java

package com.theitroad.dagger2retrofitrecyclerview.di.scopes;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import javax.inject.Scope;

@Scope
@Retention(RetentionPolicy.CLASS)
public @interface ApplicationScope {
}

@ActivityScope和@ApplicationScope将在以后的组件上使用。

限定词

因此,上下文可以是活动或者应用程序。
Dagger2如何区分它们?使用限定词。

下面定义了ActivityContext.java和ApplicationContext.java类。

package com.theitroad.dagger2retrofitrecyclerview.di.qualifier;

import javax.inject.Qualifier;

@Qualifier
public @interface ActivityContext {

}
package com.theitroad.dagger2retrofitrecyclerview.di.qualifier;

import javax.inject.Qualifier;

@Qualifier
public @interface ApplicationContext {

}

现在,无论其中使用Context的模块中,都必须根据用例使用@ApplicationContext或者@ActivityContext对其进行注释。

模组

模块是将通过组件向依赖项提供依赖项的模块。
让我们先计划一下依赖图。

因此," APIInterface"不依赖任何内容。
ApplicationComponent将容纳Retrofit和AppContext模块。
MainActivity将保存适配器和活动上下文模块以及ApplicationComponent的依赖项。
DetailActivityComponent不包含任何其自身的模块。
它仅使用ApplicationComponent中存在的那些。

上下文模块

package com.theitroad.dagger2retrofitrecyclerview.di.module;

import android.content.Context;

import com.theitroad.dagger2retrofitrecyclerview.di.qualifier.ApplicationContext;
import com.theitroad.dagger2retrofitrecyclerview.di.scopes.ApplicationScope;

import dagger.Module;
import dagger.Provides;

@Module
public class ContextModule {
  private Context context;

  public ContextModule(Context context) {
      this.context = context;
  }

  @Provides
  @ApplicationScope
  @ApplicationContext
  public Context provideContext() {
      return context;
  }
}

我们为上下文指定了应用程序级别范围和限定符。

改造模块

package com.theitroad.dagger2retrofitrecyclerview.di.module;

import com.theitroad.dagger2retrofitrecyclerview.di.scopes.ApplicationScope;
import com.theitroad.dagger2retrofitrecyclerview.retrofit.APIInterface;

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

@Module
public class RetrofitModule {

  @Provides
  @ApplicationScope
  APIInterface getApiInterface(Retrofit retroFit) {
      return retroFit.create(APIInterface.class);
  }

  @Provides
  @ApplicationScope
  Retrofit getRetrofit(OkHttpClient okHttpClient) {
      return new Retrofit.Builder()
              .baseUrl("https://swapi.co/api/")
              .addConverterFactory(GsonConverterFactory.create())
              .client(okHttpClient)
              .build();
  }

  @Provides
  @ApplicationScope
  OkHttpClient getOkHttpCleint(HttpLoggingInterceptor httpLoggingInterceptor) {
      return new OkHttpClient.Builder()
              .addInterceptor(httpLoggingInterceptor)
              .build();
  }

  @Provides
  @ApplicationScope
  HttpLoggingInterceptor getHttpLoggingInterceptor() {
      HttpLoggingInterceptor httpLoggingInterceptor = new HttpLoggingInterceptor();
      httpLoggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
      return httpLoggingInterceptor;
  }
}

@Provides表示将从该方法向其依赖项提供依赖项。
对于翻新,我们使用ApplicationScope。

MainActivityContextModule

package com.theitroad.dagger2retrofitrecyclerview.di.module;

import android.content.Context;

import com.theitroad.dagger2retrofitrecyclerview.di.qualifier.ActivityContext;
import com.theitroad.dagger2retrofitrecyclerview.di.scopes.ActivityScope;
import com.theitroad.dagger2retrofitrecyclerview.ui.MainActivity;

import dagger.Module;
import dagger.Provides;

@Module
public class MainActivityContextModule {
  private MainActivity mainActivity;

  public Context context;

  public MainActivityContextModule(MainActivity mainActivity) {
      this.mainActivity = mainActivity;
      context = mainActivity;
  }

  @Provides
  @ActivityScope
  public MainActivity providesMainActivity() {
      return mainActivity;
  }

  @Provides
  @ActivityScope
  @ActivityContext
  public Context provideContext() {
      return context;
  }

}

上面的模块用于提供活动上下文和活动实例。

适配器模块

AdapterModule的代码如下。

package com.theitroad.dagger2retrofitrecyclerview.di.module;

import com.theitroad.dagger2retrofitrecyclerview.adapter.RecyclerViewAdapter;
import com.theitroad.dagger2retrofitrecyclerview.di.scopes.ActivityScope;
import com.theitroad.dagger2retrofitrecyclerview.ui.MainActivity;

import dagger.Module;
import dagger.Provides;

@Module(includes = {MainActivityContextModule.class})
public class AdapterModule {

  @Provides
  @ActivityScope
  public RecyclerViewAdapter getStarWarsPeopleLIst(RecyclerViewAdapter.ClickListener clickListener) {
      return new RecyclerViewAdapter(clickListener);
  }

  @Provides
  @ActivityScope
  public RecyclerViewAdapter.ClickListener getClickListener(MainActivity mainActivity) {
      return mainActivity;
  }
}

它用于根据POJO数据创建RecyclerViewAdapter。
另外,ClickListener是RecyclerViewAdapter类中定义的接口,用于从Activity本身触发click listener回调方法。
由于我们在定义中加入了" MainActivityContextModule",因此注入了MainActivity依赖项。

让我们看一下APIInterface和POJO类。

下面给出了APIInterface.java类的代码。

package com.theitroad.dagger2retrofitrecyclerview.retrofit;

import com.theitroad.dagger2retrofitrecyclerview.pojo.Film;
import com.theitroad.dagger2retrofitrecyclerview.pojo.StarWars;

import retrofit2.Call;
import retrofit2.http.GET;
import retrofit2.http.Query;
import retrofit2.http.Url;

public interface APIInterface {

  @GET("people/?")
  Call<StarWars> getPeople(@Query("format") String format);

  @GET
  Call<Film> getFilmData(@Url String url, @Query("format") String format);
}

@Url用于在Retrofit中进行动态URL调用。
该URL将在运行时指定。

POJO类是从.jsonschema2pojo创建的。

StarWars.java

package com.theitroad.dagger2retrofitrecyclerview.pojo;

import com.google.gson.annotations.SerializedName;
import java.util.List;

public class StarWars {

  @SerializedName("results")
  public List<People> results = null;

  public class People {

      @SerializedName("name")
      public String name;
      @SerializedName("height")
      public String height;
      @SerializedName("mass")
      public String mass;
      @SerializedName("birth_year")
      public String birthYear;
      @SerializedName("gender")
      public String gender;
      @SerializedName("homeworld")
      public String homeworld;
      @SerializedName("films")
      public List<String> films = null;

  }

}

电影.java

package com.theitroad.dagger2retrofitrecyclerview.pojo;

import com.google.gson.annotations.SerializedName;

public class Film {

  @SerializedName("title")
  public String title;
  @SerializedName("director")
  public String director;

}

我们只是解析将在应用程序中使用的值。

组件

在组件中,我们将包含模块。
我们需要公开将在"活动/应用程序"中使用的字段。

ApplicationComponent.java

package com.theitroad.dagger2retrofitrecyclerview.di.component;

import android.content.Context;

import com.theitroad.dagger2retrofitrecyclerview.MyApplication;
import com.theitroad.dagger2retrofitrecyclerview.di.module.ContextModule;
import com.theitroad.dagger2retrofitrecyclerview.di.module.RetrofitModule;
import com.theitroad.dagger2retrofitrecyclerview.di.qualifier.ApplicationContext;
import com.theitroad.dagger2retrofitrecyclerview.di.scopes.ApplicationScope;
import com.theitroad.dagger2retrofitrecyclerview.retrofit.APIInterface;

import dagger.Component;

@ApplicationScope
@Component(modules = {ContextModule.class, RetrofitModule.class})
public interface ApplicationComponent {

  public APIInterface getApiInterface();

  @ApplicationContext
  public Context getContext();

  public void injectApplication(MyApplication myApplication);
}

Dagger2将自动生成一个名为Dagger%ComponentName%的类。
例如。
DaggerApplicationComponent。
injectApplication用于允许在我们的活动/应用程序中使用@Inject字段。

MainActivityComponent.java

package com.theitroad.dagger2retrofitrecyclerview.di.component;

import android.content.Context;

import com.theitroad.dagger2retrofitrecyclerview.di.module.AdapterModule;
import com.theitroad.dagger2retrofitrecyclerview.di.qualifier.ActivityContext;
import com.theitroad.dagger2retrofitrecyclerview.di.scopes.ActivityScope;
import com.theitroad.dagger2retrofitrecyclerview.ui.MainActivity;

import dagger.Component;

@ActivityScope
@Component(modules = AdapterModule.class, dependencies = ApplicationComponent.class)
public interface MainActivityComponent {

  @ActivityContext
  Context getContext();

  void injectMainActivity(MainActivity mainActivity);
}

上面的组件也可以访问ApplicationComponent依赖项。

DetailActivityComponent.java

package com.theitroad.dagger2retrofitrecyclerview.di.component;

import com.theitroad.dagger2retrofitrecyclerview.di.scopes.ActivityScope;
import com.theitroad.dagger2retrofitrecyclerview.ui.DetailActivity;
import dagger.Component;

@Component(dependencies = ApplicationComponent.class)
@ActivityScope
public interface DetailActivityComponent {

  void inject(DetailActivity detailActivity);
}

现在是时候在活动和应用程序中使用di了。
我们先来看一下布局代码。

布局

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="https://schemas.android.com/apk/res/android"
  xmlns:app="https://schemas.android.com/apk/res-auto"
  xmlns:tools="https://schemas.android.com/tools"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  tools:context=".ui.MainActivity">

  <android.support.v7.widget.RecyclerView
      android:id="@+id/recyclerView"
      android:layout_width="match_parent"
      android:layout_height="match_parent" 

</android.support.constraint.ConstraintLayout>

activity_detail.xml

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="https://schemas.android.com/apk/res/android"
  xmlns:app="https://schemas.android.com/apk/res-auto"
  xmlns:tools="https://schemas.android.com/tools"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  tools:context=".ui.DetailActivity">

  <TextView
      android:id="@+id/textView"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:text="Loading..."
      android:textColor="@android:color/black"
      android:textSize="28sp"
      android:gravity="center"
      app:layout_constraintBottom_toBottomOf="parent"
      app:layout_constraintLeft_toLeftOf="parent"
      app:layout_constraintRight_toRightOf="parent"
      app:layout_constraintTop_toTopOf="parent" 

</android.support.constraint.ConstraintLayout>

recycler_view_list_row.xml

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="https://schemas.android.com/apk/res/android"
  xmlns:app="https://schemas.android.com/apk/res-auto"
  android:id="@+id/constraintLayout"
  android:layout_width="match_parent"
  android:layout_height="wrap_content"
  android:padding="16dp">

  <TextView
      android:id="@+id/txtName"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content" 

  <TextView
      android:id="@+id/txtBirthYear"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      app:layout_constraintTop_toBottomOf="@+id/txtName" 

</android.support.constraint.ConstraintLayout>

在我们的类中使用依赖注入之前,请重新构建项目。
这样做是为了生成Dagger Component类。

下面给出了MyApplication.java类的代码。

package com.theitroad.dagger2retrofitrecyclerview;

import android.app.Activity;
import android.app.Application;

import com.theitroad.dagger2retrofitrecyclerview.di.component.ApplicationComponent;
import com.theitroad.dagger2retrofitrecyclerview.di.component.DaggerApplicationComponent;
import com.theitroad.dagger2retrofitrecyclerview.di.module.ContextModule;

public class MyApplication extends Application {

  ApplicationComponent applicationComponent;

  @Override
  public void onCreate() {
      super.onCreate();

      applicationComponent = DaggerApplicationComponent.builder().contextModule(new ContextModule(this)).build();
      applicationComponent.injectApplication(this);

  }

  public static MyApplication get(Activity activity){
      return (MyApplication) activity.getApplication();
  }

  public ApplicationComponent getApplicationComponent() {
      return applicationComponent;
  }
}

DaggerApplicationComponent.builder()。
contextModule(new ContextModule(this))。
build();用于构建组件中存在的模块。
getApplicationComponent将用于返回我们活动中的ApplicationComponent。

不要忘记在我们的AndroidManifest.xml文件中添加上述应用程序。

UI包

下面给出MainActivity.java类的代码。

package com.theitroad.dagger2retrofitrecyclerview.ui;

import android.content.Context;
import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.widget.Toast;

import com.theitroad.dagger2retrofitrecyclerview.MyApplication;
import com.theitroad.dagger2retrofitrecyclerview.R;
import com.theitroad.dagger2retrofitrecyclerview.adapter.RecyclerViewAdapter;
import com.theitroad.dagger2retrofitrecyclerview.di.component.ApplicationComponent;
import com.theitroad.dagger2retrofitrecyclerview.di.component.DaggerMainActivityComponent;
import com.theitroad.dagger2retrofitrecyclerview.di.component.MainActivityComponent;
import com.theitroad.dagger2retrofitrecyclerview.di.module.MainActivityContextModule;
import com.theitroad.dagger2retrofitrecyclerview.di.qualifier.ActivityContext;
import com.theitroad.dagger2retrofitrecyclerview.di.qualifier.ApplicationContext;
import com.theitroad.dagger2retrofitrecyclerview.pojo.StarWars;
import com.theitroad.dagger2retrofitrecyclerview.retrofit.APIInterface;

import java.util.List;

import javax.inject.Inject;

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

public class MainActivity extends AppCompatActivity implements RecyclerViewAdapter.ClickListener {

  private RecyclerView recyclerView;
  MainActivityComponent mainActivityComponent;

  @Inject
  public RecyclerViewAdapter recyclerViewAdapter;

  @Inject
  public APIInterface apiInterface;

  @Inject
  @ApplicationContext
  public Context mContext;

  @Inject
  @ActivityContext
  public Context activityContext;

  @Override
  protected void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.activity_main);

      recyclerView = findViewById(R.id.recyclerView);
      recyclerView.setLayoutManager(new LinearLayoutManager(MainActivity.this));

      ApplicationComponent applicationComponent = MyApplication.get(this).getApplicationComponent();
      mainActivityComponent = DaggerMainActivityComponent.builder()
              .mainActivityContextModule(new MainActivityContextModule(this))
              .applicationComponent(applicationComponent)
              .build();

      mainActivityComponent.injectMainActivity(this);
      recyclerView.setAdapter(recyclerViewAdapter);

      apiInterface.getPeople("json").enqueue(new Callback<StarWars>() {
          @Override
          public void onResponse(Call<StarWars> call, Response<StarWars> response) {
              populateRecyclerView(response.body().results);
          }

          @Override
          public void onFailure(Call<StarWars> call, Throwable t) {

          }
      });
  }

  private void populateRecyclerView(List<StarWars.People> response) {
      recyclerViewAdapter.setData(response);
  }

  @Override
  public void launchIntent(String url) {
      Toast.makeText(mContext, "RecyclerView Row selected", Toast.LENGTH_SHORT).show();
      startActivity(new Intent(activityContext, DetailActivity.class).putExtra("url", url));
  }
}

一旦发生这种情况:mainActivityComponent.injectMainActivity(this);@ Inject出现的字段将被自动注入。
其余的工作是在进行Retrofit调用并在RecyclerViewAdapter中设置数据。
该类实现RecyclerViewAdapter.ClickListener接口回调,该回调将在每单击RecyclerView行时触发launchIntent方法。
请注意,需要使用我们之前定义的相关限定符来指定注入的上下文。

下面给出了RecyclerViewAdapter的代码。

package com.theitroad.dagger2retrofitrecyclerview.adapter;

import android.support.constraint.ConstraintLayout;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

import com.theitroad.dagger2retrofitrecyclerview.R;
import com.theitroad.dagger2retrofitrecyclerview.pojo.StarWars;

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

import javax.inject.Inject;

public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewAdapter.ViewHolder> {
  private List<StarWars.People> data;
  private RecyclerViewAdapter.ClickListener clickListener;

  @Inject
  public RecyclerViewAdapter(ClickListener clickListener) {
      this.clickListener = clickListener;
      data = new ArrayList<>();
  }

  @Override
  public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
      return new ViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.recycler_view_list_row, parent, false));
  }

  @Override
  public void onBindViewHolder(ViewHolder holder, int position) {
      holder.txtName.setText(data.get(position).name);
      holder.txtBirthYear.setText(data.get(position).birthYear);
  }

  @Override
  public int getItemCount() {
      return data.size();
  }

  class ViewHolder extends RecyclerView.ViewHolder {

      private TextView txtName;
      private TextView txtBirthYear;
      private ConstraintLayout constraintLayoutContainer;

      ViewHolder(View itemView) {
          super(itemView);

          txtName = itemView.findViewById(R.id.txtName);
          txtBirthYear = itemView.findViewById(R.id.txtBirthYear);
          constraintLayoutContainer = itemView.findViewById(R.id.constraintLayout);

          constraintLayoutContainer.setOnClickListener(new View.OnClickListener() {
              @Override
              public void onClick(View v) {
                  clickListener.launchIntent(data.get(getAdapterPosition()).films.get(0));
              }
          });
      }
  }

  public interface ClickListener {
      void launchIntent(String filmName);
  }

  public void setData(List<StarWars.People> data) {
      this.data.addAll(data);
      notifyDataSetChanged();
  }
}

下面给出了DetailActivity.java类的代码:

package com.theitroad.dagger2retrofitrecyclerview.ui;

import android.content.Context;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.widget.TextView;

import com.theitroad.dagger2retrofitrecyclerview.MyApplication;
import com.theitroad.dagger2retrofitrecyclerview.R;
import com.theitroad.dagger2retrofitrecyclerview.di.component.ApplicationComponent;
import com.theitroad.dagger2retrofitrecyclerview.di.component.DaggerDetailActivityComponent;
import com.theitroad.dagger2retrofitrecyclerview.di.component.DetailActivityComponent;
import com.theitroad.dagger2retrofitrecyclerview.di.qualifier.ApplicationContext;
import com.theitroad.dagger2retrofitrecyclerview.pojo.Film;
import com.theitroad.dagger2retrofitrecyclerview.retrofit.APIInterface;

import javax.inject.Inject;

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

public class DetailActivity extends AppCompatActivity {

  DetailActivityComponent detailActivityComponent;

  @Inject
  public APIInterface apiInterface;

  @Inject
  @ApplicationContext
  public Context mContext;

  TextView textView;

  @Override
  protected void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.activity_detail);

      textView = findViewById(R.id.textView);

      String url = getIntent().getStringExtra("url");

      ApplicationComponent applicationComponent = MyApplication.get(this).getApplicationComponent();
      detailActivityComponent = DaggerDetailActivityComponent.builder()
              .applicationComponent(applicationComponent)
              .build();

      detailActivityComponent.inject(this);

      apiInterface.getFilmData(url, "json").enqueue(new Callback<Film>() {
          @Override
          public void onResponse(Call<Film> call, Response<Film> response) {
              Film films = response.body();
              String text = "Film name:\n" + films.title + "\nDirector:\n" + films.director;
              textView.setText(text);
          }

          @Override
          public void onFailure(Call<Film> call, Throwable t) {

          }
      });
  }
}

再次使用inject方法来注入所有依赖项字段。
改型向指定的动态URL发出请求,并在TextView中显示响应。