实例一
反射 + 多态: 生成容器实例化并装好 view 子类
简单实现步骤:
两个方法, 一个提供完整包名. 类以及资源所在引用 (android 的话就是 xml 的 id);
另外一个方法就是用反射加上多态实现的装载;
private List<View> getViewList(List<View> list){
if(list == null)
list = new ArrayList<View>();
String vName[] = {"com.sansui.Memo.MemoView",
"com.sansui.Calendar.CalendarView","com.sansui.ClassRoom.ClassRoom"};
int vNo[] = {R.layout.memoview, R.layout.calendarview , R.layout.classroomview};
for(int i = 0 ; i < vNo.length ; i++)
list.add(getInstanceView(vName[i],vNo[i]));
return list;
}
这里要解释下: 装载在 vNames 的三个类是自定义控件的类, 其最上层父类是 View(类似于 j2se 的 object 吧);
private View getInstanceView(String className,int resouces){
XmlPullParser parser = this.getResources().getXml(resouces);
AttributeSet attributes = Xml.asAttributeSet(parser);
Object view = null;
try {
Class clazz = Class.forName(className);
Constructor con = clazz.getDeclaredConstructor(Context.class,AttributeSet.class);
view = con.newInstance(MainView.this,attributes);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
return (View)view;
}
再用一个简单的反射装载好了类 (也就是具体类和 xml 的匹配以及实例化),然后再装入 list 容器中
作用就是对于 viewpager 的设置吧, 当时写这个就是这样打算的; 是不是觉得很方便呢? 要是有多个 view 的话就很简单灵活的可以装载了, 而且此类方法复用性相当高;
实例二
通过反射获取控件对象
@ViewInject(R.id.pull_to_refresh_listview)
private PullToRefreshListView pullToRefreshListView;
不再使用一下代码初始化
pullToRefreshListView = (PullToRefreshListView) findViewById(R.id.pullToRefreshListView);
实现方式(网上有很多代码):一个 interface 和一个 class
interface
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ViewInject {
int value();
}
class
import android.app.Activity;
import java.lang.reflect.Field;
@SuppressWarnings("unused")
public class ViewInjectClass {
public static void autoInjectAllField(Activity activity) {
//得到Activity对应的Class
Class clazz = activity.getClass();
//得到该Activity的所有字段
Field[] fields = clazz.getDeclaredFields();
try {
for (Field field : fields) {
//判断字段是否标注InjectView
if (field.isAnnotationPresent(ViewInject.class)) {
//如果标注了,就获得它的id
ViewInject inject = field.getAnnotation(ViewInject.class);
int id = inject.value();
if (id > 0) {
//反射访问私有成员,必须加上这句
field.setAccessible(true);
try {
//然后对这个属性复制
field.set(activity, activity.findViewById(id));
} catch (Exception ex) {
}
}
}
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
使用方式及建议:
统一写一个BaseActivity
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import com.anykaalibrary.ViewInjectClass;
public class BaseActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
@Override
public void setContentView(int layoutResID) {
super.setContentView(layoutResID);
ViewInjectClass.autoInjectAllField(this);
}
}
public class MainActivity extends BaseActivity {
@ViewInject(R.id.pull_to_refresh_listview)
private PullToRefreshListView pullToRefreshListView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
}
其实我并不建议这样使用,我倒是希望开发工具能够根据类似这种代码,在编译前自动将代码改成
pullToRefreshListView = (PullToRefreshListView) findViewById(R.id.pullToRefreshListView);
这种形式。