依賴注入框架 ----Dagger2 使用詳解及原始碼分析
在開始說Dagger之前先說下什麼叫依賴注入。
依賴:
在建立物件A的過程中,需要用到物件B的例項,這種情況較呼叫者A對被呼叫者B有一個依賴。
例如下面的例子: 組裝一臺電腦時,要用到Cpu,那麼電腦這個物件,依賴Cpu物件。
public class Computer {
CPU cpu;
public Computer(CPU cpu) {
this.cpu = cpu;
}
}
這個例子中Computer的這種初始化也叫HardInit (HI)方式,弊端在於兩個類之間不夠獨立,如果我們更改了Cpu的建構函式,那麼所有使用到Cpu的初始化方法的程式碼都要進行更改。
依賴注入:
指程式執行過程中,呼叫者(Computer)需要被呼叫者的輔助(CPU),但是建立被呼叫者(CPU)的工作不再由呼叫者(Computer)來完成,而是由相關的容器控制程式被呼叫者 (CPU)的物件在外部去創建出來並注入到呼叫者的引用中(Computer),因此也稱為控制反轉(IOC: Inversion of Control)。
如下面:
public class Computer {
//注入CPU
@Inject
Intel_CPU mCPU;
public Computer() {
}
}
那為什麼使用依賴注入?
看完上面的例子其實可以領會到它的作用了。依賴注入是實現控制反轉的方式之一(另一種是控制查詢),目的就是為了讓呼叫者和被呼叫者之間的解耦;
可以注入依賴的模擬實現,使得測試變得更加簡單。
好了,再來介紹一遍: Dagger2起源於Dagger,Dagger是由Squre公司開發出的依賴注入開源庫,但是還是存在一些效能問題,因此Google在Dagger的基礎上進行了改造演變出了現在的Dagger2.
Dagger就是一款基於Java註解實現完全在編譯階段完成依賴注入的開源庫,主要用於模組間解耦,提高程式碼的健壯性和可維護性。
ok,道理我都懂了,那怎麼用吶?
先來說下幾個註解類的作用:
@inject : 它有兩個作用,一個是用來標記需要已被注入的變數(如 注入到 Computer中的mCpu 變數);二是用來標記被依賴物件的建構函式(CPU的建構函式)。Dagger 可以通過@Inject註解可以在需要這個類例項的時候來找到這個建構函式並把例項構造出來,以此為被@Inject標記了的變數提供依賴。
@Module : 用於標記提供依賴的類(可以理解為倉庫類,工廠類)。上面說到@Inject是用來標記被依賴物件的建構函式,而@Module的作用相當於 把這些被依賴物件統一收集到@Module標記的類中進行例項化。比如被依賴物件是在第三方庫中的,我們是無法對它的建構函式做@Inject標記的,又或者說這個被依賴物件的建構函式是有引數的,那這個引數我們從哪裡傳入?這時@Module就可以解決這個問題。
@Provides : 用於標記@Module標記的類中的方法,該方法是在把被依賴物件注入使用時會呼叫。它的返回值就是被依賴物件。
@Component : 用於標註介面,是依賴需求方和依賴提供方之間的橋樑。被Compent標註的結構在編譯時會生成該介面的實現類(如被@Component標註的介面為 ComputeComponent,那麼編譯期間生成的實現類名為DaggerComputerComponent),那麼你可以通過呼叫這個實現類的方法完成注入。
@Qulifer : 用於自定義註解。被依賴物件被注入到依賴物件中時,依賴物件對被依賴物件的建立過程是不關心的。但是@Provide提供的被依賴物件是根據方法返回值型別來識別的。那若果被依賴物件的建立過程有兩種,那依賴物件需要的是哪一種吶?比如上面的例子,把Cpu注入到電腦的過程,電腦是不關心Cpu的生產過程的,但是cpu生成時有Intel和Amd兩種可選。那電腦怎麼去拿到想要的那種Cpu呢?
這時使用@Qulifer來定義自己的註解,然後通過自定義註解去標註提供依賴的方法和依賴需求方,這樣就可以精準地拿到所需要的被依賴例項。
@Scope: 同樣用於自定義註解,可以通過@Scope自定義的註解來限定註解作用於,實現區域性的單例。
@Singleton : @Singleton其實就是一個通過@Scope定義的註解,我們一般通過它來實現全域性單例。但實際上它並不能提供全域性單例,是否能提供全域性單例還要取決於對應的Component是否為一個全域性物件。
說了那麼多,是不是一臉懵逼。偉大的XXX說過,沒有經過實踐的概念都是蝦扯蛋。好 ,下面我們循序漸進地看看它的使用:
栗子1:
電腦 依賴 Cpu。 那需要把Cpu注入到 電腦中。
被依賴物件 CPU :
public class CPU {
//使用@Inject標記 被依賴物件 Cpu的構造方法。 這是注入時就會通過@Inject找到該建構函式並把例項構造出來
@Inject
public CPU () {
}
public void run() {
Log.d("======", "Intel CPU運行了");
}
}
橋樑(rebuild之後會生成實現類,DaggerComputerComponent):
@Component
public interface ComputerComponent {
void inject(Computer computer);
}
依賴物件:
public class Computer {
//注入被依賴物件
@Inject
Intel_CPU mCPU;
public Computer() {
//把依賴使用方傳入到橋樑中
DaggerComputerComponent.builder().build().inject(this);
}
public void run() {
mCPU.run();
}
}
上面就是Dagger2的簡單使用。
栗子2
這時問題來了。上面的@Inject是標記CPU類的無參建構函式的,那現在CPU的建構函式需要傳入一個品牌的引數呢?這引數從哪裡傳進來。還有上面的@Inject是直接對CPU類進行操作的,那這時如果這個類是在類庫中的,那這時是修改不了的,也就無法使用@Inject對其進行標記了。這時@Module和@Provide就出現了。
被依賴物件 CPU :
public class CPU {
private String brand;
//這時建構函式已不需要使用@Inject來標記
public CPU(String brand) {
this.brand = brand;
}
public void run() {
Log.d("======", brand + " CPU運行了");
}
}
被依賴物件的倉庫類,被@Module標記:
@Module
public class CpuModule {
//在此處例項化被依賴物件,並通過@Provide提供出去
@Provides
public CPU provideCPU() {
return new CPU("Intel");
}
}
橋樑:
@Component(modules = CpuModule.class)
public interface ComputerComponent {
void inject(Computer computer);
}
注入:
public class Computer {
@Inject
CPU mCPU;
public Computer() {
DaggerComputerComponent.builder().build().inject(this);
}
public void run() {
mCPU.run();
}
}
輸出:
栗子3
現在問題又來了,假如CPU有兩個牌子,Intel的和AMD,那例項化時也就有傳入Indel和Amd兩種。因為@Provide標記的方法也就僅僅知道其是CPU這個型別,並不知道它是Intel還是AMD的。這時就用到@Qulifier。
首先要使用@Qualifier自定義兩個註解:
@Qualifier
@Retention(RetentionPolicy.RUNTIME)
public @interface QualifilerIntel {
}
@Qualifier
@Retention(RetentionPolicy.RUNTIME)
public @interface QualifilerAmd {
}
被依賴物件 CPU:
public class CPU {
private String brand;
public CPU(String brand) {
this.brand = brand;
}
public void run() {
Log.d("======", brand + " CPU運行了");
}
}
CPUModule 類:
@Module
public class CpuModule {
// 使用 @QualifilerIntel 標註
@QualifilerIntel
@Provides
public CPU provideIntelCPU() {
return new CPU("Intel");
}
// 使用 @QualifilerAmd標註區分
@QualifilerAmd
@Provides
public CPU provideAmdCPU() {
return new CPU("Amd");
}
}
橋樑
@Component(modules = CpuModule.class)
public interface ComputerComponent {
void inject(Computer computer);
}
注入:
public class Computer {
//使用 @QualifilerIntel標記拿到指定牌子的CPU
@QualifilerIntel
@Inject
CPU mCPU;
public Computer() {
DaggerComputerComponent.builder().build().inject(this);
}
public void run() {
mCPU.run();
}
}
輸出:
栗子4: @Scope
在上面的例子2中,我們對CPU和Computer類修改下:
public class CPU {
private String brand;
public CPU(String brand) {
this.brand = brand;
Log.d("======", "Create CPU");
}
public void run() {
Log.d("======", brand + " CPU運行了");
}
}
public class Computer {
@Inject
CPU mCPU1;
@Inject
CPU mCPU2;
public Computer() {
DaggerComputerComponent.builder().build().inject(this);
}
public void run() {
mCPU1.run();
mCPU2.run();
}
}
輸出如下,可以看到,注入兩個變數,邊建立兩次CPU物件:
那現在我要這個CPU是單例的,不管注入多少次,它只建立一次,這是就用到了@Scope註解。
@Scope是通過限定作用域,實現區域性單例的。
首先我們需要通過@Scope定義一個CPUScope註解:
@Scope
@Retention(RetentionPolicy.RUNTIME)
public @interface CPUScope {
}
然後我們拿這個註解去標記依賴提供方的倉庫類CPUModule:
@Module
public class CpuModule {
@CPUScope
@Provides
public CPU provideCPU() {
return new CPU("Intel");
}
}
同時還需要使用@Scope來標註注入器Component:
@CPUScope
@Component(modules = CpuModule.class)
public interface ComputerComponent {
void inject(Computer computer);
}
依賴物件Computer:
public class Computer {
@Inject
CPU cpu1;
@Inject
CPU cpu2;
public Computer() {
DaggerComputerComponent.builder().build().inject(this);
}
public void run() {
cpu1.run();
cpu2.run();
}
}
被依賴物件CPU類:
public class CPU {
private String brand;
public CPU(String brand) {
this.brand = brand;
Log.d("======", "Create CPU");
}
public void run() {
Log.d("======", brand.hashCode() +"==" + brand + " CPU運行了");
}
}
呼叫:
Computer computer = new Computer();
computer.run();
輸出如下,可以看到注入兩個CPU,但是隻執行了一個構造方法,證明只建立了一次Cpu例項,cpu1和cpu2為同一物件。
但是,這個單例僅僅是對當前例項化的computer這個物件生效,並不是全域性單例的。假如我再例項化一個Computer:
Computer computer = new Computer();
computer.run();
Computer computer2 = new Computer();
computer2.run();
我們再來看看會輸出是怎樣:
看以看到單例沒有在computer和computer2之間生效。那現在我需要全域性單例,怎麼辦吶?先別急,這時我們肯定會疑問,為什麼是隻對當前依賴物件生效?那就回頭看看這個Computer的類:
public class Computer {
@Inject
CPU cpu1;
@Inject
CPU cpu2;
public Computer() {
DaggerComputerComponent.builder().build().inject(this);
}
public void run() {
cpu1.run();
cpu2.run();
}
}
裡面關鍵程式碼就那行: DaggerComputerComponent.builder().build().inject(this);
上面的程式碼作用就是:通過Budiler模式,生成DaggerComputerComponent這個注入器,通過這個注入器把被依賴物件(CPU)注入到這個類中。既然上面說到兩個Computer例項拿到的CPU並不是同一物件,也就是說這個註解器也不是 同一物件,那實現全域性單例的思路是不是來了?我只需要保證這個注入器Compoment是唯一的就ok啦。那我只要把這Compoment的生成過程放到Application的onCreate中不就ok了嗎?擼起袖子就是幹。
栗子5 全域性單例 : ApplicationComponent
定義ApplicationCompoment:
@CPUScope
@Component(modules = CpuModule.class)
public interface ApplicationCompoment {
void inject(Computer computer);
}
自定義Application,並且初始化ApplicationCompoment:
public class MApplication extends Application {
private static ApplicationCompoment mApplicationCompoment;
@Override
public void onCreate() {
super.onCreate();
mApplicationCompoment = DaggerApplicationCompoment.builder().cpuModule(new CpuModule()).build();
}
public static ApplicationCompoment getApplicationCompoment() {
return mApplicationCompoment;
}
}
然後Computer的使用如下,利用Application中的ApplicationComponent進行注入:
public class Computer {
@Inject
CPU cpu1;
@Inject
CPU cpu2;
public Computer() {
MApplication.getApplicationCompoment().inject(this);
}
public void run() {
cpu1.run();
cpu2.run();
}
}
呼叫:
Computer computer = new Computer();
computer.run();
Computer computer2 = new Computer();
computer2.run();
輸出如下:
栗子6
@SingleTon 就是一個現成的被@Scope標註的註解,用來限定作用域。使用和上面的@CPUScope一樣。
栗子7: include
當然,當你的Compoment可以注入多個Module的依賴物件時,可以使用花括號把多個Module.class 括起來,如以下:
@CPUScope
@Component(modules = {CpuModule.class, RamModule.class})
public interface ComputerComponent {
void inject(Computer computer);
}
當某個Module包含另外一個Module時,可以使用includes欄位:
舉個例子,現在有個需求,CPU包含高配置CPU,我想把高配置的Cpu整合到一個獨立Module中,專門提供給高階客戶,而原來的CpuModule也仍然可以使用這個高配置的Cpu。
那首先肯定是建立一個提供高階Cpu的Module : AndvancedModule
@Module
public class AdvancedCpuModule {
@Provides
AdvanedCPU provideCpu() {
return new AdvanedCPU("Indel i9");
}
}
然後在CpuModule 中使用includes 即可以包含AnvancedModule:
@Module(includes = AdvancedCpuModule.class)
public class CpuModule {
@Provides
public CPU provideCPU() {
return new CPU("Intel");
}
}
而當你的Module中提供的依賴物件需要引數進行例項化,而這個引數也是作為一個依賴物件存在,那麼也可以使用includes解決:
如下,Disk 依賴於DiskBrand:
public class Disk {
private DiskBrand mDiskBrand;
public Disk(DiskBrand diskBrand) {
mDiskBrand = diskBrand;
}
public void run() {
Log.d("======", this.hashCode() + "==" + mDiskBrand.brand + " 硬碟運轉了");
}
}
而DiskBrand也作為依賴物件存在:
@Module
public class DiskBrandModule {
@QualifilerA
@Provides
DiskBrand provideDiskBrand1() {
return new DiskBrand("三星");
}
@QualifilerB
@Provides
DiskBrand provideDiskBrand2() {
return new DiskBrand("希捷");
}
}
那麼如下,Disk的提供方法的引數就可以使用DiskModule中提供的依賴物件DiskBrand:
@Module(includes = DiskBrandModule.class)
public class DiskModule {
@Provides
Disk provideDisk(@QualifilerAmd DiskBrand diskBrand) {
return new Disk(diskBrand);
}
}
注入:
public class Computer {
@Inject
Disk mDisk;
public Computer() {
DaggerComputerComponent.builder().build().inject(this);
}
public void run() {
mDisk.run();
}
}
輸出如下:
栗子8:dependencies
dependencies :用於component之間的依賴。如ApplicationComponent是全域性的component,而其他的component需要用到ApplicationComponent的注入。那這時就可以使用dependencies,使得可以依賴於ApplicationComponent了。
被依賴物件: 顯示器類 Display:
public class Display {
public int size;
public String brand;
public Display(int size, String brand) {
this.size = size;
this.brand = brand;
}
public void run() {
Log.d("======", this.hashCode() + "==" + size + "寸" + brand + "顯示器");
}
}
被依賴物件提供方(倉庫/工具類) DisplayModule:注意下面提供了兩種Display 例項
@Module
public class DisplayModule {
@QualifilerA
@Singleton
@Provides
Display provideDisplayA() {
return new Display(27, "Dell");
}
@QualifilerB
@Singleton
@Provides
Display provideDisplayB() {
return new Display(22, "Philips");
}
}
被依賴的橋樑, ApplicationCpmponent:
@Singleton
@Component(modules = {DisplayModule.class})
public interface ApplicationCompoment {
//注意: 這裡通過這種形式把DisplayModule 中用 @QualifilerA標記的那種 Display顯示出來,而 @QualifilerB標記的那種 Display 並沒有
@QualifilerA Display display();
}
真正使用的Component , ComputerComponent,可以看到其通過dependencies依賴了ApplicationComponent:
@Component(dependencies = ApplicationCompoment.class)
public interface ComputerComponent {
void inject(Computer computer);
}
然後在Computer中進行注入:
public class Computer {
@QualifilerA
@Inject
Display mDisplay;
//這裡注入@QualifilerB 標註的Display,會編譯不通過,因為ApplicationComponent沒有顯示提供出來。
/*@QualifilerB
@Inject
Display mDisplay1;*/
public Computer() {
// 通過 applicationCompoment()把ApplicationComponent關聯
DaggerComputerComponent
.builder()
.applicationCompoment(MApplication.getApplicationCompoment())
.build()
.inject(this);
}
public void run() {
mDisplay.run();
}
}
呼叫:
Computer computer = new Computer();
computer.run();
列印:
原始碼分析
好了,說了那麼多,肯定會產生疑問為什麼可以這樣用,這是怎麼實現的。其實很簡單,我們就去一探究竟。
我們就以例子2來說。
再來回顧下 : CpuModule:
@Module
public class CpuModule {
@Provides
public CPU provideCPU() {
return new CPU("Intel");
}
}
CPUComponent:
@Component(modules = CpuModule.class)
public interface ComputerComponent {
void inject(Computer computer);
}
注入:
public class Computer {
@Inject
CPU mCPU;
public Computer() {
DaggerComputerComponent.builder().build().inject(this);
}
public void run() {
mCPU.run();
}
}
在我們寫好ComputerComponent後,重新Rebuild之後會生成ComputerComponent的實現類DaggerComputerComponent。這裡不會說Dagger根據註解生成 DaggerComputerComponent的原理是怎樣的,主要是分析這個注入的是怎樣一個流程:
我們直接去DaggerComputerComponent原始碼:
public final class DaggerComputerComponent implements ComputerComponent {
private CpuModule cpuModule;
private DaggerComputerComponent1(Builder builder) {
initialize(builder);
}
public static Builder builder() {
return new Builder();
}
public static ComputerComponent create() {
return new Builder().build();
}
@SuppressWarnings("unchecked")
private void initialize(final Builder builder) {
this.cpuModule = builder.cpuModule;
}
@Override
public void inject(Computer computer) {
injectComputer(computer);
}
private Computer injectComputer(Computer instance) {
Computer_MembersInjector.injectMCPU(
instance, CpuModule_ProvideCPUFactory.proxyProvideCPU(cpuModule));
return instance;
}
public static final class Builder {
private CpuModule1 cpuModule;
private Builder() {}
public ComputerComponent build() {
//例項化CpuModule
if (cpuModule == null) {
this.cpuModule = new CpuModule();
}
return new DaggerComputerComponent(this);
}
public Builder cpuModule(CpuModule cpuModule) {
this.cpuModule = Preconditions.checkNotNull(cpuModule);
return this;
}
}
}
可以看到上面的程式碼是通過Builder模式生成DaggerComputerComponent例項和CpuModule例項。然後在inject()方法中呼叫 injectComputer(computer);
而在injectComputer(computer)這個方法中執行了
Computer_MembersInjector.injectMCPU(
instance, CpuModule1_ProvideCPUFactory.proxyProvideCPU(cpuModule));
我們先來來看看
CpuModule1_ProvideCPUFactory.proxyProvideCPU(cpuModule)這個裡面做了什麼:
public final class CpuModule_ProvideCPUFactory implements Factory<CPU> {
private final CpuModule module;
public CpuModule_ProvideCPUFactory(CpuModule module) {
this.module = module;
}
@Override
public CPU get() {
return provideInstance(module);
}
public static CPU provideInstance(CpuModule module) {
return proxyProvideCPU(module);
}
public static CpuModule_ProvideCPUFactory create(CpuModule module) {
return new CpuModule_ProvideCPUFactory(module);
}
public static CPU proxyProvideCPU(CpuModule instance) {
return Preconditions.checkNotNull(
instance.provideCPU(), "Cannot return null from a [email protected] @Provides method");
}
}
可以看到其實就是執行了我們定義的CpuModule 的provideCPU()方法,去生成了CPU例項。而這個CPU的例項最終是通過上面的get()方法提供出去的。
好了,我們在回到上面的
Computer_MembersInjector.injectMCPU(
instance, CpuModule_ProvideCPUFactory.proxyProvideCPU(cpuModule));
看看Computer_MembersInjector.injectMCPU()做了什麼:
public final class Computer_MembersInjector implements MembersInjector<Computer> {
private final Provider<CPU> mCPUProvider;
public Computer_MembersInjector(Provider<CPU> mCPUProvider) {
this.mCPUProvider = mCPUProvider;
}
public static MembersInjector<Computer> create(Provider<CPU> mCPUProvider) {
return new Computer_MembersInjector(mCPUProvider);
}
@Override
public void injectMembers(Computer instance) {
injectMCPU(instance, mCPUProvider.get());
}
public static void injectMCPU(Computer instance, CPU mCPU) {
instance.mCPU = mCPU;
}
}
咦,這不就是對Computer的mCpu變數進行賦值操作嗎。綜上所述,CpuModule生成的例項就已經傳遞給Computer物件了。
好了,終於說完了。若有哪裡寫得不對的地方,歡迎留言指出。
相關推薦
依賴注入框架 ----Dagger2 使用詳解及原始碼分析
在開始說Dagger之前先說下什麼叫依賴注入。 依賴: 在建立物件A的過程中,需要用到物件B的例項,這種情況較呼叫者A對被呼叫者B有一個依賴。 例如下面的例子: 組裝一臺電腦時,要用到Cpu,那麼電腦這個物件,依賴Cpu物件。 public cl
Android非同步訊息處理機制詳解及原始碼分析
PS一句:最終還是選擇CSDN來整理髮表這幾年的知識點,該文章平行遷移到CSDN。因為CSDN也支援MarkDown語法了,牛逼啊! 【工匠若水 http://blog.csdn.net/yanbober 轉載煩請註明出處,尊重分享成果】 最近相對來說比較閒,加上養病,所
事件分發機制的詳解及原始碼分析
事件分發機制詳解 MotionEvent 主要分為以下幾個事件型別: ACTION_DOWN 手指開始觸控到螢幕的那一刻響應的是DOWN事件 ACTION_MOVE 接著手指在螢幕上移動響應的是MOVE事件 ACTION_UP 手指從螢幕上鬆開的那一刻響
SSH學習(十)Hibernate常用API詳解及原始碼分析
學習Java的同學注意了!!! 學習過程中遇到什麼問題或者想獲取學習資源的話,歡迎掃描左欄的二維碼加入微信公眾號(codehzm)我們一起學java! 新接觸一個框架的目的就是想利用這個框架來為我們做一些工作,或者是讓他來簡化我們的工作,利用這個框架
Java IO:FileInputStream和FileOutputStream使用詳解及原始碼分析
1 使用方法 FileInputStream即檔案輸入流,使用它從檔案中獲得位元組流,FileOutputStream即問價輸出流,使用它將位元組流寫入檔案。 1.1 方法介紹 FileInputStream提供的API如下: FileI
Spring Boot啟動命令引數詳解及原始碼分析
使用過Spring Boot,我們都知道通過java -jar可以快速啟動Spring Boot專案。同時,也可以通過在執行jar -jar時傳遞引數來進行配置。本文帶大家系統的瞭解一下Spring Boot命令列引數相關的功能及相關原始碼分析。 命令列引數使用 啟動Spring Boot專案時,我們可以通過
Show, attend and tell演算法詳解及原始碼
mark一下,感謝作者分享! https://blog.csdn.net/shenxiaolu1984/article/details/51493673 原論文:https://arxiv.org/pdf/1502.03044v2.pdf 原始碼:https://github.c
【MapReduce詳解及原始碼解析(一)】——分片輸入、Mapper及Map端Shuffle過程
title: 【MapReduce詳解及原始碼解析(一)】——分片輸入、Mapper及Map端Shuffle過程 date: 2018-12-03 21:12:42 tags: Hadoop categories: 大資料 toc: true 點選檢視我的部落格:Josonlee’
Redux-saga框架使用詳解及Demo教程
前面我們講解過redux框架和dva框架的基本使用,因為dva框架中effects模組設計到了redux-saga中的知識點,可能有的同學們會用dva框架,但是對redux-saga又不是很熟悉,今天我們就來簡單的講解下saga框架的主要API和如何配合redux框架使用 redux-saga
Spring IOC容器啟動流程原始碼解析(一)——容器概念詳解及原始碼初探
目錄 1. 前言 1.1 IOC容器到底是什麼 IOC和AOP是Spring框架的核心功能,而IOC又是AOP實現的基礎,因而可以說IOC是整個Spring框架的基石。那麼什麼是IOC?IOC即控制反轉,通俗的說就是讓Spring框架來幫助我們完成物件的依賴管理和生命週期控制等等工作。從面向物件的角度來說,
依賴注入框架Dagger2—1.入門
1.依賴注入 1.1.什麼是依賴? 如果在 Class A 中,有 Class B 的例項,則稱 Class A 對 Class B 有一個依賴。 例如下面類 A 中用到一個 B 物件,我們就說類 A 對類 B 有一個依賴。 同時,這也是一個典型的"依賴非注入
依賴注入框架Dagger2—2.各註解用法
0.前言 接上一篇入門文章,這篇主要是各屬性實戰。 1.Dagger2各屬性瞭解 必要屬性 @inject//注入,@Component,@Moudle,@Provider 為什麼說這個幾個是必要屬性,因為只要想用dagger2這幾個屬性是繞不開的。 高階屬
Android應用Context詳解及原始碼解析
轉自 http://blog.csdn.net/yanbober/article/details/45967639 1 背景 今天突然想起之前在上家公司(做TV與BOX盒子)時有好幾個人問過我關於Android的Context到底是啥的問題,所以就馬上
Android應用開發Scroller詳解及原始碼淺析
1 背景 大家都知道Android View提供了scrollTo()與scrollBy()方法來供我們進行View的滾動,但是有個問題就是他的滾動很蛋疼,疼在是瞬時挪動到指定位置的,這種對於追求使用者體驗的今天來說簡直是硬傷啊;為了解決這個問題Google給
微信 小程式前端原始碼詳解及例項分析
微信小程式前端原始碼邏輯和工作流 看完微信小程式的前端程式碼真的讓我熱血沸騰啊,程式碼邏輯和設計一目瞭然,沒有多餘的東西,真的是大道至簡。 廢話不多說,直接分析前端程式碼。個人觀點,難免有疏漏,僅供參考。 檔案基本結構: 先看入口app.js,app(obj)註冊一個小程式。接受一個 obje
Java依賴注入(DI)例項詳解
Java依賴注入模式允許我們擺脫硬編碼,使我們的應用更加鬆耦合、增強擴充套件性以及可維護性。通過依賴注入我們可以降低從編譯到執行時的依賴性。 Java依賴注入 Java的依賴注入僅僅通過理論是很難解明白的,所以我們通過幾個簡單的示例來描述它,怎樣利用依賴
Struts2實現單檔案的上傳功能例項詳解及原始碼
Struts2完成檔案的上傳功能例項 10級學員 郞志課堂筆記 在這裡通過一個例項簡單寫一下struts2實現檔案上傳的流程。 首先通過手寫的方式寫一個上傳的流程 第一步:建立相應的jsp頁面 <%@ page language="java" import="ja
OKHttp使用詳解及原始碼解析
前言 上一篇部落格瞭解了Retrofit的使用,它是對OKHttp的封裝,且Retrofit2的內部實現是OKHttp3,下面就瞭解一下OKHttp3的使用! 使用 ①首先匯入依賴,最新的版本是3.4.1,在gradle中: compile 'com
SparseArray詳解及原始碼簡析
一、前言 SparseArray 是 Android 在 Android SdK 為我們提供的一個基礎的資料結構,其功能類似於 HashMap。與 HashMap 不同的是它的 Key 只能是 int 值,不能是其他的型別。 二、程式碼分析 1. demo 及其簡析 首先也還是先通過 demo 來看一
Android快速依賴注入框架Dagger2使用1
一、啥是Dagger2 Dagger2的內容有點多,一點得有耐心。 1.1 簡介 Dagger2是一個Android/Java平臺上快速依賴注入框架,由谷歌開發,最早的版本Dagger1 由Square公司開發。依賴注入框架主要用於模組間解耦,提高程式