听说你还不会用Dagger2?Dagger2 For Android最佳实践教程

听说你还不会用Dagger2?Dagger2 For Android最佳实践教程Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(sav

@覆盖

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

(0)
CSDN's avatarCSDN
上一篇 2024年6月23日 下午1:01
下一篇 2024年6月23日 下午1:37

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注