Android Dagger 2 +改装+ RecyclerView

This is the one stop complete tutorial for implementing Dagger 2 with Retrofit and RecyclerView in our Android Application.
Dagger 2 is a dependency injection library that’s vital for clean code and architecture. For a basic overview of Dependency Injection and Dagger 2 refer this tutorial before proceeding ahead.

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

什么是依赖注入? (What is Dependency Injection?)

Dependency Injection simply put, instead of creating instances yourself using the new keyword, you’ll be provided those instances from outside.
简单地说,Dependency Injection,而不是您自己使用new关键字创建实例,而是从外部为您提供了这些实例。

Dependency Injection is our friend in the worst and best times. It helps in refactoring the code quickly and helps in testing individual things since nothing is tightly coupled. It enhances the readability and maintainability.
Regardless, of the knowledge of Dependency Injection, at some point in your Object Oriented Programming, you have definitely used it. Following example will definitely remind you of it.

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

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);
    }
}

Class A is a dependent. Class E and B are dependencies that are injected.
As you can see in the above code, instead of initializing classes in the constructors, we do them separately. Though we still have the boilerplate code above.

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

有关Dagger 2的重要注意事项 (Important Points to note about Dagger 2)

  • It checks and draws the dependency object graph at compile-time.

    它在编译时检查并绘制依赖对象图。
  • We need to use the annotations : @Module, @Provides, @Inject, @Component @Scope.

    我们需要用注释: @Module@Provides@Inject@Component @Scope
  • For two dependencies that conflict, such as Application has a different Context and an Activity has a different. Dagger 2 needs @Qualifier our @Named annotations to differentiate.

    对于两个有冲突的依赖项,例如Application具有不同的Context,而Activity具有不同的。 Dagger 2需要@Qualifier我们的@Named批注进行区分。
  • @Component is set on an interface. It acts as a bridge and is used to provide the dependencies specified in the @Module to the Java class. The dependency would be retrieved with @Inject in our Java class.

    @Component在接口上设置。 它充当桥梁,用于将@Module指定的依赖项提供给Java类。 依赖关系将在我们的Java类中使用@Inject检索。
  • Dagger 2 cannot inject private fields.

    Dagger 2无法注入私有字段。

Dagger 2 is best understood through an example. It’s been a while and we’ve tried to create an Android Application that explains the concepts in the best possible way using RecyclerView and Retrofit.
We’ll be using the StarWars API.
Let’s dive deep!

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

项目结构 (Project Structure)

That’s big! We created a separate package di for dependency injection components, modules, scopes and qualifiers. The activities go into the ui package. The API method and POJO class are inside the retrofit and pojo packages respectively. The adapter holds the RecyclerViewAdapter class.
This project consists of two activities – MainActivity and DetailActivity.

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

Add the following library dependencies inside the app’s build.gradle.

在应用程序的build.gradle添加以下库依赖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'

Ensure that you’ve added the the Internet Permissions in your AndroidManifest file.

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

依赖注入程序包

范围

(Dependency Injection package

scopes

)

Scopes define where all those Components would be used. In this application, their are two : ActivityScope and ApplicationScope.

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

ActivityScope.java

ActivityScope.java

package com.journaldev.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

ApplicationScope.java

package com.journaldev.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 and @ApplicationScope would be used on the Components later on.

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

限定词 (qualifiers)

So, a Context can be either of the Activity or the Application. How would Dagger2 differentiate between them?
Using Qualifiers.

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

The ActivityContext.java and the ApplicationContext.java classes are defined below.

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

package com.journaldev.dagger2retrofitrecyclerview.di.qualifier;

import javax.inject.Qualifier;

