在我们写程序的过程中,不可避免的就会牵扯到一些依赖,如会创建各种工厂类来生产我们所要依赖的对象等等。太多依赖会让我们的程序看起来很乱,而且很不利于测试,所以我们就使用Dagger2来进行依赖注入。
依赖注入到底是个什么概念呢?我自己的理解就是将对象的生产和使用给分开了。比如说有一个Car对象,当你要出行的时候就自己new一个Car对象,然后使用这个Car对象出行。在这里你出行的时候Car就是你的依赖,没有这个Car就无法出行,所以就自己来创建这个Car。如果使用依赖注入了呢?创建和使用Car是分隔开的,创建的地方不考虑使用,使用的时候也不用考虑来创建,只要说我需要一辆Car,Dagger2就会自动帮你创建好并让你使用。这就在一定程度上解耦了程序,让你的模块更加地可以重用。
下面我们就在Android中试试Dagger2吧。但是首先还要弄清楚一些概念:
@Inject: 可以用在构造方法上,这样就告诉Dagger2使用这个构造方法来创建对象,如果构造方法里面有参数依赖的话会自动给填充上;也可以用在成员变量上,Dagger2会自动将这个变量初始化。用@Inject修饰的内容可以理解为产品
@Provides: 用来修饰方法来提供各种依赖,方法的返回类型就是所提供的依赖类型,用@Provides修饰的可以理解为生产机器
@Module:所有的@Provides方法都必须放到一个Moudle中,一个Moudle就是使用@Moudle修饰的类,可以理解为一个工厂
@Component:修饰一个接口,将依赖的生产和使用结合起来,可以理解为运输部门吧,将工厂生产的产品运送到使用它的人们手里。
光看文字可能还不是很明白,下面就来写代码实践吧。在这里我使用一个展示炉石传说卡片的app作为例子,我们使用Retrofit来访问网络接口,得到卡片的信息等。那我们会有哪些依赖呢?
ApplicationContext对象,在Android app中使用十分广泛,比如我们需要获取资源文件等。
一个okHttpClient的对象,供Retrofit使用
一个使用Retrofit创建的网络访问的对象
可能会用到的Application对象
下面就一步步来吧,首先我们创建一个Moudle来提供对okHttpClient的依赖:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | @Module public class NetworkModule { @Provides @NonNull @Singleton public OkHttpClient provideOkHttpClient() { OkHttpClient okHttpClient = new OkHttpClient(); HttpLoggingInterceptor httpLoggingInterceptor = new HttpLoggingInterceptor(); httpLoggingInterceptor.setLevel(BuildConfig.DEBUG ? BODY : NONE); OkHttpClient newClient = okHttpClient.newBuilder() .addInterceptor(httpLoggingInterceptor) .build(); return newClient; } } |
通过@Singleton注释可以确保这个OkHttpClient对象是一个单例模式,对于这个client对象,我们加入了HttpLoggingInterceptor来控制log的显示,便于调试。
下面来创建一个网络访问的Moudle,在这之前我们还要定义好网络访问的接口:
1 2 3 4 5 6 7 8 | public interface IApi { @Headers({ "X-Mashape-Key:U4y8yvgRDUmshqUkNb1LJxmsRCBap1WWG0wjsnUj07GxYfsKUI", "Accept: application/json" }) @GET("info") Observable<Info> getInfo(); } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | @Module public class ApiModule { private static final String BASE_URL = "https://omgvamp-hearthstone-v1.p.mashape.com"; @Provides @Singleton public IApi getCardsApi(OkHttpClient client) { Retrofit CardsApiAdapter = new Retrofit.Builder() .baseUrl(BASE_URL) .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) .addConverterFactory(GsonConverterFactory.create()) .client(client) .build(); return CardsApiAdapter.create(IApi.class); } } |
我们将使用Rxjava来处理网络返回的内容,并内置一个GsonConverterFactory来将请求的Gson信息自动转化成对象的Bean。需要注意的是getCardsApi的参数就是一个OkHttpClient对象,由于我们在前面提供了对OkHttpClient的依赖,所以这里使用的是会自动传进一个OkHttpClient对象。
下面来创建提供Conext和Application的Moudle
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | @Module public class AppModule { private final MainApp mainApp; private final Context mContext; public AppModule(MainApp mainApp, Context mContext) { this.mainApp = mainApp; this.mContext = mContext; } @Provides @Singleton public MainApp getMainApp() { return mainApp; } @Provides @Singleton public Context provideApplicationContext() { return mContext; } } |
这些Moudle提供了所有我们需要的依赖,下面使用一个Component接口来将这些Moudle结合起来
1 2 3 4 5 6 7 8 9 | @Singleton @Component(modules = {AppModule.class, NetworkModule.class, ApiModule.class,}) public interface AppComponent { void inject(MainApp app); void inject(MainActivity mainActivity); } |
在这里接口里,我们定义了两个inject方法,我们将在MainApp和MainActivity里面使用Moudle里面提供的依赖。
在MainApp里面,我们创建一个AppComponent对象进行依赖的注入:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | public class MainApp extends Application { private Context mContext; public AppComponent getmAppComponent() { return mAppComponent; } private AppComponent mAppComponent; @Override public void onCreate() { super.onCreate(); mContext = getApplicationContext(); initializeInjector(); } private void initializeInjector() { mAppComponent = DaggerAppComponent.builder() .appModule(new AppModule(this, mContext)) .networkModule(new NetworkModule()) .apiModule(new ApiModule()) .build(); mAppComponent.inject(this); } } |
需要注意的一点就是里面DaggerAppComponent是由Dagger2自动生成的类,所以我们再写这些代码前要首先编译一下工程,让Dagger2生成这些类,否则是会报错的。
下面就在Activity里面使用吧,首先也是进行注入:
1 2 3 4 5 6 7 | @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ButterKnife.bind(this); ((MainApp) getApplication()).getmAppComponent().inject(this); } |
然后就可以直接进行网络的访问了:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | @Inject IApi mIApi; @OnClick(R.id.text) void () { CLogger.i(""); Observable<Info> info = mIApi.getInfo(); info.subscribeOn(Schedulers.io()) .subscribe(new Subscriber<Info>() { @Override public void onCompleted() { } @Override public void onError(Throwable e) { CLogger.e(e); } @Override public void onNext(Info info) { CLogger.i(info.patch); } }); } |
在这里,我们访问网络所需要的mIApi对象将由Dagger2自动给我们生成,我们拿过来用就可以了。赶快来实验一下吧,通过log,我们可以看到我们正确地请求到了所要的数据:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | 02-18 15:14:43.061 15902-15902/cn.com.mushuichuan.heartstonecards I/CLogger: MainActivity.java[Line: 26] 02-18 15:14:43.061 15902-16339/cn.com.mushuichuan.heartstonecards D/OkHttp: --> GET https://omgvamp-hearthstone-v1.p.mashape.com/info http/1.1 02-18 15:14:43.061 15902-16339/cn.com.mushuichuan.heartstonecards D/OkHttp: X-Mashape-Key: U4y8yvgRDUmshqUkNb1LJxmsRCBap1WWG0wjsnUj07GxYfsKUI 02-18 15:14:43.061 15902-16339/cn.com.mushuichuan.heartstonecards D/OkHttp: Accept: application/json 02-18 15:14:43.061 15902-16339/cn.com.mushuichuan.heartstonecards D/OkHttp: --> END GET 02-18 15:14:45.381 15902-16339/cn.com.mushuichuan.heartstonecards D/OkHttp: <-- 200 OK https://omgvamp-hearthstone-v1.p.mashape.com/info (2317ms) 02-18 15:14:45.381 15902-16339/cn.com.mushuichuan.heartstonecards D/OkHttp: Cache-Control: private, must-revalidate 02-18 15:14:45.381 15902-16339/cn.com.mushuichuan.heartstonecards D/OkHttp: Content-Type: application/json 02-18 15:14:45.381 15902-16339/cn.com.mushuichuan.heartstonecards D/OkHttp: Date: Thu, 18 Feb 2016 07:14:49 GMT 02-18 15:14:45.381 15902-16339/cn.com.mushuichuan.heartstonecards D/OkHttp: expires: -1 02-18 15:14:45.381 15902-16339/cn.com.mushuichuan.heartstonecards D/OkHttp: pragma: no-cache 02-18 15:14:45.381 15902-16339/cn.com.mushuichuan.heartstonecards D/OkHttp: Server: Mashape/5.0.6 02-18 15:14:45.381 15902-16339/cn.com.mushuichuan.heartstonecards D/OkHttp: Set-Cookie: XSRF-TOKEN=eyJpdiI6ImRrT1dUN1dcLzVPcnlzVTRZNlVXUURRPT0iLCJ2YWx1ZSI6ImJYNkRONURJeEJTVW9ydndKeGM0Q1RQMmdYR3JzcTgxKzJtOGtcL0FKRHpNNEtaWStiVURMSVFTWldTY0lrdTR4bG1CYnJQN1JKNDRsXC82M25tS0pyNVE9PSIsIm1hYyI6IjdmNjVjYmJmMjZlYzQ0YjM4ZWZmYmVhYThhZDA5MzYxN2Y5OGFjODc3YmM1ODI4NjAwMjNiZTlhOWJlNDljNjQifQ%3D%3D; expires=Thu, 18-Feb-2016 09:14:49 GMT; Max-Age=7200; path=/ 02-18 15:14:45.381 15902-16339/cn.com.mushuichuan.heartstonecards D/OkHttp: Set-Cookie: laravel_session=eyJpdiI6ImMwQnZ3QXVDUWNIMVNNT1Z2bUR1VlE9PSIsInZhbHVlIjoiODFndUFnYlBENUVoMXQ0TThsWmFzQldLN2Y0NUR0TTluaE1mMEZZdExwTVVtaFBySTB1K1wvRzFZQThCQVdrbXRHQkxtVExURVJycWRkc2ZrMmZpNXRRPT0iLCJtYWMiOiI3NDAxYzM1ZDA0MzkyYjMxNzlmNzk2YmNmNGM5OTc5NDU2YmY1MTY4OGU1NTQyMTE3ZDY5NmNlMWNjZmI0ODAwIn0%3D; expires=Thu, 18-Feb-2016 09:14:49 GMT; Max-Age=7200; path=/; httponly 02-18 15:14:45.381 15902-16339/cn.com.mushuichuan.heartstonecards D/OkHttp: X-Powered-By: PHP/5.6.13 02-18 15:14:45.381 15902-16339/cn.com.mushuichuan.heartstonecards D/OkHttp: Content-Length: 681 02-18 15:14:45.381 15902-16339/cn.com.mushuichuan.heartstonecards D/OkHttp: Connection: keep-alive 02-18 15:14:45.381 15902-16339/cn.com.mushuichuan.heartstonecards D/OkHttp: OkHttp-Sent-Millis: 1455779684200 02-18 15:14:45.381 15902-16339/cn.com.mushuichuan.heartstonecards D/OkHttp: OkHttp-Received-Millis: 1455779685387 02-18 15:14:45.381 15902-16339/cn.com.mushuichuan.heartstonecards D/OkHttp: {"patch":"4.1.0.10956","classes":["Druid","Hunter","Mage","Paladin","Priest","Rogue","Shaman","Warlock","Warrior","Dream"],"sets":["Basic","Classic","Credits","Naxxramas","Slush","Goblins vs Gnomes","Missions","Promo","Reward","System","Blackrock Mountain","Hero Skins","Tavern Brawl","The Grand Tournament","The League of Explorers"],"types":["Hero","Minion","Spell","Enchantment","Weapon","Hero Power"],"factions":["Horde","Alliance","Neutral"],"qualities":["Free","Common","Rare","Epic","Legendary"],"races":["Demon","Dragon","Mech","Murloc","Beast","Pirate","Totem"],"locales":["deDE","enGB","enUS","esES","esMX","frFR","itIT","koKR","plPL","ptBR","ruRU","zhCN","zhTW","jaJP"]} 02-18 15:14:45.381 15902-16339/cn.com.mushuichuan.heartstonecards D/OkHttp: <-- END HTTP (681-byte body) 02-18 15:14:45.391 15902-16339/cn.com.mushuichuan.heartstonecards I/CLogger: MainActivity.java[Line: 42] 4.1.0.10956 |
实验成功,可以继续进行接下来的开发了。
完整代码请见Github
共同学习,写下你的评论
评论加载中...
作者其他优质文章