Android -- 带你从源码角度领悟Dagger2入门到放弃(三)
1, 前面两篇文章我们知道了怎么使用常用的四种标签,现在我们结合我们自己的项目中去简单的使用
在我们搭建项目的时候,一般会创建自己的Application,在里面进行一些初始化如一些第三方的GreenDao、ShareSDK等等,再或者提供一些常用的属性初始化:例如初始化屏幕的宽高度、初始化SPUtils工具类等,所以我们可以创建App类继承自Application(这里我只写了简单的App对象创建,没有写其他的任何方法)
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提供对象的代码
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类
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的对象(当然这个需求在现实中是不成立的),我们就可以这样写Module
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对象了。
OK,这里我们在activity中开始调用试试创建Student对象,看看能不能拿到值
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两个都是不容易上手的,麻蛋,自己思路写的也混乱了,祝大家早日拖坑)。
Android -- 带你从源码角度领悟Dagger2入门到放弃(三)的更多相关文章
- Android -- 带你从源码角度领悟Dagger2入门到放弃
1,以前的博客也写了两篇关于Dagger2,但是感觉自己使用的时候还是云里雾里的,更不谈各位来看博客的同学了,所以今天打算和大家再一次的入坑试试,最后一次了,保证最后一次了. 2,接入项目 在项目的G ...
- Android -- 带你从源码角度领悟Dagger2入门到放弃(二)
1,接着我们上一篇继续介绍,在上一篇我们介绍了简单的@Inject和@Component的结合使用,现在我们继续以老师和学生的例子,我们知道学生上课的时候都会有书籍来辅助听课,先来看看我们之前的Stu ...
- Android -- 带你从源码角度领悟Dagger2入门到放弃(一)
1,以前的博客也写了两篇关于Dagger2,但是感觉自己使用的时候还是云里雾里的,更不谈各位来看博客的同学了,所以今天打算和大家再一次的入坑试试,最后一次了,保证最后一次了. 2,接入项目 在项目的G ...
- 消息队列高手课,带你从源码角度全面解析MQ的设计与实现
消息队列中间件的使用并不复杂,但如果你对消息队列不熟悉,很难构建出健壮.稳定并且高性能的企业级系统,你会面临很多实际问题: 如何选择最适合系统的消息队列产品? 如何保证消息不重复.不丢失? 如果你掌握 ...
- Android 带你从源码的角度解析Scroller的滚动实现原理
转帖请注明本文出自xiaanming的博客(http://blog.csdn.net/xiaanming/article/details/17483273),请尊重他人的辛勤劳动成果,谢谢! 今天给大 ...
- Android AsyncTask完全解析,带你从源码的角度彻底理解
转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/11711405 我们都知道,Android UI是线程不安全的,如果想要在子线程里进 ...
- [转]Android事件分发机制完全解析,带你从源码的角度彻底理解(上)
Android事件分发机制 该篇文章出处:http://blog.csdn.net/guolin_blog/article/details/9097463 其实我一直准备写一篇关于Android事件分 ...
- 【转】Android事件分发机制完全解析,带你从源码的角度彻底理解(下)
转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/9153761 记得在前面的文章中,我带大家一起从源码的角度分析了Android中Vi ...
- [学习总结]7、Android AsyncTask完全解析,带你从源码的角度彻底理解
我们都知道,Android UI是线程不安全的,如果想要在子线程里进行UI操作,就需要借助Android的异步消息处理机制.之前我也写过了一篇文章从源码层面分析了Android的异步消息处理机制,感兴 ...
随机推荐
- zepto中的scrollTo
//zepto没有scrollTo动画,这里扩展了一个scrollTo函数 $.fn.scrollTo = function(options) { var defaults = { scrollTop ...
- 【AtCoder】【模型转化】【二分答案】Median Pyramid Hard(AGC006)
题意: 给你一个排列,有2*n-1个元素,现在进行以下的操作: 每一次将a[i]替换成为a[i-1],a[i],a[i+1]三个数的中位数,并且所有的操作是同时进行的,也就是说这一次用于计算的a[], ...
- webpack打包 基础
001.什么是webpack? 作用有哪些? WebPack可以看做是模块打包机:它做的事情是,分析你的项目结构,找到JavaScript模块以及其它的一些浏览器不能直接运行的拓展语言(Scss,Ty ...
- 解析CommandMessage
Json 解析: void CommandMessage::ParseCmdBody() { try { Json::Reader reader; Json::Value root; if (!rea ...
- Python基础之容器1----字符串和列表
一.编码: 1.编码只是梳理 2.编码涉及的函数: 3.实例: 字符串内存图 二.字符串 1.定义:由一系列字符组成的不可变序列容器,存储的是字符的编码值. 不可变:指字符串一旦定义,其内存地址就已经 ...
- 黑盒测试实践——day06
一.任务进展情况 通过小组成员的共同努力,终于完成了此次“黑盒测试实践”任务.目前的主要任务将之前的文件汇总,整理出来. 二.存在的问题 由于此 ...
- 2019.3.22 JMeter基础操作
1.添加线程组:testplan—添加—线程(用户)Threads(Users) 线程属性值:线程数(虚拟用户数).Rump-up(准备时长:设置所有线程全部启动时间).循环次数(每个线程重复发送请求 ...
- 为什么局部变量必须以final修饰(或者有final实效:java8)才可以在内部类中使用?
为什么局部变量必须以final修饰(或者有final实效:java8)才可以在内部类中使用? public class Ace { public static void main(String[] a ...
- Spring Security Session并发控制原理解析
当使用spring security 的标签,如下,其中<sec:session-management>对应的SessionManagementFilter.从名字可以看出,这是一个管理S ...
- webpack 知识点
安装 webpack npm install -g webpack npm install -g webpack-cli@2.x 初始化项目 npm init -y npm install --sav ...