@Qualifier
public @interface ActivityContext {

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

import javax.inject.Qualifier;


@Qualifier
public @interface ApplicationContext {

}

Now in the Modules wherever we use Context, we must annotate it with @ApplicationContext or @ActivityContext depending on the use case.

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

模组 (Modules)

Modules are what would provide the dependencies to the dependents via Components.
Let’s plan out our Dependency Graph first.

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

So the APIInterface isn’t dependent on anything.
The ApplicationComponent would hold the Retrofit and AppContext Modules.
The MainActivity would hold the Adapter and Activity Context Modules along with the ApplicationComponent’s dependencies.
The DetailActivityComponent doesn’t include any of its own modules. It just uses the ones present in the ApplicationComponent.

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

上下文模块 (ContextModule)

package com.journaldev.dagger2retrofitrecyclerview.di.module;

import android.content.Context;


import com.journaldev.dagger2retrofitrecyclerview.di.qualifier.ApplicationContext;
import com.journaldev.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;
    }
}

We’ve specified the Application Level scope and qualifier for the context.

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

改造模块 (RetrofitModule)

package com.journaldev.dagger2retrofitrecyclerview.di.module;


import com.journaldev.dagger2retrofitrecyclerview.di.scopes.ApplicationScope;
import com.journaldev.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 denotes that a dependency would be provided from that method to it’s dependents.
For Retrofit we use an ApplicationScope.

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

MainActivityContextModule (MainActivityContextModule)

package com.journaldev.dagger2retrofitrecyclerview.di.module;

import android.content.Context;

import com.journaldev.dagger2retrofitrecyclerview.di.qualifier.ActivityContext;
import com.journaldev.dagger2retrofitrecyclerview.di.scopes.ActivityScope;
import com.journaldev.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;
    }

}

The above module is used to provide the Activity Context and the Activity’s instance.

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

适配器模块 (AdapterModule)

The code for the AdapterModule is given below.

AdapterModule的代码如下。

package com.journaldev.dagger2retrofitrecyclerview.di.module;


import com.journaldev.dagger2retrofitrecyclerview.adapter.RecyclerViewAdapter;
import com.journaldev.dagger2retrofitrecyclerview.di.scopes.ActivityScope;
import com.journaldev.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;
    }
}

It’s used to create the RecyclerViewAdapter from the POJO data.
Also, the ClickListener is an interface defined in the RecyclerViewAdapter class to trigger the click listener callback methods from the Activity itself.
It injects the MainActivity dependency since we’ve included the MainActivityContextModule in the definition.

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

Let’s look at the APIInterface and the POJO classes.

让我们看一下APIInterface和POJO类。

The code for the APIInterface.java class is given below.

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

package com.journaldev.dagger2retrofitrecyclerview.retrofit;


import com.journaldev.dagger2retrofitrecyclerview.pojo.Film;
import com.journaldev.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 is used to do a dynamic URL call in Retrofit. The URL would be specified at runtime. @Url用于在Retrofit中进行动态URL调用。 该URL将在运行时指定。

The POJO classes are created from the .jsonschema2pojo.

POJO类是从.jsonschema2pojo创建的。

StarWars.java

StarWars.java

package com.journaldev.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;


    }

}

Film.java

Film.java

package com.journaldev.dagger2retrofitrecyclerview.pojo;

import com.google.gson.annotations.SerializedName;


public class Film {

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

}

We’re only parsing the values which we’ll be using in our application.

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

The star wars api looks like this:

android dagger2 retrofit recyclerview star wars api

星球大战api如下所示:

组件 (Components)

In the Components, we’ll include the Modules.
We’ll need to expose the fields that’ll be used in our Activity/Application.

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

ApplicationComponent.java

ApplicationComponent.java

package com.journaldev.dagger2retrofitrecyclerview.di.component;

import android.content.Context;

import com.journaldev.dagger2retrofitrecyclerview.MyApplication;
import com.journaldev.dagger2retrofitrecyclerview.di.module.ContextModule;
import com.journaldev.dagger2retrofitrecyclerview.di.module.RetrofitModule;
import com.journaldev.dagger2retrofitrecyclerview.di.qualifier.ApplicationContext;
import com.journaldev.dagger2retrofitrecyclerview.di.scopes.ApplicationScope;
import com.journaldev.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 would autogenerate a class named Dagger%ComponentName%. Eg. DaggerApplicationComponent.
injectApplication is used to allow @Inject fields in our Activity/Application.

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

MainActivityComponent.java

MainActivityComponent.java

package com.journaldev.dagger2retrofitrecyclerview.di.component;

import android.content.Context;


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

