Dagger2-Android基本使用(一)

一、前言:

gitHub 地址:https://github.com/lyyRunning/DaggerAndroid

1. Dagger2的缺點

在使用Dagger2進(jìn)行Android開發(fā)時,不可避免的問題是我們需要實例化一些Android系統(tǒng)的類,比如Activity或者Fragment。最理想的情況是Dagger能夠創(chuàng)建所有需要依賴注入的對象,但事實上,我們不得不在容器的聲明周期中聲明這樣的代碼:

public class FrombulationActivity extends Activity {
  @Inject Frombulator frombulator;

  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    // DO THIS FIRST. Otherwise frombulator might be null!
    ((SomeApplicationBaseType) getContext().getApplicationContext())
        .getApplicationComponent()
        .newActivityComponentBuilder()
        .activity(this)
        .build()
        .inject(this);
    // ... now you can write the exciting code
  }
}

這樣的確可以實現(xiàn)Android的依賴注入,但還有兩個問題需要我們?nèi)ッ鎸Γ?/p>

  1. 類似的復(fù)制性的代碼以后會很難維護(hù)。而且隨著越來越多的開發(fā)者去復(fù)制粘貼這些代碼,很少會有人知道它的作用。
  2. 更重要的是,它要求注射類型(FrombulationActivity)知道其注射器。 即使這是通過接口而不是具體類型完成的,它打破了依賴注入的核心原則:一個類不應(yīng)該知道如何實現(xiàn)依賴注入。

瑕不掩瑜,雖然Dagger2在Android開發(fā)中有一些問題,但是它強(qiáng)大的功能依然使得開發(fā)人員趨之若鶩,無數(shù)的工程師們嘗試彌補(bǔ)Dagger的這個問題,于是Dagger2-Android,基于Dagger2,應(yīng)用于Android開發(fā),由google開發(fā)的的拓展庫應(yīng)運(yùn)而生。

二、基本使用:

1. 依賴

//一定要添加dagger2的annotationProcessor!
annotationProcessor 'com.google.dagger:dagger-compiler:2.11' 
compile 'com.google.dagger:dagger-android:2.11'
//使用支持的類庫
compile 'com.google.dagger:dagger-android-support:2.11' 
annotationProcessor 'com.google.dagger:dagger-android-processor:2.11 '

注意:依賴的包單引號一定要成對。

2. 先看看Demo效果

image.png

結(jié)構(gòu)如下:


image.png

可以看到,我們在MainActivity中需要通過依賴注入,獲得4個對象,同時MainPresenter和MainModel也同樣得到了實例化,我們先看下MVP這個架構(gòu)中三個成員的代碼:

三、詳細(xì)代碼相關(guān):

1. MyApplication 代碼:

我們先聲明我們的Application類,然后記得一定要記得添加到清單文件中:

public class MyApplication  extends Application implements HasActivityInjector {

    @Inject
    DispatchingAndroidInjector<Activity> dispatchingAndroidInjector;

    @Override
    public void onCreate() {
        super.onCreate();
        //全局注入
        DaggerAppComponent.create().inject(this);

    }

    @Override
    public AndroidInjector<Activity> activityInjector() {
        return dispatchingAndroidInjector;
    }

}

我們在這里做了幾件事:

  1. 實現(xiàn)HasActivityInjector接口
  2. 實現(xiàn)HasActivityInjector接口的activityInjector()方法
  3. 聲明一個泛型為Activity的DispatchingAndroidInjector成員變量并在activityInjector()方法中返回

注意:我們要先寫AppComponent接口,然后編譯,才能讓編譯器自動生成DaggerAppComponent類。

2. AppComponent 代碼:

/**
 * Created by luo on 2019/8/7.
 * 全局的快遞員
 */
@Component(modules = {AndroidInjectionModule.class,
        AndroidSupportInjectionModule.class,
        AppModule.class})
public interface AppComponent {
    void inject(MyApplication application);
}

我們在這里做了幾件事:

  1. 在這個Component中添加了 AndroidInjectionModule 和 AndroidSupportInjectionModule
  2. 同時添加了MainActivityModule 和 SecondActivityModule的依賴
  3. 聲明注入方法inject,參數(shù)類型為MyApplication

3. MainACtivity 代碼:

/**
 * Created by luo on 2019/8/7.
 * 整個 APP 統(tǒng)一的 Moudle,類似大箱子
 *
 */
@Module
public abstract class AppModule {

    /**
     * 引入MainActivityModule
     * @return
     */
    @ActivityScope
    @ContributesAndroidInjector(modules = MainActivityModule.class)
    abstract MainActivity contributeMainActivityInject();

    /**
     * 引入SecondActivityModule
     * @return
     */
    @ActivityScope
    @ContributesAndroidInjector(modules = SecondActivityModule.class)
    abstract SecondActivity contributeSecondActivityInject();

}

