1、ioc介紹
控制反轉(zhuǎn)(Inversion of Control漾稀,英文縮寫為IoC)把創(chuàng)建對象的權(quán)利交給框架,是框架的重要特征瓮顽,并非面向?qū)ο缶幊?/a>的專用術(shù)語。它包括依賴注入(Dependency Injection缕贡,簡稱DI)和依賴查找(Dependency Lookup)晾咪。
到底啥意思呢???
原本我們在一個類里面用到很多成員變量,都是靠new出來塞赂,然后去訪問昼蛀。
如果咋們運用ioc那就不需要new了,你配置個xml文件仇哆,里面寫明類名夫植,有哪些成員變量,等加載這個類的時候延欠,ioc幫你new沈跨。
?說了這么多好像還沒說明白^_^,那就直接上代碼~~~~~~
2隅俘、框架
開發(fā)android的小伙伴應(yīng)該對 butterknife框架應(yīng)該不陌生吧笤喳。筆者對此框架的評價就是:好用,好用蒙畴,很好用!
目標:
@SetContentView(R.layout.activity_main)
public class MainActivityextends AppCompatActivity {
???????? @ViewBind(R.id.tv)
???????? private TextViewtv;??
???????? @Override
???????? protected void onCreate(Bundle savedInstanceState) {
???????????? super.onCreate(savedInstanceState);? ? ??
???????????? ViewInjectUtils.inject(this);? ? ?
???????????? tv.setOnClickListener(new View.OnClickListener()
??? ? ? ? ? {
???????????????? @Override? ? ? ? ??
????????????????? public void onClick(View v) {??
?????????????????????? Toast.makeText(MainActivity.this,"我被點擊了",Toast.LENGTH_LONG).show();? ? ? ??
??????????? }? ?
? ?? });
?? }
}
這里省去了tv控件創(chuàng)建的代碼 和 xml文件的加載呜象。其中控件創(chuàng)建時咋們最討厭的事情,一直重復(fù)findViewById蹬音。
SetContentView用于在類上使用休玩,主要標明該Activity需要使用的布局文件劫狠。
ViewBind在字段上使用独泞,主要標明該字段綁定的控件id苔埋。
3.框架實現(xiàn)
首先先來寫SetContentView和ViewBind這兩個注解類
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;
/**
*描述:
* * @author guoweiquan * @version 1.0
* @data 2018/5/14 下午2:15
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface SetContentView
{
int value();
}
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
*描述:
* * @author guoweiquan
* @version 1.0
* @data 2018/5/14 下午2:25 */
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ViewBind{
?????? int value();
}
解釋下注解:@interface代表是注解類 ;
@Target表示該注解可以用于什么地方(ElementType系統(tǒng)枚舉類)组橄,
總共類型如下:
??????? @Target(ElementType.TYPE)//接口、類衫画、枚舉瓮栗、注解
??????? @Target(ElementType.FIELD)//字段费奸、枚舉的常量
??????? @Target(ElementType.METHOD)//方法
??????? @Target(ElementType.PARAMETER)//方法參數(shù)
??????? @Target(ElementType.CONSTRUCTOR)//構(gòu)造函數(shù)
??????? @Target(ElementType.LOCAL_VARIABLE)//局部變量
??????? @Target(ElementType.ANNOTATION_TYPE)//注解
???????? @Target(ElementType.PACKAGE) //包
???????? @Retention表示:表示需要在什么級別保存該注解信息进陡;我們這里設(shè)置為運行時.總共類型如下:
? ? ? ? ? enumRetentionPolicy {
?????????????? SOURCE,
?????????????? CLASS,
?????????????? RUNTIME
???????????? }
下面來看下viewInjectUtils的實現(xiàn):
import android.app.Activity;
import java.lang.reflect.Field;import java.lang.reflect.Method;
/**
*描述:
* * @author guoweiquan
* @version 1.0
* @data 2018/5/14 下午2:19
*/
public class ViewInjectUtils {
private static final StringSETCONTENTVIEW ="setContentView";?
private static final StringFINDVIEWBYID ="findViewById";?
public static void inject(Activity activity)??
{
?????? bindContentView(activity);? ?
? ? ?? bindViews(activity);??
}
/**? ?
? * 綁定主布局文件? ? ??
? * @param activity? ?
? */?
private static void bindContentView(Activity activity)
{? ? ?
??????? Class clazz = activity.getClass();??
??????? SetContentView contentView = clazz.getAnnotation(SetContentView.class);
?????? // 查詢類上SetContentView注解? ? ?
?????? if (contentView !=null)? ? ?
?????? {
????????? int contentViewLayoutId = contentView.value();
????????? try{? ? ? ? ? ? ?
????????????????????? Method method = clazz.getMethod(SETCONTENTVIEW, int.class);???
????????????????????? method.setAccessible(true);
???????????????????? //設(shè)置可以訪問private域? ? ? ? ? ? ??
????????????????????? method.invoke(activity, contentViewLayoutId);
???????????????? }catch (Exception e)? ? ? ? ?
???????????? {? ? ? ? ? ? ??
???????????????? e.printStackTrace();? ? ? ? ?
????????????? }? ? ?
?????????? }??
}
/**??
? * 綁定所有的控件? ? ?
? * @param activity? ?
? */?
private static void bindViews(Activity activity)??
{? ? ??
??????? Class clazz = activity.getClass();? ? ??
???????? Field[] fields = clazz.getDeclaredFields();//獲取自己聲明的各種字段缨历,包public糙麦,protected,private? ? ? ???? for (Field field : fields)? ? ?
???????? {
????????????? ViewBind viewInjectAnnotation = field.getAnnotation(ViewBind.class);? ? ? ? ?
???????????? if (viewInjectAnnotation !=null)
???????????? {
??????????????????? int viewId = viewInjectAnnotation.value();? ? ? ? ? ? ??
??????????????????? if (viewId != -1)? ? ? ? ? ? ?
??????????????????? {
???????????????????????? try{
????????????????????????????????? Method method = clazz.getMethod(FINDVIEWBYID,? int.class);
????????????????????????????????? Object view = method.invoke(activity, viewId);//找到相應(yīng)控件對象????
?????????????????????????????????? field.setAccessible(true);
?????????????????????????????????? field.set(activity, view);//給本字段賦值? ? ? ? ? ? ? ? ?
??????????????????????????????? }catch (Exception e)? ? ? ? ? ? ? ? ?
??????????????????????????????? {? ? ? ? ? ? ? ? ? ? ??
? ? ? ? ? ??????????????????????????? e.printStackTrace();? ? ? ? ? ? ? ??
?????????????????????????????????? }? ? ? ?
???????????????????????? }? ? ? ??
???????????????? }? ? ?
? ? ? ? ?? }??
??????? }
?}
在MainActivity創(chuàng)建時候inject方法被調(diào)用魄缚,其中bindContentView和bindViews這兩個方法 就是幫咋們把加載xml和創(chuàng)建控件的活給干了冶匹。
結(jié)果如下:
項目github地址:https://github.com/seaeel/AndroidIoc.git
博主技術(shù)交流群:239025382