Dagger2
真的不是一件简单的事情Dagger 1
:匕首 一个用于Android和Java的快速依赖注入。由SQUAR
公司开发Dagger 2
:由谷歌公司接手开发 Dagger 2Martin Flower
在解释介绍注入时使用的一部分代码来讲明这个问题public class MovieLister {
private MovieFinder finder;
public MovieLister() {
finder = new MovieFinderImpl();
}
public Movie[] moviesDirectedBy(String arg) {
List allMovies = finder.findAll();
for (Iterator it = allMovies.iterator(); it.hasNext();) {
Movie movie = (Movie) it.next();
if (!movie.getDirector().equals(arg)) it.remove();
}
return (Movie[]) allMovies.toArray(new Movie[allMovies.size()]);
}
...
}
复制代码
public interface MovieFinder {
List findAll();
}
复制代码
public class MovieLister {
private MovieFinder finder;
public MovieLister(MovieFinder finder) {
this.finder = finder;
}
...
}
复制代码
public class MovieLister {
s...
public void setFinder(MovieFinder finder) {
this.finder = finder;
}
}
复制代码
public interface InjectFinder {
void injectFinder(MovieFinder finder);
}
复制代码
class MovieLister implements InjectFinder {
...
public void injectFinder(MovieFinder finder) {
this.finder = finder;
}
...
}
复制代码
//dagger2
api "com.google.dagger:dagger:2.15"
compileOnly 'org.glassfish:javax.annotation:10.0-b28'
复制代码
@Module
public class ActivityModule {
private Activity mActivity;
public ActivityModule(Activity activity) {
mActivity = activity;
}
@Provides
Activity provideActivity() {
return mActivity;
}
@Provides
@ActivityContext
Context providesContext() {
return mActivity;
}
}
复制代码
IRemoteServer
,经过Retrofit获得,这个有个坏处,就是全部的接口请求信息都放在一个类了,后续应该根据项目的壮大,须要增长多个Server
@Module
public class ApplicationModule {
protected final HementApplication mApplication;
public ApplicationModule(HementApplication application) {
mApplication = application;
}
@Provides
Application provideApplication() {
return mApplication;
}
@Provides
@ApplicationContext
Context provideContext() {
return mApplication;
}
@Provides
@Singleton
IRemoteServer provideRibotsService() {
return IRemoteServer.Creator.newHementService();
}
}
复制代码
component
。ActivityComponent
代码以下:@PerActivity
@Subcomponent(modules = ActivityModule.class)
public interface ActivityComponent {
/**
* 注入activity
* @param mainActivity
*/
void inject(MainActivity mainActivity);
/**
* 每个类都得单独的注入
* @param baseActivity
*/
void inject(NetWorkActivity baseActivity);
void inject(SPreferencesActivity sPreferencesActivity);
void inject(DBNetWorkDemoActivity dbDemoActivity);
void inject(RxEventBusActivity rxEventBusActivity);
void inject(RxPermissionsActivity rxPermissionsActivity);
void inject(ImageLoaderActivity imageLoaderActivity);
}
复制代码
null
的问题?MainActivity
,而不能够写成其父类,好比Activity
。由于Dagger2
在编译时生成依赖注入的代码,会到inject
方法的参数类型中寻找能够注入的对象,可是实际上这些对象存在于MainActivity
,而不是Activity
中。若是函数声明参数为Activity
,Dagger2
会认为没有须要注入的对象。当真正在MainActivity
中建立Component
实例进行注入时,会直接执行按照Activity做为参数生成的inject方法,致使全部注入都失败。@Singleton
@Component(modules = ApplicationModule.class)
public interface ApplicationComponent {
@ApplicationContext
Context context();
Application application();
IRemoteServer remoteServer();
PreferencesHelper preferencesHelper();
DatabaseHelper databaseHelper();
DataManager dataManager();
RxEventBus eventBus();
}
复制代码
@Scope // Scope 的用法,@Scope是元注解,是用来标注自定义注解的
@Retention(RetentionPolicy.RUNTIME)
public @interface ConfigPersistent {
}
复制代码
ConfigPersistent
注解的话,能够复用以前的依赖实例,在Hement中我使用在了NetWorkPresenter
类中@ConfigPersistent
public class NetWorkPresenter extends BasePresenter<NetWorkView> {
.....
}
复制代码
Activity
的复用,定义ConfigPersistentComponent:意思就是持久的Component,和App的生命周期同样@ConfigPersistent
@Component(dependencies = ApplicationComponent.class)
public interface ConfigPersistentComponent {
ActivityComponent activityComponent(ActivityModule activityModule);
}
复制代码
@Qualifier
@Retention(RetentionPolicy.RUNTIME)
public @interface ApplicationContext {
}
复制代码
DbOpenHelper
中。@Singleton
public class DbOpenHelper extends SQLiteOpenHelper {
public static final String DATABASE_NAME = "hement.db";
public static final int DATABASE_VERSION = 1;
@Inject
public DbOpenHelper(@ApplicationContext Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
}
复制代码
BaseActivity、BaseFragment
关于Dagger2
的封装BaseActivity
中的封装,Hement中定义了一个持久的ConfigPersistentComponent
,在BaseActivity
定义一个LongSparseArray
具体原理请看 经常使用集合的原理分析
private static final LongSparseArray<ConfigPersistentComponent> sComponentsMap = new LongSparseArray<>();
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//建立ActivityComponent,若是配置更改后调用缓存的ConfigPersistentComponent,则重用它。
mActivityId = savedInstanceState != null ? savedInstanceState.getLong(KEY_ACTIVITY_ID) : NEXT_ID.getAndIncrement();
ConfigPersistentComponent configPersistentComponent = sComponentsMap.get(mActivityId, null);
if (null == configPersistentComponent) {
Timber.tag(getClassName()).i("建立新的configPersistentComponent id=%d",mActivityId);
configPersistentComponent = DaggerConfigPersistentComponent.builder()
.applicationComponent(HementApplication.get(this).getComponent())
.build();
sComponentsMap.put(mActivityId, configPersistentComponent);
}
mActivityComponent = configPersistentComponent.activityComponent(new ActivityModule(this));
//状态栏的颜色
QMUIStatusBarHelper.setStatusBarLightMode(this);
}
复制代码
AtomicLong
对象:AtomicLong是做用是对长整形进行原子操做,线程安全.主要做用就是 NEXT_ID.getAndIncrement()
获取一个自增加的Id。private static final AtomicLong NEXT_ID = new AtomicLong(0);
复制代码
在java1.8中新加入了一个新的原子类LongAdder,该类也能够保证Long类型操做的原子性,相对于AtomicLong,LongAdder有着更高的性能和更好的表现,能够彻底替代AtomicLong的来进行原子操做可是对 java的版本有要求,这里就不使用 LongAdder了java
原子递增一个当前值。android
NEXT_ID.getAndIncrement()
复制代码
BaseActivity
中的代码package com.shiming.hement.ui.base;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.util.LongSparseArray;
import android.support.v7.app.AppCompatActivity;
import com.shiming.base.ui.QMUIActivity;
import com.shiming.base.utils.QMUIDisplayHelper;
import com.shiming.base.utils.QMUIStatusBarHelper;
import com.shiming.hement.HementApplication;
import com.shiming.hement.injection.component.ActivityComponent;
import com.shiming.hement.injection.component.ConfigPersistentComponent;
import com.shiming.hement.injection.component.DaggerConfigPersistentComponent;
import com.shiming.hement.injection.module.ActivityModule;
import java.util.concurrent.atomic.AtomicLong;
import timber.log.Timber;
import static com.shiming.base.BaseApplication.getContext;
/**
* <p>
* 抽象应用程序中的其余活动必须实现的活动。它处理Dagger组件的建立,并确保ConfigPersistentComponent的实例跨配置更改存活。
* </p>
*
* @author shiming
* @version v1.0
* @since 2018/11/28 10:04
*/
public class BaseActivity extends QMUIActivity {
private static final String KEY_ACTIVITY_ID = "KEY_ACTIVITY_ID";
/**
* AtomicLong是做用是对长整形进行原子操做。 线程安全
*/
private static final AtomicLong NEXT_ID = new AtomicLong(0);
/**
* java1.8中新加入了一个新的原子类LongAdder,该类也能够保证Long类型操做的原子性,
* 相对于AtomicLong,LongAdder有着更高的性能和更好的表现,能够彻底替代AtomicLong的来进行原子操做
* 可是对 java的版本有要求,这里就不使用 LongAdder了
*/
// private static final LongAdder NEXT_ID = new LongAdder();
/**
* LongSparseArray是android里为<Long,Object> 这样的Hashmap而专门写的类,目的是提升效率,其核心是折半查找函数(binarySearch)。
* SparseArray仅仅提升内存效率,而不是提升执行效率
* ,因此也决定它只适用于android系统(内存对android项目有多重要)SparseArray不须要开辟内存空间来额外存储外部映射,从而节省内存。
*/
// https://www.jianshu.com/p/a5f638bafd3b 经常使用集合的原理分析 Dagger does not support injection into private fields
private static final LongSparseArray<ConfigPersistentComponent> sComponentsMap = new LongSparseArray<>();
private long mActivityId;
private ActivityComponent mActivityComponent;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//建立ActivityComponent,若是配置更改后调用缓存的ConfigPersistentComponent,则重用它。
mActivityId = savedInstanceState != null ? savedInstanceState.getLong(KEY_ACTIVITY_ID) : NEXT_ID.getAndIncrement();
ConfigPersistentComponent configPersistentComponent = sComponentsMap.get(mActivityId, null);
if (null == configPersistentComponent) {
Timber.tag(getClassName()).i("建立新的configPersistentComponent id=%d",mActivityId);
configPersistentComponent = DaggerConfigPersistentComponent.builder()
.applicationComponent(HementApplication.get(this).getComponent())
.build();
sComponentsMap.put(mActivityId, configPersistentComponent);
}
mActivityComponent = configPersistentComponent.activityComponent(new ActivityModule(this));
//状态栏的颜色
QMUIStatusBarHelper.setStatusBarLightMode(this);
}
protected String getClassName(){
return this.getClass().getSimpleName();
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putLong(KEY_ACTIVITY_ID, mActivityId);
}
/**
* isChangingConfigurations()函数在是Api level 11(Android 3.0.x) 中引入的
* 也就是用来检测当前的Activity是否 由于Configuration的改变被销毁了,而后又使用新的Configuration来建立该Activity。
* 常见的案例就是 Android设备的屏幕方向发生变化,好比从横屏变为竖屏。
*/
@Override
protected void onDestroy() {
//检查此活动是否处于销毁过程当中,以便用新配置从新建立。
if (!isChangingConfigurations()) {
Timber.tag(getClassName()).i("销毁的configPersistentComponent id=%d",mActivityId);
sComponentsMap.remove(mActivityId);
}
super.onDestroy();
}
public ActivityComponent activityComponent() {
return mActivityComponent;
}
@Override
protected int backViewInitOffset() {
return QMUIDisplayHelper.dp2px(getContext(), 100);
}
}
复制代码
未完待续 下一篇文章git
GitHub地址:Hement:持续更新中github
最后说明几点数据库
谢谢一下博客对个人帮助api