Android -- 帶你從源碼角度領悟Dagger2入門到放棄(三)

1, 前面兩篇文章咱們知道了怎麼使用經常使用的四種標籤,如今咱們結合咱們本身的項目中去簡單的使用java

  在咱們搭建項目的時候,通常會建立本身的Application,在裏面進行一些初始化如一些第三方的GreenDao、ShareSDK等等,再或者提供一些經常使用的屬性初始化:例如初始化屏幕的寬高度、初始化SPUtils工具類等,因此咱們能夠建立App類繼承自Application(這裏我只寫了簡單的App對象建立,沒有寫其餘的任何方法)android

package com.qianmo.rxjavatext;

import android.app.Application;

/**
 * Created by Administrator on 2017/4/21 0021.
 * E-Mail:543441727@qq.com
 */

public class App extends Application {

    public static App instance;

    public static synchronized App getInstance() {
        return instance;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        instance = this;
    }
}

  通常狀況下咱們使用不少狀況下會使用到上下文環境,而使用Activity的上下文環境會容易發生內存泄漏問題,即該Activity本應該被銷燬,但由於外部類持有context對象的引用而致使沒法回收Activity,因此這裏咱們通常使用App中的上下文,這時候咱們要向全部的activity提供一個Application的上下文環境對象,再結合咱們以前學習的Dagger2知識,先寫一下AppModule提供對象的代碼app

package com.qianmo.rxjavatext.di;


import com.qianmo.rxjavatext.App;

import javax.inject.Singleton;

import dagger.Module;
import dagger.Provides;

/**
 * Created by Administrator on 2017/4/21 0021.
 * E-Mail:543441727@qq.com
 */

@Module
public class AppModule {
    public final App application;

    public AppModule(App application) {
        this.application = application;
    }

    @Provides
    @Singleton
    App provideApplicationContext() {
        return application;
    }
}

  很簡單,就是在建立AppModule對象的時候將App對象傳遞進來,而後添加provideApplicationContext暴露app對象出去,再來看看AppComponent類ide

package com.qianmo.rxjavatext.di;

import com.qianmo.rxjavatext.App;

import javax.inject.Singleton;

import dagger.Component;

/**
 * Created by Administrator on 2017/4/21 0021.
 * E-Mail:543441727@qq.com
 */
@Singleton
@Component(modules = AppModule.class)
public interface AppComponent {

    //向下層提供上下文環境
    App getContext();

}

  這裏可能你們有個疑問App getContext();這句代碼是幹什麼的,咱們知道Activity中有可能要使用到App上下文環境(雖然這個方法不必定能用到,可是咱們仍是準備着),這裏就是給下層提供這個對象的。那麼咱們須要在App初始化這個AppComponent對象了函數

public class App extends Application {

    public static App instance;
    public static AppComponent appComponent;

    public static synchronized App getInstance() {
        return instance;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        instance = this;
    }

    public static AppComponent getAppComponent() {
        if (appComponent == null) {
            appComponent = DaggerAppComponent.builder().appModule(new AppModule(instance)).build();
        }
        return appComponent;
    }
}

  那麼有同窗就會有這個疑問什麼叫「下層」,用什麼表示上下層關係,這裏給出的解釋是當另外一個Activity中的module也想擁有咱們的上下文application對象呢?是還要想咱們的AppModule同樣嗎?nonono,這是咱們使用dependencies,首先建立Activity的Module,這個類很簡單就是提供咱們的activity對象,因此代碼以下工具

package com.qianmo.rxjavatext.di;

import android.app.Activity;

import com.qianmo.rxjavatext.di.scope.ActivityScope;

import javax.inject.Singleton;

import dagger.Module;
import dagger.Provides;

/**
 * Created by Administrator on 2017/4/21 0021.
 * E-Mail:543441727@qq.com
 */
@Module
public class ActivityModule {
    private Activity mActivity;

    public ActivityModule(Activity mActivity) {
        this.mActivity = mActivity;
    }

    @Provides
    @ActivityScope
    Activity provideActivity() {
        return mActivity;
    }
}

  這裏的@ActivityScope就是咱們上一篇學習的自定義Scope註解標籤,沒什麼難的,再看看咱們的ActivityComponent學習

package com.qianmo.rxjavatext.di;

import android.app.Activity;

import com.qianmo.rxjavatext.MainActivity;
import com.qianmo.rxjavatext.di.scope.ActivityScope;


import dagger.Component;

/**
 * Created by Administrator on 2017/4/21 0021.
 * E-Mail:543441727@qq.com
 */
@ActivityScope
@Component(dependencies = AppComponent.class,modules = ActivityModule.class)
public interface ActivityComponent {

    //將當前的activity暴露出去
    Activity getActivity();

    void inject(MainActivity mainActivity);
}

  dependencies 關鍵字就是這樣使用的 ,例如咱們建立student對象,須要App的對象(固然這個需求在現實中是不成立的),咱們就能夠這樣寫Moduleui

package com.qianmo.rxjavatext.di;

import android.app.Activity;
import android.content.Context;

import com.qianmo.rxjavatext.Student;
import com.qianmo.rxjavatext.di.scope.ActivityScope;

import javax.inject.Singleton;

import dagger.Module;
import dagger.Provides;

/**
 * Created by Administrator on 2017/4/21 0021.
 * E-Mail:543441727@qq.com
 */
@Module
public class ActivityModule {
    private Activity mActivity;

    public ActivityModule(Activity mActivity) {
        this.mActivity = mActivity;
    }

    @Provides
    @ActivityScope
    Activity provideActivity() {
        return mActivity;
    }

