自定義xUtils框架
阿新 • • 發佈:2018-01-15
const enum list 解釋 policy nbsp 利用 ext.get 生命
xUtils是基於Afinal開發的目前功能比較完善的一個Android開源框架,最近又發布了xUtil3.0,在增加新功能的同時又提高了框架的性能。它的功能很強大,但是有時候我們只需要其中的一些功能,如果把整個xUtils引進去沒什麽必要。
下面我們就講講如何自定義小型的xUtils,只有兩個功能:通過註解找到省去findViewById()和setContentView().
一、首先:要自定義兩個註解:
(1)找到activity視圖的註解,即用來省去setContentView()的:
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface ContentView {
int value();
}
(2)找到控件的註解,即用來省去findViewById()的。
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface ViewInject {
int value();
}
給大家解釋一下,@Target ,@Retentio這種註解叫元註解。
Target的功能就是表明你這個註解是用在什麽地方,它值是一個枚舉類型:
public enum ElementType {
/**
* Class, interface or enum declaration. 用於描述類、接口(包括註解類型)
*/
TYPE,
/**
* Field declaration. 字段聲明
*/
FIELD,
/**
* Method declaration. 方法聲明
*/
METHOD,
/**
* Parameter declaration. 參數聲明
*/
PARAMETER,
/**
* Constructor declaration. 構造器聲明
*/
CONSTRUCTOR,
/**
* Local variable declaration. 局部變量
*/
LOCAL_VARIABLE,
/**
* Annotation type declaration. 註釋類型聲明。
*/
ANNOTATION_TYPE,
/**
* Package declaration. 用於描述包
*/
PACKAGE
}
Retention大概意思是註解的生命周期什麽時候生效。
public enum RetentionPolicy {
/**
* Annotation is only available in the source code. 在源文件中有效(指定註解只保留在源文件當中,
編譯成類文件後就把註解去掉;)
*/
SOURCE,
/**
* Annotation is available in the source code and in the class file, but not
* at runtime. This is the default policy. 在class文件中有效,不是在運行時有效(指定註解只保留在源文件和編譯後的class
文件中,當jvm加載類時就把註解去掉)
*/
CLASS,
/**
* Annotation is available in the source code, the class file and is
* available at runtime. 運行時有效
*/
RUNTIME
}
二、我們需要自定義一個工具類,這個工具類裏面可以獲得我們的註解,通過反射來找到我們的View。
public class InjectUtils {
public static void initContext(Object context) {
//injectLayout必須在injectView前面,因為必須先找到contentView才能夠找到控件
injectLayout(context); //找到contentView
injectView(context); //找到控件
}
private static void injectView(Object context) {
Class<?> clazz = context.getClass();
Field[] fields = clazz.getDeclaredFields();
for(Field field : fields){
//獲取註解
ViewInject viewInject = field.getAnnotation(ViewInject.class);
//如果上面沒有標明註解
if (viewInject == null)
continue;
//獲取註解裏面的Id
int valueId = viewInject.value();
try {
//用反射調用findViewById()方法
Method findViewById = context.getClass().getMethod("findViewById",int.class);
View view = (View) findViewById.invoke(context,valueId);
//反射訪問私有成員,必須加上這句
field.setAccessible(true);
//然後對這個屬性復制
field.set(context,view);
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
private static void injectLayout(Object context) {
int layoutId = 0;
//獲得類
Class<?> clazz = context.getClass();
//獲得該類聲明的註解
ContentView contentView = clazz.getAnnotation(ContentView.class);
//如果該類沒有聲明註解
if (contentView == null)
{
return;
}
//獲得註解裏面設置的Id
layoutId = contentView.value();
try {
//利用反射調用setContentView()方法
Method setContentView = context.getClass().getMethod("setContentView",int.class);
setContentView.invoke(context,layoutId);
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
具體含義請看註釋。
三、定義一個BaseActivity
public class BaseActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
InjectUtils.initContext(this);
}
}
四、實現我們的activity
//給該class加上我們自定義的註解,InjectUtils會通過找到
//註解裏面的R.layout.activity_main,然後通過反射調用
//setContentView()方法
@ContentView(R.layout.activity_main)
public class MainActivity extends BaseActivity {
//給該組件加上我們自定義的註解,InjectUtils會通過找到
//註解裏面的R.id.xx,然後通過反射調用
//findViewById()方法找到控件
@ViewInject(R.id.text1)
private TextView textView1;
@ViewInject(R.id.text2)
private TextView textView2;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
textView1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
textView1.setText("text1");
}
});
textView2.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
textView2.setText("text2");
}
});
}
}
要註意一點:如果某個註解屬性使用value作為名稱如ContentView中的value,那麽賦值的時候可以直接@ContentView(類的ID),但是如果你使用的是其他名稱,比如下面這個註解:
public @interface Person
{
//name是屬性而不是方法,t是它的默認值,在定義的時候可以不用給定默認值
String name() default t;
}
那麽必須@Person(name=xx)這樣調用
自定義xUtils框架