日常开发过程中,总会遇到一个接口拥有多个子类,同时都需要进行实例化并完成自动依赖注入过程,有些DI框架针对这种场景的问题是通过ByName的方式处理的,也就是说,给实例化后的子类实例一个别名,实际使用过程中通过自动注入到引用别名的地方来使用的。
在Dagger2中也就类似的功能来支撑这种业务场景的对象实例自动依赖注入,接下来,我们将简要说明多态场景下Dagger2的使用。
首先定义一个MyBusinessInterface接口,此接口将被多个子类继承:
package com.tc.app.dagger2.di.ext;
public interface MyBusinessInterface {
void display();
}
对应子类的定义如下
MyBusinessA的定义:
package com.tc.app.dagger2.di.ext;
import android.util.Log;
public class MyBusinessA implements MyBusinessInterface {
MyBusinessA() {
}
@Override
public void display() {
Log.i("[MyBusinessA.display()]", "MyBusinessA.display() called!");
}
}
MyBusinessB的定义
package com.tc.app.dagger2.di.ext;
import android.util.Log;
public class MyBusinessB implements MyBusinessInterface {
MyBusinessB() {
}
@Override
public void display() {
Log.i("[MyBusinessB.display()]", "MyBusinessB.display() called!");
}
}
关键部分来了,我们定义一个MyBusinessModule类来专门处理多态的问题,具体定义如下面代码所示:
package com.tc.app.dagger2.di.ext;
import javax.inject.Named;
import dagger.Module;
import dagger.Provides;
@Module
public class MyBusinessModule {
@Named("myBusinessA")
@Provides
public MyBusinessInterface provideMyBusinessA(){
return new MyBusinessA();
}
@Provides
@Named("myBusinessB")
public MyBusinessInterface provideMyBusinessB(){
return new MyBusinessB();
}
}
定义好相应的实例后,开始进行对接:
package com.tc.app.dagger2;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
import com.google.android.material.snackbar.Snackbar;
import com.tc.app.dagger2.di.DaggerMyApartComponent;
import com.tc.app.dagger2.di.ext.MyBusinessInterface;
import javax.inject.Inject;
import javax.inject.Named;
public class MainActivity extends AppCompatActivity {
/** 通过依赖注入的业务服务实例 */
@Named("myBusinessA")
@Inject
MyBusinessInterface myBusinessA;
/** 通过依赖注入的业务服务实例 */
@Named("myBusinessB")
@Inject
MyBusinessInterface myBusinessB;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.setContentView(R.layout.activity_main);
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
FloatingActionButton fab = findViewById(R.id.fab);
fab.setOnClickListener((view) ->
Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
.setAction("Action", null).show()
);
//初始化环境,并完成功能调用
DaggerMyApartComponent.create().inject(this);
this.myBusinessA.display();
this.myBusinessB.display();
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
}
注:对接前,一定要记得执行build操作,否则可能导致中间代码没有生成而报错哦
不失完整性,我们给出MyApartComponent的定义:
package com.tc.app.dagger2.di;
import com.tc.app.dagger2.MainActivity;
import com.tc.app.dagger2.di.ext.MyBusinessModule;
import dagger.Component;
@Component(modules = {MyBusinessApartModule.class, MyBusinessModule.class})
public interface MyApartComponent {
void inject(MainActivity activity);
}
运行后,如果看到下面的日志,则说明配置成功了
I/[MyBusinessA.display()]: MyBusinessA.display() called!
I/[MyBusinessB.display()]: MyBusinessB.display() called!
上面例子中,虽然演示了Dagger2对多态的支持,但场景过于简单,实际使用场景中,我们对多态的应用在命令模式(Command模式)的使用场景中通常会大量应用。为了方便能够通过Dagger2完成多态实例的集中管理,我们再次对MyBusinessModule类进行改造,代码如下:
package com.tc.app.dagger2.di.ext;
import java.util.HashMap;
import java.util.Map;
import javax.inject.Named;
import dagger.Module;
import dagger.Provides;
@Module
public class MyBusinessModule {
@Named("myBusinessA")
@Provides
public MyBusinessInterface provideMyBusinessA() {
return new MyBusinessA();
}
@Provides
@Named("myBusinessB")
public MyBusinessInterface provideMyBusinessB() {
return new MyBusinessB();
}
@Provides
public Map<String, MyBusinessInterface> bizCtx(@Named("myBusinessA") MyBusinessInterface myBusinessA, @Named("myBusinessB") MyBusinessInterface myBusinessB) {
Map<String, MyBusinessInterface> bizCtx = new HashMap<>();
if (myBusinessA != null) {
bizCtx.put("myBusinessA", myBusinessA);
}
if (myBusinessB != null) {
bizCtx.put("myBusinessB", myBusinessB);
}
return bizCtx;
}
}
注:通过@Provides方式,我们声明一个bizCtx数据实例
使用数据实例的Activity代码如下:
package com.tc.app.dagger2;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
import com.google.android.material.snackbar.Snackbar;
import com.tc.app.dagger2.di.DaggerMyApartComponent;
import com.tc.app.dagger2.di.ext.MyBusinessInterface;
import java.util.Map;
import javax.inject.Inject;
public class MainActivity extends AppCompatActivity {
/** 通过依赖注入的业务服务实例 */
@Inject
Map<String, MyBusinessInterface> bizCtx;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.setContentView(R.layout.activity_main);
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
FloatingActionButton fab = findViewById(R.id.fab);
fab.setOnClickListener((view) ->
Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
.setAction("Action", null).show()
);
//初始化环境,并完成功能调用
DaggerMyApartComponent.create().inject(this);
if (bizCtx != null && bizCtx.size() > 0) {
bizCtx.get("myBusinessB").display();
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
}
注:通过注入Map<String, MyBusinessInterface> bizCtx数据实例,我们可以随心所欲的取用任意一款心仪的特定实现
运行app后,控制台日志出现如下日志,则说明本次多态的集中管理改造过程已经成功完成:
I/[MyBusinessB.display()]: MyBusinessB.display() called!