前一段時間在學習Java的註解,突發奇想,來一個安卓的FindViewById,能夠自動適配同名的R.id,這用就不用每一個組件都要去做一次findViewById的初始化了
具體代碼如下
FindViewById註解
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Created by Kazz on 2016/9/9.
* 以註解的形式初始化一些view
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface FindViewById {
/**
* 給定默認值
*/
public final int DEFAULT_VALUE = -31243249;
int value() default DEFAULT_VALUE;
}
基礎的Activity類(封裝了一些常用方法以及實現註解的處理)
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.Window;
import android.view.WindowManager;
import android.widget.Toast;
import java.lang.reflect.Field;
/**
* 基礎的Activity,封裝了一些公共方法
*/
public abstract class MyBaseActivity extends AppCompatActivity implements View.OnClickListener<span style="font-family: Arial, Helvetica, sans-serif;">{</span>
protected final String TAG = getClass().getSimpleName();
protected final String CURRENT_TAG = "MyBaseActivity";
/**
* 設置界面的R id的抽象方法,直接return R.layout.xxxx
*
* @return
*/
protected abstract int getLayoutID();
protected abstract void initUI();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(getLayoutID());
initViewAnnotation();
initUI();
}
/**
* 加載該Activity下有FindViewById註解的View
*/
final private void initViewAnnotation() {
Log.i(CURRENT_TAG, "initViewAnnotation: 開始");
Field[] viewFields = getClass().getDeclaredFields();
for (Field field : viewFields) {
field.setAccessible(true);
final String fieldName = field.getName();
Log.d(CURRENT_TAG, "initViewAnnotation: 開始處理" + fieldName + "的註解");
if (!PubTools.isViewClass(field.getType())) {
Log.w(CURRENT_TAG, "initViewAnnotation: " + fieldName + "不是View的子類,不需要處理");
continue;
}
if (field.isAnnotationPresent(FindViewById.class)) {
FindViewById anno = field.getAnnotation(FindViewById.class);
int rid = anno.value();
Log.d(CURRENT_TAG, "initViewAnnotation: 這個view有註解,view是{},註解值爲{},類型是{}", fieldName, rid, field.getType());
if (rid == FindViewById.DEFAULT_VALUE) { //如果註解的是空(即默認值,則直接反射R.id裏面的同名屬性)
try {
Field ridField = R.id.class.getField(fieldName);
rid = ridField.getInt(new R.id());
Log.d(CURRENT_TAG, "initViewAnnotation: 這個屬性註解的是默認值,獲得的R.id是" + rid);
field.set(MyBaseActivity.this, findViewById(rid)); //給其設值
} catch (NoSuchFieldException e) {
Log.e(CURRENT_TAG, "initViewAnnotation: 沒有找到" + fieldName + "對應的R.id,無法完成初始化,程序將退出!");
throw new RuntimeException();
} catch (Exception e) {
Log.e(CURRENT_TAG, "initViewAnnotation: 給" + field.getName() + "設置失敗");
throw new RuntimeException();
}
} else {
try {
field.set(MyBaseActivity.this, findViewById(rid)); //給其設值
} catch (IllegalAccessException e) {
Log.e(CURRENT_TAG, "initViewAnnotation: 給" + field.getName() + "設置失敗");
}
}
}
try {
View view = (View) field.get(MyBaseActivity.this);
view.setOnClickListener(this);
} catch (IllegalAccessException e) {
Log.e(CURRENT_TAG, "initViewAnnotation: 給組件{}添加Onclicklistener出錯,{}", fieldName, Arrays.toString(e.getStackTrace()));
}
}
Log.i(CURRENT_TAG, "initViewAnnotation: 結束");
}
final protected void showToast(String message) {
Toast.makeText(getApplicationContext(), message, Toast.LENGTH_SHORT).show();
}
}
實際使用
package com.kazz.SaveMoney2;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
public class MainActivity extends MyBaseActivity {
@FindViewById(R.id.tv_h)
private TextView tv_h;
@FindViewById()
private Button bt_anno;
@Override
protected int getLayoutID() {
return R.layout.activity_main;
}
@Override
public void initUI() {
}
@Override
public void onClick(View v) {
switch (v.getId()){
case R.id.bt_anno:{
showToast("點擊註解按鈕");
break;
}
case R.id.tv_h:{
showToast("點擊就送屠龍寶刀");
break;
}
default:{
Log.i(TAG,"點擊了{}組件",v.getId());
}
}
}
}