Android MVP和Dagger2

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

在本教程中,我们将在Android应用程序中与Dagger2一起实现MVP模式。
建议一起使用这些设计模式概念之前,分别进行探讨。

Android MVP和Dagger2

我们知道,MVP是基于关注点分离的。
MVP模式将我们的代码分为三层-模型,视图和演示者。

演示者充当模型和视图之间的桥梁。
没有演示者,模型和视图将无法相互通信。

演示者模型,演示者视图使用接口进行通信。

Dagger2是Square开发的依赖注入库。
我们没有在类中创建依赖关系,而是通过使用Dagger2核心结构-"模块","组件","注入"和"提供"来提供依赖。

使用Dagger2批注,编译器会在编译时自动构建Dagger类。

MVP + Dagger2 =开始我们的旅程,以遵循SOLID原则编写简洁的代码。

因此,在以下部分中,我们将从本教程的MVP Android Studio项目中使用Dagger2。
这将使我们更清楚Dagger2如何与MVP配合使用。

Android MVP Dagger2项目结构

模型–项目的模型类。

视图–我们的活动就是这里的视图。

Presenter – Presenter类,它最终告诉Activity如何处理View。

MainContract.java –包括模型,视图和演示者的接口。

di –包括依赖项注入– Dagger2类。

不要忘记在build.gradle文件中添加以下依赖项。

annotationProcessor 'com.google.dagger:dagger-compiler:2.13'
implementation 'com.google.dagger:dagger:2.13'

Android MVP Dagger2代码

让我们看看在MainContract.java类中为MVP类定义的接口。

package com.theitroad.mvpdagger2;
public interface MainContract {

  interface ViewCallBack {
      void showProgress();

      void hideProgress();

      void setQuote(String string);
  }

  interface ModelCallBack {
      interface OnFinishedListener {
          void onFinished(String string);
      }

      void getNextQuote(OnFinishedListener onFinishedListener);
  }

  interface PresenterCallBack {
      void onButtonClick();

      void onDestroy();
  }
}

因此,视图具有用于设置字符串,显示或者隐藏ProgressBar的界面。

该模型具有一个onFinished接口,该接口在处理程序间隔成功之后触发。

演示者控制活动按钮的单击和onDestroy()生命周期。

模型

package com.theitroad.mvpdagger2.model;

import android.os.Handler;

import com.theitroad.mvpdagger2.MainContract;

import java.util.Arrays;
import java.util.List;
import java.util.Random;

public class Model implements MainContract.ModelCallBack {

  @Override
  public void getNextQuote(final MainContract.ModelCallBack.OnFinishedListener listener) {
      new Handler().postDelayed(new Runnable() {
          @Override
          public void run() {
              listener.onFinished(getRandomQuote());
          }
      }, 1200);
  }

  private List<String> arrayList = Arrays.asList(
          "Be yourself. everyone else is already taken.",
          "A room without books is like a body without a soul.",
          "You only live once, but if you do it right, once is enough.",
          "Be the change that you wish to see in the world.",
          "If you tell the truth, you don't have to remember anything."
  );

  private String getRandomQuote() {

      Random random = new Random();
      int index = random.nextInt(arrayList.size());
      return arrayList.get(index);
  }
}

演示者实现在MainPresenterImpl.java类中定义。

package com.theitroad.mvpdagger2.presenter;

import com.theitroad.mvpdagger2.MainContract;
import com.theitroad.mvpdagger2.model.Model;

public class MainPresenterImpl implements MainContract.PresenterCallBack, MainContract.ModelCallBack.OnFinishedListener {

  private MainContract.ViewCallBack mainView;
  private Model model;

  public MainPresenterImpl(MainContract.ViewCallBack mainView, Model model) {
      this.mainView = mainView;
      this.model = model;
  }

  @Override
  public void onButtonClick() {
      if (mainView != null) {
          mainView.showProgress();
      }
      model.getNextQuote(this);
  }

  @Override
  public void onDestroy() {
      mainView = null;
  }

