首页 文章 精选 留言 我的

精选列表

搜索[Solon框架],共10000篇文章
优秀的个人博客,低调大师

Dagger——Android 的依赖注入框架

简介 在开发程序的时候,会用到各种对象,很多对象在使用之前都需要进行初始化。例如你要操作一个SharedPreference,你需要调用getSharedPreferences(String name,int mode)来获取一个对象,然后才能使用它。而如果这个对象会在多个Activity中被使用,你就需要在每个使用的场景中都写下同样的代码。这不仅麻烦,而且增加了出错的可能。dagger的用途就是:让你不需要初始化对象。换句话说,任何对象声明完了就能直接用。 原理 dagger是使用依赖注入的方式,使用Annotation给需要注入的对象做标记,通过inject()方法自动注入所有对象,从而完成自动的初始化。 示例代码: public class MainActivity extends Activity { // 通过@Inject对对象进行标记 @Inject SharedPreferences sharedPreferences; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // 注入依赖 ObjectGraph.create(AppModule.class).inject(this); // 获取name的值并输出 System.out.println(sharedPreferences.getString("name", "")); } } 依赖注入(Dependency Injection):在类A中要用到一个B的对象(依赖),需要通过新建B的实例或其他一些主动的方式来获取对象,然后才能调用。而通过外部的方式自动将B的对象分配给A(注入),实现相对被动的获取对象,这个过程称为依赖注入。希望更多了解依赖注入可以自行Google。 使用方式 以一个简单的“老板和程序员”App为例。你想实现Boss对象的自动注入,那么首先你要告诉程序它要怎么初始化一个Boss。在dagger中,为Boss类的构造方法添加一个@Inject注解,程序就会在需要的时候找到这个被标记的构造方法并调用它,从而获取一个Boss对象。 public class Boss { ... @Inject public Boss() { ... } ... } 需要注意的是,如果构造函数含有参数,Dagger会在构造对象的时候先去获取这些参数(不然谁来传参?),所以你要保证这些参数的构造方法也有@Inject标记,或者能够通过@Provides注解(下面会介绍)来获取到。 然后,在声明Boss对象的时候,在前面同样添加@Inject注解。程序会在依赖注入的过程中自动初始化被注解的对象。 public class MainActivity extends Activity { @Inject Boss boss; ... } 最后,创建ObjectGraph类并执行inject()方法并将当前MainActivity作为参数传入,Boss的对象就被注入到了MainActivity中。 public class MainActivity extends Activity { @Inject Boss boss; @Override protected void onCreate(Bundle savedInstanceState) { ObjectGraph.create(AppModule.class).inject(this); } ... } 到此为止,使用Dagger将一个Boss对象注入到MainActivity的流程就完成了。上面这段代码中出现了两个类:ObjectGraph和AppModule。其中ObjectGraph是由Dagger提供的类,可以简单理解为一个工具类,它的create函数中参数为所有的Module,本文不详述,如果有兴趣可以跟进我之后的Dagger详解。AppModule是一个自定义类,代码如下: @Module(injects = MainActivity.class) public class AppModule { } 可以看到,AppModule是一个空类,只有一行注解。@Module注解表示,这个类是一个Module,Module的作用是提供信息,让ObjectGraph知道应该怎样注入所有的依赖。例如,上面这段代码中声明了可注入对象的信息:MainActivity.class(使用显式声明这样的看起来很麻烦、多此一举的方式和Dagger的原理有关,本文不详述)。 自定义依赖 对构造方法进行注解是很好用的实现依赖的途径,然而它并不适用于所有情况。 接口(Interface)是没有构造方法的第三方库提供的类,它们的构造方法不能被注解有些类需要灵活选择初始化的配置,而不是使用一个单一的构造方法对于这样的情况,可以使用@Provides注解来提供专用的初始化方法,实现自定义依赖。 **@ProvidesCoder provideCoder(Boss boss) { return new Coder(boss); }**同样,@Provides注解的方法如果含有参数,它的所有参数也要保证能够被Dagger获取到。 所有带有@Provides注解的方法都需要被封装到带有@Module注解的类中: **@Modulepublic class AppModule { @Provides Coder provideCoder(Boss boss) { return new Coder(boss); } }**单例 Dagger支持单例,实现方式也十分简单: **// @Inject注解构造方法的单例模式@Singletonpublic class Boss { ... @Inject public Boss() { ... } ... }// @Provides注解提供初始化方法的单例模式@Provides@SingletonCoder provideCoder(Boss boss) { return new Coder(boss); }**通过上面的方法添加@Singleton注解之后,对象只会被初始化一次,之后的每次都会被直接注入相同的对象。 Qualifier(限定符) 如果有两类程序员,他们的能力值power分别是5和1000,应该怎样让Dagger对他们做出区分呢?使用@Qualifier注解 首先,创建一个@interface: @Qualifier @Documented @Retention(RUNTIME) public @interface Level { String value() default ""; } 然后,为这两类程序员分别设置@Provides方法,并使用@Qualifier对他们做出不同的标记: @Provides @Level("low") Coder provideLowLevelCoder() { Coder coder = new Coder(); coder.setName("战五渣"); coder.setPower(5); return coder; } @Provides @Level("high") Coder provideHighLevelCoder() { Coder coder = new Coder(); coder.setName("大神"); coder.setPower(1000); return coder; } 最后,在使用的时候也用上相应的@Qualifier注解。 @Inject @Level("low") Coder lowLevelCoder; @Inject @Level("high") Coder highLevelCoder; 编译时检查 实质上,Dagger会在编译时对代码进行检查,并在检查不通过的时候报编译错误(为什么?这和Dagger的原理有关,有兴趣的话可以关注我之后发布的Dagger详解)。检查内容主要有三点: 所有含有依赖注入的类,需要被显式 声明在相应的Module中。 一个Module中所有@Provides方法的参数都必须在这个Module种提供相应的@Provides方法,或者在@Module注解后添加“complete = false”注明这是一个不完整Module(即它会被其他Module所扩展)。 一个Module中所有的@Provides方法都要被它声明的注入对象所使用,或者在@Module注解后添加“library = ture”注明(即它是为了扩展其他Module而存在的)。

优秀的个人博客,低调大师

安卓框架——SlidingMenu使用技巧

SlidingMenu的一些常用属性 原文转载http://blog.csdn.net/zwl5670/article/details/48274109 [java] view plain copy //设置侧滑菜单的位置,可选值LEFT,RIGHT,LEFT_RIGHT(两边都有菜单时设置) menu.setMode(SlidingMenu.LEFT_RIGHT); //设置触摸屏幕的模式,可选只MARGIN,CONTENT menu.setTouchModeAbove(SlidingMenu.TOUCHMODE_MARGIN); //根据dimension资源文件的ID来设置阴影的宽度 menu.setShadowWidthRes(R.dimen.shadow_width); //根据资源文件ID来设置滑动菜单的阴影效果 menu.setShadowDrawable(R.drawable.shadow); //这两个都是设置滑动菜单视图的宽度,二选一 //设置SlidingMenu离屏幕的偏移量 menu.setBehindOffsetRes(R.dimen.slidingmenu_offset); //设置宽度 menu.setBehindWidth() //设置渐入渐出效果的值 menu.setFadeDegree(0.35f); //设置SlidingMenu与下方视图的移动的速度比,当为1时同时移动,取值0-1 menu.setBehindScrollScale(1.0f); //设置二级菜单的阴影效果 menu.setSecondaryShadowDrawable(R.drawable.shadow); //设置右边(二级)侧滑菜单 menu.setSecondaryMenu(R.layout.right_menu_frame); //为侧滑菜单设置布局 menu.setMenu(R.layout.leftmenu); //把滑动菜单添加进所有的Activity中,可选值SLIDING_CONTENT,SLIDING_WINDOW menu.attachToActivity(this,SlidingMenu.SLIDING_CONTENT); 1、在Activity中通过SlidingMenu构造方法,直接设置侧滑菜单 [java] view plain copy publicclassMainActivityextendsActivity{ @Override protectedvoidonCreate(BundlesavedInstanceState){ super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); SlidingMenumenu=newSlidingMenu(this);//初始化滑动菜单 menu.setMode(SlidingMenu.LEFT);//设置触摸屏幕的模式 menu.setTouchModeAbove(SlidingMenu.TOUCHMODE_MARGIN); menu.setShadowWidthRes(R.dimen.shadow_width);//设置阴影的宽度 menu.setShadowDrawable(R.drawable.shadow);//设置滑动菜单的阴影效果 //设置滑动菜单视图的宽度 menu.setBehindOffsetRes(R.dimen.slidingmenu_offset); //设置渐入渐出效果的值 menu.setFadeDegree(0.35f); /** *SLIDING_WINDOWwillincludetheTitle/ActionBarinthecontent *sectionoftheSlidingMenu,whileSLIDING_CONTENTdoesnot. */ //把滑动菜单添加进所有的Activity中 menu.attachToActivity(this,SlidingMenu.SLIDING_CONTENT); //为侧滑菜单设置布局 menu.setMenu(R.layout.leftmenu); } } 2、通过把Activity继承SlidingActivity a、继承SlidingActivity b、然后在onCreate中setBehindContentView(R.layout.leftmenu); 设置侧滑菜单的布局 c、通过getSlidingMenu()得到SlidingMenu对象,然后设置样式 [java] view plain copy publicclassMainActivityextendsSlidingActivity{ @Override publicvoidonCreate(BundlesavedInstanceState){ super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); setBehindContentView(R.layout.leftmenu); //configuretheSlidingMenu SlidingMenumenu=getSlidingMenu(); menu.setMode(SlidingMenu.LEFT); //设置触摸屏幕的模式 menu.setTouchModeAbove(SlidingMenu.TOUCHMODE_FULLSCREEN); menu.setShadowWidthRes(R.dimen.shadow_width); menu.setShadowDrawable(R.drawable.shadow); //设置滑动菜单视图的宽度 menu.setBehindOffsetRes(R.dimen.slidingmenu_offset); //设置渐入渐出效果的值 menu.setFadeDegree(0.35f); /** *SLIDING_WINDOWwillincludetheTitle/ActionBarinthecontent *sectionoftheSlidingMenu,whileSLIDING_CONTENTdoesnot. */ //menu.attachToActivity(this,SlidingMenu.SLIDING_CONTENT); //menu.setMenu(R.layout.leftmenu); } } 3、将SlidingMenu当作普通控件 可以把SlidingMenu作为普通的view,然后在布局中声明。 [java] view plain copy <RelativeLayoutxmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/id_main_ly" android:layout_width="match_parent" android:layout_height="match_parent"> <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="30dp" android:layout_marginTop="30dp"> <com.jeremyfeinstein.slidingmenu.lib.SlidingMenu xmlns:sliding="http://schemas.android.com/apk/res-auto" android:id="@+id/slidingmenulayout" android:layout_width="120dp" android:layout_height="170dp" android:background="#ffffffff" sliding:behindOffset="0dp" sliding:behindScrollScale="1" sliding:fadeDegree="0.3" sliding:fadeEnabled="true" sliding:touchModeAbove="fullscreen" sliding:viewAbove="@layout/pic"/> </LinearLayout> </RelativeLayout> pic布局: [plain] view plain copy <?xmlversion="1.0"encoding="utf-8"?> <ImageViewxmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="120dp" android:layout_height="170dp" android:src="@drawable/zhy"/> MainActivity: [java] view plain copy packagecom.zhy.zhy_slidemenu_demo03; importandroid.app.Activity; importandroid.os.Bundle; importandroid.view.View; importandroid.view.View.OnClickListener; importcom.jeremyfeinstein.slidingmenu.lib.SlidingMenu; publicclassMainActivityextendsActivity { privateSlidingMenumLeftMenu; @Override protectedvoidonCreate(BundlesavedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mLeftMenu=(SlidingMenu)findViewById(R.id.slidingmenulayout); //configuretheSlidingMenu //SlidingMenumenu=newSlidingMenu(this); mLeftMenu.setMode(SlidingMenu.LEFT); //设置触摸屏幕的模式 mLeftMenu.setShadowWidthRes(R.dimen.shadow_width); mLeftMenu.setShadowDrawable(R.drawable.shadow); mLeftMenu.setMenu(R.layout.leftmenu); mLeftMenu.setOnClickListener(newOnClickListener() { @Override publicvoidonClick(Viewv) { if(mLeftMenu.isMenuShowing()) mLeftMenu.toggle(); } }); //设置滑动菜单视图的宽度 //设置渐入渐出效果的值 /** *SLIDING_WINDOWwillincludetheTitle/ActionBarinthecontent *sectionoftheSlidingMenu,whileSLIDING_CONTENTdoesnot. */ } } 4、SlidingMenu设置左右侧滑菜单例子 上面3个方法,SlidingMenu的布局中控件的事件都需要写在Activity中,这样代码比较臃肿,一般会使用Fragment作为侧滑菜单的布局容器。 核心代码: · [java] view plain copy FragmentleftMenuFragment=newMenuLeftFragment(); ·setBehindContentView(R.layout.left_menu_frame); ·getSupportFragmentManager().beginTransaction() ·.replace(R.id.id_left_menu_frame,leftMenuFragment).commit(); ·SlidingMenumenu=getSlidingMenu(); ·menu.setMode(SlidingMenu.LEFT_RIGHT); ·//设置触摸屏幕的模式 ·menu.setTouchModeAbove(SlidingMenu.TOUCHMODE_MARGIN); 先给侧滑菜单通过 setBehindContentView(R.layout.left_menu_frame); 设置一个布局,此布局中只有一个FrameLayout,然后使用FragmentManager将Fragment替换掉此Fragment,这样这个 Fragment就作为我们侧滑菜单的布局了,我们的事件处理代码也可以写在Fragement中,而不是Activity中。 MenuLeftFragment [java] view plain copy packagecom.zhy.zhy_slidemenu_demo04; importjava.util.Arrays; importjava.util.List; importandroid.os.Bundle; importandroid.support.v4.app.Fragment; importandroid.view.LayoutInflater; importandroid.view.View; importandroid.view.ViewGroup; importandroid.widget.ArrayAdapter; importandroid.widget.ListAdapter; importandroid.widget.ListView; publicclassMenuLeftFragmentextendsFragment { privateViewmView; privateListViewmCategories; privateList<String>mDatas=Arrays .asList("聊天","发现","通讯录","朋友圈","订阅号"); privateListAdaptermAdapter; @Override publicViewonCreateView(LayoutInflaterinflater,ViewGroupcontainer, BundlesavedInstanceState){ if(mView==null){ initView(inflater,container); } returnmView; } privatevoidinitView(LayoutInflaterinflater,ViewGroupcontainer){ mView=inflater.inflate(R.layout.left_menu,container,false); mCategories=(ListView)mView .findViewById(R.id.id_listview_categories); mAdapter=newArrayAdapter<String>(getActivity(), android.R.layout.simple_list_item_1,mDatas); mCategories.setAdapter(mAdapter); } } MenuRightFragment packagecom.zhy.zhy_slidemenu_demo04; importandroid.os.Bundle; importandroid.support.v4.app.Fragment; importandroid.view.LayoutInflater; importandroid.view.View; importandroid.view.ViewGroup; publicclassMenuRightFragmentextendsFragment{ privateViewmView; @Override publicViewonCreateView(LayoutInflaterinflater,ViewGroupcontainer, BundlesavedInstanceState){ if(mView==null){ mView=inflater.inflate(R.layout.right_menu,container,false); } returnmView; } } MainActivity [java] view plain copy publicclassMainActivityextendsSlidingFragmentActivity{ privateViewPagermViewPager; privateFragmentPagerAdaptermAdapter; privateList<Fragment>mFragments=newArrayList<Fragment>(); @Override publicvoidonCreate(BundlesavedInstanceState){ super.onCreate(savedInstanceState); this.requestWindowFeature(Window.FEATURE_NO_TITLE); setContentView(R.layout.activity_main); //初始化SlideMenu initRightMenu(); //初始化ViewPager initViewPager(); } privatevoidinitViewPager(){ mViewPager=(ViewPager)findViewById(R.id.id_viewpager); MainTab01tab01=newMainTab01(); MainTab02tab02=newMainTab02(); MainTab03tab03=newMainTab03(); mFragments.add(tab01); mFragments.add(tab02); mFragments.add(tab03); /** *初始化Adapter */ mAdapter=newFragmentPagerAdapter(getSupportFragmentManager()){ @Override publicintgetCount(){ returnmFragments.size(); } @Override publicFragmentgetItem(intarg0){ returnmFragments.get(arg0); } }; mViewPager.setAdapter(mAdapter); } privatevoidinitRightMenu(){ FragmentleftMenuFragment=newMenuLeftFragment(); setBehindContentView(R.layout.left_menu_frame); getSupportFragmentManager().beginTransaction() .replace(R.id.id_left_menu_frame,leftMenuFragment).commit(); SlidingMenumenu=getSlidingMenu(); menu.setMode(SlidingMenu.LEFT_RIGHT); //设置触摸屏幕的模式 menu.setTouchModeAbove(SlidingMenu.TOUCHMODE_MARGIN); menu.setShadowWidthRes(R.dimen.shadow_width); menu.setShadowDrawable(R.drawable.shadow); //设置滑动菜单视图的宽度 menu.setBehindOffsetRes(R.dimen.slidingmenu_offset); //设置渐入渐出效果的值 menu.setFadeDegree(0.35f); //menu.setBehindScrollScale(1.0f); menu.setSecondaryShadowDrawable(R.drawable.shadow); //设置右边(二级)侧滑菜单 menu.setSecondaryMenu(R.layout.right_menu_frame); FragmentrightMenuFragment=newMenuRightFragment(); getSupportFragmentManager().beginTransaction() .replace(R.id.id_right_menu_frame,rightMenuFragment).commit(); } publicvoidshowLeftMenu(Viewview){ getSlidingMenu().showMenu(); } publicvoidshowRightMenu(Viewview){ getSlidingMenu().showSecondaryMenu(); } } MainActivity继承的是SlidingFragmentActivity ,在Activity中FragmentPagerAdapter和viewPager作为主布局,然后分别初始化SlidingMenu的两边的菜单。

资源下载

更多资源
Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

Sublime Text

Sublime Text

Sublime Text具有漂亮的用户界面和强大的功能,例如代码缩略图,Python的插件,代码段等。还可自定义键绑定,菜单和工具栏。Sublime Text 的主要功能包括:拼写检查,书签,完整的 Python API , Goto 功能,即时项目切换,多选择,多窗口等等。Sublime Text 是一个跨平台的编辑器,同时支持Windows、Linux、Mac OS X等操作系统。

WebStorm

WebStorm

WebStorm 是jetbrains公司旗下一款JavaScript 开发工具。目前已经被广大中国JS开发者誉为“Web前端开发神器”、“最强大的HTML5编辑器”、“最智能的JavaScript IDE”等。与IntelliJ IDEA同源,继承了IntelliJ IDEA强大的JS部分的功能。

用户登录
用户注册