IOC(Inversion of Control):控制反转。采用配置文件和注解的方式,将成员变量通过反射注入,舍弃new的方式,降低了耦合度。
反射:JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。Java反射机制主要提供了以下功能: 在运行时判断任意一个对象所属的类;在运行时构造任意一个类的对象;在运行时判断任意一个类所具有的成员变量和方法;在运行时调用任意一个对象的方法;生成动态代理。
注解:注解的实现依赖于反射。JAVA中的注解是一种继承自接口java.lang.annotation.Annotation的特殊接口。通过动态代理的方式为你生成了一个实现了接口Annotation的实例,然后对该代理实例的属性赋值,这样就可以在程序运行时(如果将注解设置为运行时可见的话)通过反射获取到注解的配置信息。
常见IOC框架:Afinal,Xutils,Annotations,ButterKnife,Dagger,RoboGuice等。
注解写法比较:
未加注解写法:
public class MainActivity extends Activity { TextView textView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); textView = (TextView) findViewById(R.id.text); textView.setText("test"); textView.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { // TODO Auto-generated method stub Intent intent = new Intent(this, ChildActivity.class); startActivity(intent); } }); } }
Android Annotations写法:
@EActivity(R.layout.activity_main) public class MainActivity extends Activity { @ViewById(R.id.text) TextView textView; @AfterViews public void init() { textView.setText("annotations test"); } @Click(R.id.text) void buttonClick() { Intent intent = new Intent(this,ChildActivity_.class); startActivity(intent); } }
其他语法举例
色值 @ColorRes
@ColorRes(R.color.backgroundColor) int someColor; @ColorRes int backgroundColor;
动画 @AnimationRes
@AnimationRes(R.anim.fadein)
XmlResourceParser xmlResAnim;
@AnimationRes
Animation fadein;
自定义View @EViewGroup
@EViewGroup(R.layout.title_with_subtitle) public class TitleWithSubtitle extends RelativeLayout { @ViewById protected TextView title, subtitle; public TitleWithSubtitle(Context context, AttributeSet attrs) { super(context, attrs); } public void setTexts(String titleText, String subTitleText) { title.setText(titleText); subtitle.setText(subTitleText); } }
HttpClient @HttpsClient
@HttpsClient
HttpClient httpsClient;
UiThread @UiThread
void myMethod() { doInUiThread("hello", 100); } @UiThread void doInUiThread(String aParam, long anotherParam) { [...] }
Android Annotations的实现原理
使用标准的Java注解处理工具自动添加一个额外的编译步骤生成的源代码。其实就是生成一个原有类的子类,这个子类才是真正运行用的类。
ButterKnife
常规写法
public class MainActivity extends Activity { TextView textView; ListView listView; ListViewAdapter adapter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); textView = (TextView) findViewById(R.id.text); listView = (ListView) findViewById(R.id.ListView); textView.setText("test"); adapter = new ListViewAdapter(MainActivity.this); listView.setAdapter(adapter); textView.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { text.setText("你点击了按钮"); } }); } class ListViewAdapter extends BaseAdapter { private Context mContext; public ListViewAdapter(Context context) { mContext = context; } @Override public int getCount() { // TODO Auto-generated method stub return 1000; } @Override public Object getItem(int position) { // TODO Auto-generated method stub return position; } @Override public long getItemId(int position) { // TODO Auto-generated method stub return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { ViewHolder holder = null; if (convertView == null) { holder = new ViewHolder(); LayoutInflater layoutInflater = ((Activity) mContext) .getLayoutInflater(); convertView = layoutInflater.inflate(R.layout.list_item, parent, false); holder.imageview = (ImageView) convertView .findViewById(R.id.headshow); holder.textview0 = (TextView) convertView .findViewById(R.id.name); holder.textview1 = (TextView) convertView .findViewById(R.id.text); convertView.setTag(convertView); } else { convertView = (View) convertView.getTag(); } holder.textview0.setText("star"); holder.textview1.setText("test"); return convertView; } } static class ViewHolder { ImageView imageview; TextView textview0; TextView textview1; } }
ButterKnife写法
public class MainActivity extends Activity { @InjectView(R.id.text) TextView text; @InjectView(R.id.ListView) ListView listView; ListViewAdapter adapter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ButterKnife.inject(this); adapter = new ListViewAdapter(MainActivity.this); listView.setAdapter(adapter); text.setText("ButterKnife test"); } @OnClick(R.id.text) void onClick() { text.setText("你点击了按钮"); } class ListViewAdapter extends BaseAdapter { private Context mContext; public ListViewAdapter(Context context) { mContext = context; } @Override public int getCount() { // TODO Auto-generated method stub return 1000; } @Override public Object getItem(int position) { // TODO Auto-generated method stub return position; } @Override public long getItemId(int position) { // TODO Auto-generated method stub return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { ViewHolder holder = null; if (convertView == null) { LayoutInflater layoutInflater = ((Activity) mContext) .getLayoutInflater(); convertView = layoutInflater.inflate( R.layout.list_item, parent, false); holder = new ViewHolder(convertView); convertView.setTag(convertView); } else { convertView = (View) convertView.getTag(); } holder.textview0.setText("butterknife"); holder.textview1.setText("test"); return convertView; } } static class ViewHolder { @InjectView(R.id.headshow) ImageView imageview; @InjectView(R.id.name) TextView textview0; @InjectView(R.id.text) TextView textview1; public ViewHolder(View view) { ButterKnife.inject(this, view); } } }
ButterKnife其他语法列举
资源注入
class ExampleActivity extends Activity { @BindString(R.string.title) String title; @BindDrawable(R.drawable.graphic) Drawable graphic; @BindColor(R.color.red) int red; @BindDimen(R.dimen.spacer) Float spacer; // ... }
Fragment注入
public class FancyFragment extends Fragment { @InjectView(R.id.button1) Button button1; @InjectView(R.id.button2) Button button2; @Override View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fancy_fragment, container, false); ButterKnife.inject(this, view); // TODO Use "injected" views... return view; } }
回调函数注入
// 带有 Button 参数 @OnClick(R.id.submit) public void sayHi(Button button) { button.setText("Hello!"); } // 不带参数 @OnClick(R.id.submit) public void submit() { // TODO submit data to server... } // 同时注入多个 View 事件 @OnClick({ R.id.door1, R.id.door2, R.id.door3 }) public void pickDoor(DoorView door) { if (door.hasPrizeBehind()) { Toast.makeText(this, "You win!", LENGTH_SHORT).show(); } else { Toast.makeText(this, "Try again", LENGTH_SHORT).show(); } }
实现原理上ButterKnife的实现也是在编译的过程中生成了另外一个类来帮我们完成一些基本操作,生成了一个名为MainActivity$$ViewInjector的类。但与Android Annotations所不同的是,我们在代码中操作的还是MainActivity,而并不是MainActivity$$ViewInjector。