  @Override
  public void onFinished(String string) {
      if (mainView != null) {
          mainView.setQuote(string);
          mainView.hideProgress();
      }
  }
}

迪包

在di包中,我们定义了依赖项注入模块和组件。

我们先来看一下模块。

AppModule.java

package com.theitroad.mvpdagger2.di.module;

import android.app.Application;

import com.theitroad.mvpdagger2.InitApplication;

import javax.inject.Singleton;

import dagger.Module;
import dagger.Provides;

@Module
public class AppModule {

  private InitApplication initApplication;

  public AppModule(InitApplication initApplication) {
      this.initApplication = initApplication;
  }

  @Provides
  @Singleton
  public Application provideApplication() {
      return initApplication;
  }
}

这在整个项目中提供了一个应用程序实例。

ContextModule.java

package com.theitroad.mvpdagger2.di.module;

import android.content.Context;
import dagger.Module;
import dagger.Provides;

@Module
public class ContextModule {
  private Context context;

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

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

提供getApplicationContext()

DataModule.java

package com.theitroad.mvpdagger2.di.module;

import com.theitroad.mvpdagger2.model.Model;

import dagger.Module;
import dagger.Provides;

@Module
public class DataModule {

  @Provides
  public Model provideModelClass() {
      return new Model();
  }
}

这为我们提供了Model类的实例。

MvpModule.java

package com.theitroad.mvpdagger2.di.module;

import com.theitroad.mvpdagger2.MainContract;
import com.theitroad.mvpdagger2.model.Model;
import com.theitroad.mvpdagger2.presenter.MainPresenterImpl;

import dagger.Module;
import dagger.Provides;

@Module
public class MvpModule {

  private MainContract.ViewCallBack viewCallBack;

  public MvpModule(MainContract.ViewCallBack viewCallBack) {
      this.viewCallBack = viewCallBack;
  }

  @Provides
  public MainContract.ViewCallBack provideView() {
      return viewCallBack;
  }

  @Provides
  public MainContract.PresenterCallBack providePresenter(MainContract.ViewCallBack view, Model model) {
      return new MainPresenterImpl(view, model);
  }
}

这提供了MainPresenterImpl.java类的实例。

它使用View的界面和Model类作为构造函数参数。

ActivityScope.java

package com.theitroad.mvpdagger2.di.scope;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

import javax.inject.Scope;

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

这将设置组件的范围,我们将在后面看到。

AppComponent.java

package com.theitroad.mvpdagger2.di.component;

import android.app.Application;
import android.content.Context;

import com.theitroad.mvpdagger2.InitApplication;
import com.theitroad.mvpdagger2.di.module.AppModule;
import com.theitroad.mvpdagger2.di.module.ContextModule;
import com.theitroad.mvpdagger2.di.module.DataModule;
import com.theitroad.mvpdagger2.model.Model;

import javax.inject.Singleton;

import dagger.Component;

@Singleton
@Component(modules = {AppModule.class, DataModule.class, ContextModule.class})
public interface AppComponent {
  void inject(InitApplication initApplication);

  Context getContext();

  Model getFindItemsInteractor();

  Application getApplication();
}

这是应用程序级组件。
在整个应用程序中都可以访问这些字段。

ActivityComponent.java

package com.theitroad.mvpdagger2.di.component;

import com.theitroad.mvpdagger2.MainContract;
import com.theitroad.mvpdagger2.di.module.MvpModule;
import com.theitroad.mvpdagger2.di.scope.ActivityScope;
import com.theitroad.mvpdagger2.view.MainActivity;

import dagger.Component;

@ActivityScope
@Component(dependencies = AppComponent.class, modules = MvpModule.class)
public interface ActivityComponent {
  void inject(MainActivity mainActivity);

  MainContract.PresenterCallBack getMainPresenter();
}

该组件用于将Presenter注入到我们的MainActivity中。

下面给出了InitApplication.java的代码:

package com.theitroad.mvpdagger2;

import android.app.Application;
import android.content.Context;
import com.theitroad.mvpdagger2.di.component.AppComponent;
import com.theitroad.mvpdagger2.di.component.DaggerAppComponent;
import com.theitroad.mvpdagger2.di.module.AppModule;
import com.theitroad.mvpdagger2.di.module.ContextModule;
import com.theitroad.mvpdagger2.di.module.DataModule;

public class InitApplication extends Application {