    @Provides
    Student provideStudent(App app) {
        return new Student(app);
    }
}

  咱們按Ctrl+F9編譯一下,發現咱們的程序能夠編譯過來,正常的話不是應該報錯誤說App沒有注入對象嗎,爲何這裏是能夠運行,這就是dependencies 關鍵字的用法了,這裏咱們使用的是AppComponent中的getContext方法的app對象了。this

  OK,這裏咱們在activity中開始調用試試建立Student對象,看看能不能拿到值spa

package com.qianmo.rxjavatext;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;

import com.jakewharton.rxbinding.view.RxView;
import com.jakewharton.rxbinding.widget.RxCompoundButton;
import com.qianmo.rxjavatext.di.ActivityComponent;
import com.qianmo.rxjavatext.di.ActivityModule;
import com.qianmo.rxjavatext.di.DaggerActivityComponent;

import java.util.Collections;
import java.util.List;
import java.util.concurrent.TimeUnit;

import javax.inject.Inject;

import rx.Observable;
import rx.Subscriber;
import rx.android.schedulers.AndroidSchedulers;
import rx.functions.Action0;
import rx.functions.Action1;
import rx.functions.Func1;
import rx.schedulers.Schedulers;

public class MainActivity extends AppCompatActivity {
    //須要一個Student對象
    @Inject
    Student mStudent;

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

    }

    //開始註解
    public void initInject() {
        getActivityComponent().inject(this);
    }

    protected ActivityComponent getActivityComponent() {
        return DaggerActivityComponent.builder()
                .appComponent(App.getAppComponent())
                .activityModule(getActivityModule())
                .build();
    }

    protected ActivityModule getActivityModule() {
        return new ActivityModule(this);
    }
}

  運行一下看一下打印結果

04-21 05:36:19.510 2646-2646/com.qianmo.rxjavatext I/System.out: 打印上下文對象呀com.qianmo.rxjavatext.App@34877b0

  沒問題,說明咱們的程序沒問題,可是在實際項目中咱們都是要編寫BaseActivity的,因此咱們須要在BaseActivity中這樣寫

public abstract class BaseActivity<T extends BasePresenter> extends AppCompatActivity implements BaseView {

    @Inject
    protected T mPresenter;

    protected void onCreate(@Nullable Bundle savedInstanceState) {
       
        super.onCreate(savedInstanceState);
        setContentView(getLayout());

        initInject();
        if (mPresenter != null)
            mPresenter.attachView(this);
        App.getInstance().addActivity(this);
        initEventAndData();
    }

    @Override
    protected void onStart() {
        super.onStart();

    }

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


    /**
     * 添加註解
     */
    protected abstract void initInject();

    protected abstract int getLayout();

    protected abstract void initEventAndData();


    protected ActivityComponent getActivityComponent(){
        return  DaggerActivityComponent.builder()
                .appComponent(App.getAppComponent())
                .activityModule(getActivityModule())
                .build();
    }

    protected ActivityModule getActivityModule(){
        return new ActivityModule(this);
    }
}

  這裏的BaseView和BasePresenter都是咱們的MVP的基類,裏面很簡單的沒有說明代碼的,咱們在具體的activity中怎麼使用呢?首先建立MainActivity,在這裏調用 mPresenter.attachView(new MainView())方法

package com.qianmo.rxjavatext.mvp.view;

import com.qianmo.rxjavatext.R;
import com.qianmo.rxjavatext.base.BaseActivity;
import com.qianmo.rxjavatext.mvp.presenter.MainPresenterImpl;

/**
 * Created by Administrator on 2017/4/21 0021.
 * E-Mail:543441727@qq.com
 */

public class SecondActivity extends BaseActivity<MainPresenterImpl> {

    @Override
    public void showError(String msg) {

    }

    @Override
    public void useNightMode(boolean isNight) {

    }

    @Override
    protected void initInject() {
        getActivityComponent().inject(this);
    }

    @Override
    protected int getLayout() {
        return R.layout.activity_main;
    }

    @Override
    protected void initEventAndData() {
        mPresenter.attachView(new MainView());
    }
}

  再看看重要的MainPresenterImpl類

package com.qianmo.rxjavatext.mvp.presenter;

import android.content.Context;
import android.widget.Toast;


import com.qianmo.rxjavatext.App;
import com.qianmo.rxjavatext.base.BasePresenter;
import com.qianmo.rxjavatext.mvp.view.MainView;

import javax.inject.Inject;

import rx.Observable;
import rx.Subscriber;
import rx.Subscription;


/**
 * Created by MVPHelper on 2016/11/08
 */

public class MainPresenterImpl implements BasePresenter<MainView> {

    private Context context;

    @Inject
    public MainPresenterImpl(App app) {
        this.context = app;
    }


    @Override
    public void attachView(MainView view) {
        Toast.makeText(context, "獲取到值了", Toast.LENGTH_SHORT).show();
    }

    @Override
    public void detachView() {

    }
}

  在這裏最關鍵的標註了構造函數MainPresenterImpl,這樣咱們就註解到了該presenter對象了,看一下效果,ok,基本上咱們就是在MVP工程下註解presenter對象了,關鍵是封裝!!!(若是你封裝很好了,後面開發使用就很簡單,並且也不用單獨的寫一些Module、component類)

  最後,說一下使用範圍對於中小型的項目真心不必使用Dagger2,還有若是你是Android負責人的話,你還要考慮一下你的Android同事他們上手Dagger2的狀況,因此這裏仍是要試開發狀況定(感受這一片仍是沒和你們在項目封裝的時候講清楚啊,關鍵是封裝是Dagger兩個都是不容易上手的,麻蛋,本身思路寫的也混亂了,祝你們早日拖坑)。

相關文章
相關標籤/搜索