前一段时间在学习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());
}
}
}
}