4. MainACtivity 代碼:

public class MainActivity extends BaseActivity implements MainContract.View {

    @Inject
    String className;
    @Inject
    SharedPreferences sp;
    @Inject
    MainPresenter presenter;
    @Inject
    Student s1;
    @Inject
    Student s2;

    @BindView(R.id.tv_content)
    TextView tvContent;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ButterKnife.bind(this);
        tvContent.setText(className + "\n" +
                s2.toString() + "\n" +
                s1.toString() + "\n" +
                sp.toString()
        );
    }


    public void gotoSecond(View view) {
        startActivity(new Intent(this, SecondActivity.class));
    }

    public void requestHttp(View view) {
        presenter.requestHttp();
    }

    /**
     * 返回數(shù)據(jù)
     *
     * @param message
     */
    public void onGetMessage(String message) {
        Toast.makeText(this, message, Toast.LENGTH_SHORT).show();
    }
}

顯然,從結(jié)果來看,我們根本沒有在Activity中添加上文所述的模板代碼:

//就是這些,模板代碼
    ((SomeApplicationBaseType) getContext().getApplicationContext())
        .getApplicationComponent()
        .newActivityComponentBuilder()
        .activity(this)
        .build()
        .inject(this);

5. MainContract代碼:

public interface MainContract {

    public interface View {

    }

    public interface Presenter {

    }

    public interface Model {

    }
}

6. MainContract代碼:

public class MainPresenter implements MainContract.Presenter {

    private final MainActivity view;
    private final MainModel model;

    @Inject
    public MainPresenter(MainActivity view, MainModel model) {
        this.view = view;
        this.model = model;
    }

    public void requestHttp() {
        view.onGetMessage(model.returnMessage());
    }
}

7. MainModel代碼:

public class MainModel implements MainContract.Model {

    @Inject
    public MainModel() {
    }

    public String returnMessage() {
        return "小明";
    }
}

和Dagger2的使用沒有區(qū)別,其根本原理,都是通過@Inject注解,使Dagger2自動生成對應(yīng)的工廠類,以提供MainPresenter和MainModel的實例。

8. MainActivityModule代碼:

@Module
public class MainActivityModule {


    @Provides
    static String provideName() {
        return MainActivity.class.getName();
    }

    @Provides
    static SharedPreferences provideSp(MainActivity activity) {
        return activity.getSharedPreferences("def", Context.MODE_PRIVATE);
    }

    @Provides
    @ActivityScope
    static Student provideStudent() {
        return new Student();
    }
}

9. ActivityScope代碼:

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

10. SecondActivity代碼:

public class SecondActivity extends BaseActivity {

    @Inject
    String className;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_second);
        TextView tv = (TextView) findViewById(R.id.tv_content);
        tv.setText(className);
    }
}

和MainActivity基本一樣,為了簡便我們只注入了一個String,用來展示類名。

可以看到,我們依然沒有添加冗余的模板代碼,試想,一個app中這樣幾十個Activity容器都不需要這樣的模板代碼,我們的工作量確實減少了很多,同時,也達(dá)到了我們的目的,即:

依賴注入的核心原則:一個類不應(yīng)該知道如何實現(xiàn)依賴注入。

實際上,我們只是在BaseActivity中,添加了這樣一行代碼,就實現(xiàn)了我們想要的效果

11. BaseActivity代碼:

public class BaseActivity extends AppCompatActivity {
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        //一處聲明,處處依賴注入
        AndroidInjection.inject(this);
        super.onCreate(savedInstanceState);
    }
}

接下來,讓我們看看Dagger2-Android 的Module和Component怎么寫

參考:谷歌官方Demo https://google.github.io/dagger//android.html

12. SecondActivityModule代碼:

/**
 * Created by luo on 2019/8/7.
 * 對應(yīng)每一個 Activity 的小箱子
 */
@Module
public class SecondActivityModule {
    @Provides
    static String provideName(){
        return SecondActivity.class.getName();
    }
}

好的,所有配置全部結(jié)束,我們使用ctrl+F9(Mac:cmd+F9)進(jìn)行編譯,運(yùn)行app,依賴注入成功。

四、總結(jié):

注意:除Activity之外,Dagger-Android還提供了Fragment,BroadCast,Service等其他組件的注入方式,詳情請參照官方網(wǎng)站,本文不贅述。

https://google.github.io/dagger//android.html

簡述如下:

  1. AppComponent 的module : AllActivity的Module,其負(fù)責(zé)所有ActivityModule實例的管理
  2. AppComponent 為 AllActivity 的 Module 的 subcomponent,管理了提供各activity所需對象的module
  3. MainActivityModule 負(fù)責(zé)提供所有對應(yīng)Activity所需要對象實例的提供。

參考作者:卻把清梅嗅
鏈接:http://www.lxweimin.com/p/917bf39cae0d

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。