@覆盖
protected void onCreate(bundle 保存实例状态) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.d(TAG,chef.cook());
}
}
使用Dagger2你会发现你的代码更加简洁。不过,Dagger 2 还需要辅助代码来实现依赖注入。如果你使用过Dagger2,你就会知道实现依赖注入需要编写大量的模板代码。那么,我们不能以更简单的方式使用Dagger2 吗?今天我们将向您展示在Android 上使用Dagger2 的更简单的解决方案。
首先,我们看一下DaggerMainActivity中实现依赖注入所需的代码。
烹饪模块
@模块
公共类CookModules {
@单例
@假如
公共MapString,布尔ProviderMenus(){
MapString, 布尔菜单=new LinkedHashMap();
menu.put(\”酸菜鱼\”, true);
menu.put(\”土豆丝\”, true);
menu.put(\”铁板牛肉\”, true);
返回菜单。
}
}
活动模块
@模块
抽象类ActivityModules {
@ContributesAndroidInjector
抽象MainActivity commitMainActivity();
}
烹饪应用程序组件
@单例
@Component(模块={
AndroidSupportInjectionModule.class,
ActivityModules.class,
厨师模块.class})
公共接口CookAppComponent 扩展AndroidInjector {
@组件.builder
抽象类Builder 扩展了AndroidInjector.Builder{}
}
我的应用程序
公共类MyApplication 扩展DaggerApplication{
@覆盖
公共无效onCreate() {
super.onCreate();
}
@覆盖
protected AndroidInjector 是否扩展DaggerApplication applicationInjector() {?
返回DaggerCookAppComponent.builder().create(this)。
}
}
Dagger2 For Android 使用要点分析
CookModule CookModule 的目的是通过@Providers 注解向Menu 对象提供必要的数据。由于Menu 必须依赖于Map 对象,因此我们通过CookModules 构造该Map 对象,并将其自动注入到Menu 实例中。 ActivityModules ActivityModules的主要作用是通过@ContributesAndroidInjector来标记需要使用依赖注入功能的类。这里标记的是ManActivity,因此MainActivity可以通过@Inject注解注入Chef对象。 CookAppComponent CookAppComponent 对应于一个注入器。我们刚刚定义的模块是使用@Inject 注入对象的地方。 MyApplication MyApliction 的独特之处在于它继承了DaggerApliction 类并在applicationInjector 方法中构建了DaggerCookAppComponent 注入器。
这是我在Android 上使用Dagger 2 的计划。在这里您可以看到,很容易接收该类型(MainActivity)中的代码。
@注入
厨师厨师
接收类中没有多余的代码。如果扩展SecondsActivity,则必须使用SecondsActivity 中的Menu 类。
然后只需将以下内容添加到您的ActivityModules 中:
@ContributesAndroidInjector
抽象SecondsActivity commitSecondsActivity();
接下来,将Menu 插入SecondsActivity。
@注入
菜单菜单;
从项目整体来看,你会发现使用Dagger2 For Android实现依赖注入的模板代码其实相当小,而且非常简洁。只需配置一次,无需频繁编写大量模板代码。 Dagger2 增加模板代码的问题已基本得到解决。
演示地址:目录中的Dagger2Simple就是演示地址。上面的示例是Dagger2Simple 中的一个简单模块。
Dagger2的优势
这里我们总结一下使用Dagger2的优点。
减少代码量,提高工作效率。例如,在上面的示例中,在不使用Dagger2 构建Chef 对象时,必须在初始化Chef 对象之前初始化一组前置对象(Menu、Map)。并且你必须手动将其注入到相应的实例中。想象一下,如果您添加一个Restaurant 对象并需要将Chef 注入到该Restaurant 中,那么初始化Restaurant 对象所需的前期步骤将变得更加麻烦。 有些人可能认为手动初始化就可以了。但是如果你的系统中有N个地方需要初始化Restaurant对象怎么办?使用Dagger2,你可以只使用注释注入。使用Dagger2 时不需要指定对象依赖关系,它会自动处理依赖关系。 Dagger2 自动处理依赖关系(例如,Chef 必须依赖于Menu,Menu 必须依赖于Map,而Dagger 会自动处理这种依赖关系)。 )。使用静态编译不会影响运行效率。 Dagger2在编译时处理依赖注入,这也在一定程度上提高了系统的运行效率(例如,如果不使用Dagger2实现单例)。锁效率更高)。提高多人编程的效率。一起工作时,一个人可以使用Dagger2 编写代码,然后所有其他团队成员可以通过@Inject 注解直接注入常用对象。提高了编程效率,大大提高了代码的复用性。
上面我们已经介绍了Dagger2 For Android的基本使用方法。有些读者可能会觉得这个例子太简单并且不能令人满意。接下来,构建一个更复杂的系统来更详细地体验Dagger2 For Android 的好处。现在让我们扩展上面的示例,并开发一个简单的订购演示,以获得更深入的体验。
Dagger2应用实战
现在让我们看看如何使用Dagger2 开发一个简单的演示。作者这里开发的demo是一个简单的订购demo。该演示的功能非常简单,提供了显示菜单、添加/编辑/删除菜单和订购功能的功能。点餐功能只是利用小吃栏在屏幕上显示菜品名称。
Demo展
操作显示
演示地址:目录中的Dagger2Simple就是演示地址。上面的示例是Dagger2Simple 中模块的顺序。
代码目录
该演示使用经典的MVP 架构。首先我们简单分析一下demo的详细实现。
使用SharedPreferences 提供简单的缓存功能(存储菜单)。使用Gson将列表序列化为Json格式的数据,并以String的形式保存在SharedPreferences中。使用Dagger2 实现依赖注入功能。
这基本上实现了一个简单的订购演示。
Dagger在Demo中的应用解释
当您使用SharedPreferences 和Gson 实现缓存功能时,您会发现项目中的许多地方都需要SharedPreferences 和Gson 对象。因此,我们可以得出两个结论:
项目中的多个模块使用一些公共实例。这些公共实例必须是单例对象。
让我们看看如何通过使用Dagger2 提供全局模块来实现此类对象的依赖注入。
烹饪应用程序模块
@模块
公共抽象类CookAppModules {
公共静态最终字符串KEY_MENU=“菜单”;
私有静态最终字符串SP_COOK=\”cook\”;
@单例
@假如
公共静态设置ProviderMenus(SharedPreferences sp,Gson gson){
套餐;
String menuJson=sp.getString(KEY_MENU, null);
if (menuJson==null){
返回一个新的LinkedHashSet()。
}
菜单=gson.fromJson(menuJson, new TypeTokenSet(){}.getType());
返回菜单。
}
@单例
@假如
公共静态SharedPreferences ProviderSharedPreferences(上下文上下文){
返回context.getSharedPreferences(SP_COOK, Context.MODE_PRIVATE);
}
@单例
@假如
公共静态Gson ProviderGson(){
返回一个新的Gson()。
}
@单例
@绑定
public Abstract Context Context(OrderApp应用程序);
}
举个例子,dishesPresenter模块负责数据处理,所以我们将这些实例注入到DishesPresenter中。
烹饪主持人
公共类DishesPresenter 实现DishesContract.Presenter{。
私人DishesContract.View mView;
@注入
摆好餐具。
@注入
古松森.
@注入
共享首选项sp;
@注入
公共DishesPresenter(){
}
@覆盖
公共无效loadDishes(){
mView.showDishes(new ArrayList(dishes));
}
@覆盖
公共字符串顺序(MapDish,布尔selectMap){
if (selectMap==null || selectMap.size()==0) return \”\”;
StringBuilder sb=new StringBuilder();
对于(菜板:板){
if (selectMap.get(dish)){
sb.append(dish.getName()).append(“,”);
}
}
if (TextUtils.isEmpty(sb.toString())) 返回“”。
return \’烹饪:\’ + sb.toString();
}
@覆盖
公共布尔deleteDish(字符串id){
对于(菜板:板){
if (dish.getId().equals(id)){
烹饪.删除(菜);
sp.edit().putString(CookAppModules.KEY_MENU, gson.toJson(dishes)).apply();
返回真。
}
}
返回假。
}
@覆盖
公共无效takeView(DishesContract.View视图){
mView=视图;
加载菜肴();
}
@覆盖
公共无效dropView(){
mView=null;
}
}
上面的代码可以让你充分体验到Dagger2的好处。如果您的项目中有更复杂的对象并且在很多地方使用,您可以通过这种方式简化您的代码。
Dishes 模块的UI 的主要功能是由Activity 和Fragments 实现的,而Activity 只是Fragment 的外层。它们是:DishesActivity 和DishesFragment。
DishesActivity 依赖于DishesFragment 对象,而后者又依赖于DishesAdapter、RecyclerView.LayoutManager 和DishesContract.Presenter 对象。
首先我们分别看一下DishesActivity和DishesFragment的关键代码。
烹饪活动
公共类DishesActivity 扩展DaggerAppCompatActivity {
@注入
菜肴片段mDishesFragment;
……
}
烹饪碎片
公共类DishesFragment 扩展DaggerFragmentimplemented DishesContract.View{
Recycler查看rvDishes;
@注入
餐具适配器餐具适配器;
@注入
RecyclerView.LayoutManager布局管理器;
@注入
DishesContract.Presenter mPresenter;
@注入
公共DishesFragment(){
}
}
DishesFragment通过Dagger2注入DishesAdapter、RecyclerView.LayoutManager和DishesContract.Presenter。这些实例由DishesModules 提供。
烹饪模块
@模块
公共抽象类DishesModules {
@ContributesAndroidInjector
抽象公共DishesFragmentDishesFragment();
@假如
静态DishesAdapter ProviderDishesAdapter(){
返回一个新的DishesAdapter()。
}
@绑定
抽象DishesContract.View DishesView(DishesFragment);
@绑定
AbstractrecyclerView.LayoutManagerlayoutManager(LinearLayoutManagerLinearLayoutManager);
}
我们将首先解释这些注释的功能。
@ContributesAndroidInjector 可以想想Dagger2是否会自动将需要的模块注入到DishesFragment中。此注释对于简化Dagger2 For Android 中的代码至关重要。下一节通过一个具体的例子来解释。
@Module 标记有该注解的类可以被认为是依赖对象的提供者,通过该标记的类与其他注解的组合可以实现依赖关系。
@Provides的主要功能是提供第三方类库对象,或者非常复杂的对象,其行为类似于Dagger2的工厂类。
@Binds的主要作用是确定接口和具体实现类。这个比较抽象,我们来看一个例子。 DishesFragment 的代码如下:
@注入
DishesContract.Presenter mPresenter;
我们知道DishesContract.Presenter是一个接口,而这个接口可以有不同的实现类,而@Binds的作用就是确定这个特定的实现类。让我们看一下PresenterModules 的代码。
@模块
公共抽象类PresenterModules {
@绑定
抽象DishesContract.Presenter 菜肴演示者(DishesPresenter 演示者);
……
}
从这段代码可以看到,使用@Inject插入的DishesContract.Presenter对象的具体实现类是DishesPre
从。
Dagger2 For Android是如何注入依赖的?
使用Dagger2时,您通过一些模板代码实现依赖注入,例如DaggerXXXComponent.builder().inject(xxx),但在演示的DishesFragment中看不到任何类似的代码,这些对象是否注入到DishesFragment中?
答案是**@ContributesAndroidInjector** 注解
首先我们看一下Dagger2是如何自动将依赖注入到DishesActivity中的。
活动模块
@模块
公共抽象类ActivityModules {
@ContributesAndroidInjector(模块=DishesModules.class)
抽象公共DishesActivity贡献DishActivity();
@ContributesAndroidInjector(模块=AddEditModules.class)
抽象公共AddEditDishActivitycontributesAddEditDishActivity();
}
没错,这就是@ContributesAndroidInjector注解,modules代表了这个DishesActivity需要依赖的模块。本教程不解释其具体实现原理。您需要做的就是了解@ContributesAndroidInjector 的功能。
以前使用Dagger2时,实现依赖注入需要很多组件,但现在我只需要为整个应用程序编写一个组件。 @ContributesAndroidInjector 注解自动帮助生成其他所需的组件,自动处理组件之间的关系,并使用生成的组件注入依赖项。
首先,我们来看看如何使用整个模块中唯一的组件。
订单应用组件
@单例
@Component(模块={
AndroidSupportInjectionModule.class,
LayoutManagerModules.class,
CookAppModules.class,
PresenterModules.class,
活动模块.class})
公共接口OrderAppComponent 扩展AndroidInjector {
@组件.builder
抽象类Builder 扩展了AndroidInjector.Builder {
}
}
订购应用程序
公共类OrderApp 扩展DaggerApplication {
@覆盖
protected AndroidInjector 是否扩展DaggerApplication applicationInjector() {?
返回DaggerOrderAppComponent.builder().create(this)。
}
}
我们将对DishesModules 进行轻微更改,以更好地理解@ContributesAndroidInjecto 注释。
@模块
公共抽象类DishesModules {
//@ContributesAndroidInjector
//抽象公共DishesFragment菜肴片段();
@假如
静态DishesAdapter ProviderDishesAdapter(){
返回一个新的DishesAdapter()。
}
@绑定
抽象DishesContract.View DishesView(DishesFragment);
@绑定
AbstractrecyclerView.LayoutManagerlayoutManager(LinearLayoutManagerLinearLayoutManager);
}
烹饪活动
公共类DishesActivity 扩展DaggerAppCompatActivity {
//@注入
菜肴片段mDishesFragment;
太多了
lbar toolbar;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_dishes);
DishesFragment dishesFragment
= (DishesFragment) getSupportFragmentManager().findFragmentById(R.id.content_fragment);
if (dishesFragment == null){
mDishesFragment = new DishesFragment();//新增代码
dishesFragment = mDishesFragment;
ActivityUtils.addFragmentToActivity(getSupportFragmentManager(), dishesFragment, R.id.content_fragment);
}
initView();
}
…
}
//DaggerFragment改为Fragment
public class DishesFragment extends Fragment implements DishesContract.View{
}
这个时候,我们运行的时候会发现,DishesFragment中的依赖注入失败了,运行时会抛出空指针异常,没注入需要的数据。导致这个原因是因为我们在这里使用new来创建DishesFragment实例的,为什么使用new的时候会Dagger2没有帮我们注入实例呢?
当我们使用@Inject来注入DishesFragment的时候,Dagger2会自动帮我们判断DishesFragment所依赖的对象(@Inject注解标记),如果能直接注入的对象则直接注入到Fragment中,否则则从DishesModules中寻找是否有需要的对象,有的话则注入到DishesFragment中。而我们使用new来创建DishesFragment时Dagger2无法通过DishesModules来查找对象,因为我们没有声明DishesFragment与DishesModules的联系,DishesFragment也没有自动注入注解的标记( 没有实现HasSupportFragmentInjector )。所以Dagger2无法判断它们依赖关系也没办法自动帮DishesFragment自动注入依赖。
如果我们坚持要使用new的方式来依赖DishesFragment的话,则可以通过@ContributesAndroidInjecto注解来实现它们之间的关联。具体实现方式如下:
DishesModules
@Module(includes = PresenterModules.class)
public abstract class DishesModules {
@ContributesAndroidInjector
abstract public DishesFragment dishesFragment(); //增加这个抽象方法
@Provides
static DishesAdapter providerDishesAdapter(){
return new DishesAdapter();
}
@Binds
abstract DishesContract.View dishesView(DishesFragment dishesFragment);
@Binds
abstract RecyclerView.LayoutManager layoutManager(LinearLayoutManager linearLayoutManager);
}
DishesFragment继承于DaggerFragment
public class DishesFragment extends DaggerFragment implements DishesContract.View{
…
}
改成这样,我们通过new方法来创建DishesFragment的时候也能实现通过注解进行依赖注入了,为什么会这样呢?因为@ContributesAndroidInjector的作用时帮我们生成需要的Subcomponent,然后在DaggerFragment通过 DispatchingAndroidInjector 对象来实现依赖注入( 底层原理和我们使用DaggerXXXComponent手动实现依赖注入差不多 )。我们可以看看DishesModules中被@ContributesAndroidInjector注解的方法生成的代码。
@Module(subcomponents = DishesModules_DishesFragment.DishesFragmentSubcomponent.class)
public abstract class DishesModules_DishesFragment {
private DishesModules_DishesFragment() {}
@Binds
@IntoMap
@FragmentKey(DishesFragment.class)
abstract AndroidInjector.Factory<? extends Fragment> bindAndroidInjectorFactory(
DishesFragmentSubcomponent.Builder builder);
@Subcomponent
public interface DishesFragmentSubcomponent extends AndroidInjector {
@Subcomponent.Builder
abstract class Builder extends AndroidInjector.Builder {}
}
}
可以看出,编生成的代码符合我们上面的结论。
Dagger2 For Android使用要点
我们现在来总结下,简化版的Dagger实现依赖注入的几个必要条件:
第三方库通过Modules的@provides注解来提供依赖提供一个全局唯一的Component,并且Modules中需要添加AndroidSupportInjectionModule类,它的作用时关联需求与依赖之间的关系Application需要继承DaggerApplication类,并且在applicationInjector构建并返回全剧唯一的Component实例其它需要使用依赖注入的组建都需要继承Dagger组件名字类,并且需要在相应的Modules中通过@ContributesAndroidInjector注解标记需要注入依赖的组建。
上面四个步骤就是使用Dagger2实现依赖注入的要点了,总的来说,复杂度比之前的方法简单了非常多,要写的模版代码也减少了非常多。
一般来说,上面的知识点已经足够让我们在项目中正常使用Dagger2了,但是在使用中还会遇到一些其它的问题,Dagger2也提供了解决方法。如果希望进一步了解的话,可以继续阅读下文。
Dagger2拓展
@Scope
Scope字面的意思是作用域,在我们使用Dagger2的时候经常会用到@Singleton这个注解,这个注解的意思的作用是提供单例对象。而我们在使用@Singleton这个注解的时候,会同时@Provides和@Component,为什么要这样做呢?因为@Scope的作用范围其实就是单例的作用范围,这个范围主要是通过Component来确定的。
所以@Scope的作用就是以指定Component的范围为边界,提供局部的单例对象。我们可以以上面的例子为例验证这个论点论点。
我们在DishesActivity中增加一句代码,作用时注入DishesPresneter对象。
@Inject
DishesContract.Presenter mPresenter;
从上面的代码中,我们知道DishesFragment中也用同样的方式来注入过DishesPresneter对象,那么它们有什么区别的,我们通过调试功能来看下。
可以看出,DishesActivity和DishesFragment中的DishesPresenter不是同一个实例,它们的内存地址是不一样的。如果我们在PresenterModules的dishesPresenter方法中加上@Singleton
@Singleton
@Binds
abstract DishesContract.Presenter dishesPresenter(DishesPresenter presenter);
可以预见,DishesActivity和DishesFragment中的DishesPresenter会变成同一个实例,在这个例子中@Singleton的作用是提供全局的单例( 因为OrderAppComponent这个全局唯一的Component也被标注成@Singleton )。这种用法比较简单,这里不再深入。而比较难理解的就是自定义Scope了,下面我们通过一个例子来加深大家对自定义Scope的理解。
@DishesScoped
@Documented
@Scope
@Retention(RetentionPolicy.RUNTIME)
public @interface DishesScoped {
}
为了使测试效果更明显,我们稍微修改下Order这个Demo。
DishesModules
@Module
public abstract class DishesModules {
…
@DishesScoped // 添加注解
@Binds
abstract DishesContract.Presenter dishesPresenter(DishesPresenter presenter);
…
}
ActivityModules
@Module
public abstract class ActivityModules {
@DishesScoped // 添加注解
@ContributesAndroidInjector(modules = DishesModules.class)
abstract public DishesActivity contributesDishActivity();
}
然后现在我们来运行Demo,看下DishesActivity和DishesFragment中的DishesContract.Presenter的对象:
可以看出,它们是同一个对象,这验证了我们上面的结论。这里又个小问题就是,我们之前说@Scope是通过Component来确定作用边界的,但是上面这个例子中,并没有对任何Component类使用@Dishes注解啊?那么这里是如何确认边界的呢?
我们可以看看Dagger生成的类ActivityModules_ContributesDishActivity,这个类是根据ActivityModules中的contributesDishActivity方法生成的。
@Module(subcomponents = ActivityModules_ContributesDishActivity.DishesActivitySubcomponent.class)
public abstract class ActivityModules_ContributesDishActivity {
private ActivityModules_ContributesDishActivity() {}
@Binds
@IntoMap
@ActivityKey(DishesActivity.class)
abstract AndroidInjector.Factory<? extends Activity> bindAndroidInjectorFactory(
DishesActivitySubcomponent.Builder builder);
@Subcomponent(modules = DishesModules.class)
@DishesScoped //看这里
public interface DishesActivitySubcomponent extends AndroidInjector {
@Subcomponent.Builder
abstract class Builder extends AndroidInjector.Builder {}
}
}
谜底揭晓,当我们为contributesDishActivity添加上@DishesScoped注解后,自动生成的DishesActivitySubcomponent类被@DishesScoped注解了。所以@DishesScoped是通过DishesActivitySubcomponent来确认作用范围的,这也符合上面的结论。
@Scope的实现原理
@Scope实现单例的原理其实很简单,我们可以看下加了@DishesScoped后Dagger为我们生成的注入辅助代码。在这里我们只看关键方法:
private void initialize(final DishesActivitySubcomponentBuilder builder) {
this.dishesFragmentSubcomponentBuilderProvider =
new Provider<DishesModules_DishesFragment.DishesFragmentSubcomponent.Builder>() {
@Override
public DishesModules_DishesFragment.DishesFragmentSubcomponent.Builder get() {
return new DishesFragmentSubcomponentBuilder();
}
};
this.dishesPresenterProvider =
DishesPresenter_Factory.create(
DaggerOrderAppComponent.this.providerMenusProvider,
DaggerOrderAppComponent.this.providerGsonProvider,
DaggerOrderAppComponent.this.providerSharedPreferencesProvider);
this.dishesPresenterProvider2 = DoubleCheck.provider((Provider) dishesPresenterProvider); //这句代码是实现单例的关键。
}
可以看到,我们的dishesPresenterProvider2这个对象的初始化是通过双锁校验的方式来实现单例的,所以这个对象是一个单例对象。而其它没有使用@Spoce注解的类则没有使用双锁校验的方式实现初始化,Dagger通过@Scope实现单例的原理其实非常简单。关于@Spoce的介绍就到这里了,如果需要深入的话,可以进一步查看Dagger2生成的辅助代码。
@Qualifier和@Named注解
除了作用域的问题之外我们还会经常会遇到一个问题,总所周知,Dagger2是自动判断依赖关系的,如果我们的代码中需要使用同一个类生成两个或多个不同的对象呢?例如我们的LinearManager,我们现在想用Dagger提供一个横向的Manager,如果直接写在项目中是会报错的,因为Dagger无法判断需要注入/依赖的对象是哪个。如下面的代码:
LayoutManagerModules
@Module
public class LayoutManagerModules {
@Provides
public LinearLayoutManager providesLinearLayoutManager(Context context){
return new LinearLayoutManager(context);
}
@Provides
public LinearLayoutManager providesHorizonalLinearLayoutManager(Context context){
return new LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false);
}
}
这段代码肯定是会报错的,如果我们想实现这个功能的话,这个时候我们就需要用到@Qualifier或者@Named注解了。
我们先用@Named来实现上面这个需求。
LayoutManagerModules
@Module
public class LayoutManagerModules {
@Named(“vertical”)
@Provides
public LinearLayoutManager providesLinearLayoutManager(Context context){
return new LinearLayoutManager(context);
}
@Named(“horizontal”)
@Provides
public LinearLayoutManager providesHorizonalLinearLayoutManager(Context context){
return new LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false);
}
}
DishesModules
public class DishesFragment extends DaggerFragment implements DishesContract.View{
RecyclerView rvDishes;
@Inject
DishesAdapter dishesAdapter;
@Named(“horizontal”)
最后
小编这些年深知大多数初中级Android工程师,想要提升自己,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。
因此我收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人
都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
资料⬅专栏获取
ew LinearLayoutManager(context);
}
@Named(“horizontal”)
@Provides
public LinearLayoutManager providesHorizonalLinearLayoutManager(Context context){
return new LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false);
}
}
DishesModules
public class DishesFragment extends DaggerFragment implements DishesContract.View{
RecyclerView rvDishes;
@Inject
DishesAdapter dishesAdapter;
@Named(“horizontal”)
最后
小编这些年深知大多数初中级Android工程师,想要提升自己,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。
因此我收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。
[外链图片转存中…(img-8zcdc7z5-1719100004969)]一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人
都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
资料⬅专栏获取
#以上关于听说你还不会用Dagger2?Dagger2 For Android最佳实践教程的相关内容来源网络仅供参考,相关信息请以官方公告为准!
原创文章,作者:CSDN,如若转载,请注明出处:https://www.sudun.com/ask/91749.html