自定的FindViewById註解,實現同名的R.id無需初始化

前一段時間在學習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());
            }
        }
    }
}




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章