  private AppComponent component;

  public static InitApplication get(Context context) {
      return (InitApplication) context.getApplicationContext();
  }

  @Override
  public void onCreate() {
      super.onCreate();
      component = DaggerAppComponent.builder()
              .appModule(new AppModule(this))
              .contextModule(new ContextModule(this))
              .dataModule(new DataModule())
              .build();
  }

  public AppComponent component() {
      return component;
  }
}

下面给出了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"
  android:layout_width="match_parent"
  android:layout_height="match_parent">

  <TextView
      android:id="@+id/textView"
      android:layout_width="0dp"
      android:layout_height="wrap_content"
      android:gravity="center"
      android:padding="8dp"
      android:text="Implementing MVP and Dagger2 in this Application."
      android:textAppearance="?android:attr/textAppearanceSearchResultTitle"
      app:layout_constraintBottom_toBottomOf="parent"
      app:layout_constraintLeft_toLeftOf="parent"
      app:layout_constraintRight_toRightOf="parent"
      app:layout_constraintTop_toTopOf="parent" 

  <Button
      android:id="@+id/button"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:layout_margin="@android:dimen/notification_large_icon_height"
      android:text="GET NEXT QUOTE"
      app:layout_constraintLeft_toLeftOf="parent"
      app:layout_constraintRight_toRightOf="parent"
      app:layout_constraintTop_toBottomOf="@+id/textView" 

  <ProgressBar
      android:id="@+id/progressBar"
      style="?android:attr/progressBarStyleLarge"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:visibility="gone"
      app:layout_constraintBottom_toBottomOf="parent"
      app:layout_constraintLeft_toLeftOf="parent"
      app:layout_constraintRight_toRightOf="parent"
      app:layout_constraintTop_toTopOf="parent" 

</android.support.constraint.ConstraintLayout>

MainActivity.java类的代码如下:

package com.theitroad.mvpdagger2.view;

import android.content.Context;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;

import com.theitroad.mvpdagger2.InitApplication;
import com.theitroad.mvpdagger2.MainContract;
import com.theitroad.mvpdagger2.R;
import com.theitroad.mvpdagger2.di.component.DaggerActivityComponent;
import com.theitroad.mvpdagger2.di.module.MvpModule;

import javax.inject.Inject;

import static android.view.View.GONE;

public class MainActivity extends AppCompatActivity implements MainContract.ViewCallBack {

  @Inject
  MainContract.PresenterCallBack presenterCallBack;

  @Inject
  Context mContext;

  private TextView textView;
  private ProgressBar progressBar;

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

      DaggerActivityComponent.builder()
              .appComponent(InitApplication.get(this).component())
              .mvpModule(new MvpModule(this))
              .build()
              .inject(this);

      textView = findViewById(R.id.textView);
      Button button = findViewById(R.id.button);
      progressBar = findViewById(R.id.progressBar);

      button.setOnClickListener(new View.OnClickListener() {
          @Override
          public void onClick(View v) {
              presenterCallBack.onButtonClick();
          }
      });
  }

  @Override
  protected void onResume() {
      super.onResume();
  }

  @Override
  protected void onDestroy() {
      super.onDestroy();
      presenterCallBack.onDestroy();
  }

  @Override
  public void showProgress() {
      progressBar.setVisibility(View.VISIBLE);
      textView.setVisibility(View.INVISIBLE);
  }

  @Override
  public void hideProgress() {
      progressBar.setVisibility(GONE);
      textView.setVisibility(View.VISIBLE);
  }

  @Override
  public void setQuote(String string) {
      textView.setText(string);
      Toast.makeText(mContext, "Quote Updated", Toast.LENGTH_SHORT).show();
  }
}

瞧!我们将Presenter注入到这里而不实例化它。
多亏了Dagger2。