import dagger.Component;


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

    @ActivityContext
    Context getContext();


    void injectMainActivity(MainActivity mainActivity);
}

The above component would have access to the ApplicationComponent dependencies too.

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

DetailActivityComponent.java

DetailActivityComponent.java

package com.journaldev.dagger2retrofitrecyclerview.di.component;

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

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

    void inject(DetailActivity detailActivity);
}

Now is the time to use the di in our Activity’s and Application.
Let’s look at the layout codes first.

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

布局 (Layout)

activity_main.xml

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

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

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>

Before we use dependency injection in our classes, REBUILD THE PROJECT. This is done to generate the Dagger Component classes.

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

The code for the MyApplication.java class is given below.

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

package com.journaldev.dagger2retrofitrecyclerview;

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

import com.journaldev.dagger2retrofitrecyclerview.di.component.ApplicationComponent;
import com.journaldev.dagger2retrofitrecyclerview.di.component.DaggerApplicationComponent;
import com.journaldev.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(); is used to build the modules present in the component.
getApplicationComponent would be used to return the ApplicationComponent in our Activities.

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

Don’t forget to add the above application in our AndroidManifest.xml file.

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

UI包 (UI package)

The code for the MainActivity.java class is given below.

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

package com.journaldev.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.journaldev.dagger2retrofitrecyclerview.MyApplication;
import com.journaldev.dagger2retrofitrecyclerview.R;
import com.journaldev.dagger2retrofitrecyclerview.adapter.RecyclerViewAdapter;
import com.journaldev.dagger2retrofitrecyclerview.di.component.ApplicationComponent;
import com.journaldev.dagger2retrofitrecyclerview.di.component.DaggerMainActivityComponent;
import com.journaldev.dagger2retrofitrecyclerview.di.component.MainActivityComponent;
import com.journaldev.dagger2retrofitrecyclerview.di.module.MainActivityContextModule;
import com.journaldev.dagger2retrofitrecyclerview.di.qualifier.ActivityContext;
import com.journaldev.dagger2retrofitrecyclerview.di.qualifier.ApplicationContext;
import com.journaldev.dagger2retrofitrecyclerview.pojo.StarWars;
import com.journaldev.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));
    }
}

Once this happens: mainActivityComponent.injectMainActivity(this);, The fields present with the @Inject would be automatically injected.
The rest is doing a Retrofit call and setting the data in the RecyclerViewAdapter.
The class implements the RecyclerViewAdapter.ClickListener interface callback which triggers a launchIntent method whenever the RecyclerView row gets clicked.
Note that the Context injected needs to be specified with the relevant qualifier we had earlier defined.

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

The code for the RecyclerViewAdapter is given below.

下面给出了RecyclerViewAdapter的代码。

package com.journaldev.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.journaldev.dagger2retrofitrecyclerview.R;
import com.journaldev.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();
    }
}

The code for the DetailActivity.java class is given below:

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

package com.journaldev.dagger2retrofitrecyclerview.ui;

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

import com.journaldev.dagger2retrofitrecyclerview.MyApplication;
import com.journaldev.dagger2retrofitrecyclerview.R;
import com.journaldev.dagger2retrofitrecyclerview.di.component.ApplicationComponent;
import com.journaldev.dagger2retrofitrecyclerview.di.component.DaggerDetailActivityComponent;
import com.journaldev.dagger2retrofitrecyclerview.di.component.DetailActivityComponent;
import com.journaldev.dagger2retrofitrecyclerview.di.qualifier.ApplicationContext;
import com.journaldev.dagger2retrofitrecyclerview.pojo.Film;
import com.journaldev.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) {

            }
        });
    }
}

Again the inject method is used to inject all the dependency fields.
The retrofit makes a request to the dynamic URL specified and displays the response in a TextView.

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

The output of the above application in action is given below.

android dagger2 recyclerview retrofit output

下面给出了上面应用程序的输出。

This brings an end to this tutorial. You can download the full source code from the link below.

本教程到此结束。 您可以从下面的链接下载完整的源代码。

翻译自: https://www.journaldev.com/20405/android-dagger-2-retrofit-recyclerview

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值