Android应用中使用运行时注解

@Target({ ElementType.METHOD })

@Retention(RetentionPolicy.RUNTIME)

public @interface InjectClick {

int[] value();

}

2. 定义自己的注解处理类:

package com.xxx.app.inject;

import android.app.Activity;

import android.view.View;

import java.lang.annotation.Annotation;

import java.lang.reflect.Field;

import java.lang.reflect.Method;

public class Injector {

public static void injectView(Object obj, Object root) {

Field[] fields = obj.getClass().getDeclaredFields();

for (Field field : fields) {

field.setAccessible(true);

Annotation[] annotations = field.getAnnotations();

if (annotations != null) {

for (Annotation annotation : annotations) {

if (annotation instanceof InjectView) {

InjectView injectView = (InjectView) annotation;

int value = injectView.value();

if (value != -1) {

try {

View view = getViewByRoot(root, value);

field.set(obj, view);

} catch (IllegalArgumentException e) {

e.printStackTrace();

} catch (IllegalAccessException e) {

e.printStackTrace();

}

}

break;

}

}

}

}

}

public static void injectClick(Object obj, Object root) {

Method[] methods = obj.getClass().getDeclaredMethods();

for (Method method : methods) {

Annotation[] annotations = method.getAnnotations();

if (annotations != null) {

for (Annotation annotation : annotations) {

if (annotation instanceof InjectClick) {

InjectClick inject = (InjectClick) annotation;

int[] value = inject.value();

if (value != null && value.length > 0) {

View.OnClickListener listener = (View.OnClickListener) obj;

try {

for (int res : value) {

View view = getViewByRoot(root, res);

if (view == null) {

throw new NullPointerException();

}

view.setOnClickListener(listener);

}

} catch (IllegalArgumentException e) {

e.printStackTrace();

}

}

} else if (annotation instanceof InjectLongClick) {

InjectLongClick inject = (InjectLongClick) annotation;

int[] value = inject.value();

if (value != null && value.length > 0) {

View.OnLongClickListener listener = (View.OnLongClickListener) obj;

try {

for (int res : value) {

View view = getViewByRoot(root, res);

if (view == null) {

throw new NullPointerException();

}

view.setOnLongClickListener(listener);

}

} catch (IllegalArgumentException e) {

e.printStackTrace();

}

}

}

}

}

}

}

public static View getViewByRoot(Object root, int res) {

View view = null;

if (root instanceof Activity) {

view = ((Activity)root).findViewById(res);

}

return view;

}

}

3. Activity中使用注解:

@InjectView(R.id.action_back)

private ImageView actionBack;

@InjectView(R.id.site_top_bg)

private ImageView mSiteTopBg;

@InjectView(R.id.site_name)

private TextView mSiteName;

@InjectView(R.id.site_producter)

private TextView mProducter;

@InjectView(R.id.site_logo)

private ImageRoundView mSiteLogo;

@InjectView(R.id.site_description)

private TextView mSiteDescription;

@InjectView(R.id.viewPager)

private ViewPager mViewPager;

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_site);

Injector.injectView(this, this);

Injector.injectClick(this, this);

}

@Override

@InjectClick({R.id.action_back})

public void onClick(View v) {

int id = v.getId();

switch (id){

case R.id.action_back:

SiteDetailActivity.this.finish();

break; }

}

=============================================

一、布局文件的注解

我们在Android开发的时候,总是会写到setContentView方法,为了避免每次都写重复的代码,我们需要使用注解来代替我们做这个事情,只需要在类Activity上声明一个ContentView注解和对应的布局文件就可以了。

@ContentView(R.layout.activity_main)

public class MainActivity extends AppCompatActivity {

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

ViewUtils.injectContentView(this);

}

}

从上面可以看到,上面代码在MainActivity上面使用到了ContentView注解,下面我们来看看ContentView注解。

@Target(ElementType.TYPE)

@Retention(RetentionPolicy.RUNTIME)

public @interface ContentView {

int value();

}

这个注解很简单,它有一个int的value,用来存放布局文件的id,另外它注解的对象为一个类型,需要说明的是,注解的生命周期会一直到运行时,这个很重要,因为程序是在运行时进行反射的,我们来看看ViewUtils.injectContentView(this)方法,它进行的就是注解的处理,就是进行反射调用setContentView()方法。

public static void injectContentView(Activity activity) {

Class a = activity.getClass();

if (a.isAnnotationPresent(ContentView.class)) {

// 得到activity这个类的ContentView注解

ContentView contentView = (ContentView) a.getAnnotation(ContentView.class);

// 得到注解的值

int layoutId = contentView.value();

// 使用反射调用setContentView

try {

Method method = a.getMethod(“setContentView”, int.class);

method.setAccessible(true);

method.invoke(activity, layoutId);

} catch (NoSuchMethodException e) {

e.printStackTrace();

} catch (IllegalAccessException e) {

e.printStackTrace();

} catch (InvocationTargetException e) {

e.printStackTrace();

}

}

}

如果对Java注解比较熟悉的话,上面代码应该很容易看懂。

二、字段的注解

除了setContentView之外,还有一个也是我们在开发中必须写的代码,就是findViewById,同样,它也属于简单但没有价值的编码,我们也应该使用注解来代替我们做这个事情,就是对字段进行注解。

@ContentView(R.layout.activity_main)

public class MainActivity extends AppCompatActivity {

@ViewInject(R.id.btn1)

private Button mButton1;

@ViewInject(R.id.btn2)

private Button mButton2;

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

ViewUtils.injectContentView(this);

ViewUtils.injectViews(this);

}

}

上面我们看到,使用ViewInject对两个Button进行了注解,这样我们就是不用写findViewById方法,看上去很神奇,但其实原理很简单。我们先来看看ViewInject注解。

@Target(ElementType.FIELD)

@Retention(RetentionPolicy.RUNTIME)

public @interface ViewInject {

int value();

}

这个注解也很简单,就不说了,重点就是注解的处理了。

public static void injectViews(Activity activity) {

Class a = activity.getClass();

// 得到activity所有字段

Field[] fields = a.getDeclaredFields();

// 得到被ViewInject注解的字段

for (Field field : fields) {

if (field.isAnnotationPresent(ViewInject.class)) {

// 得到字段的ViewInject注解

ViewInject viewInject = field.getAnnotation(ViewInject.class);

// 得到注解的值

int viewId = viewInject.value();

// 使用反射调用findViewById,并为字段设置值

try {

Method method = a.getMethod(“findViewById”, int.class);

method.setAccessible(true);

Object resView = method.invoke(activity, viewId);

field.setAccessible(true);

field.set(activity, resView);

} catch (NoSuchMethodException e) {

e.printStackTrace();

} catch (InvocationTargetException e) {

e.printStackTrace();

} catch (IllegalAccessException e) {

e.printStackTrace();

}

}

}

}

上面的注释很清楚,使用的也是反射调用findViewById函数。

三、事件的注解

在Android开发中,我们也经常遇到setOnClickListener这样的事件方法。同样我们可以使用注解来减少我们的代码量。

@ContentView(R.layout.activity_main)

public class MainActivity extends AppCompatActivity {

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

ViewUtils.injectContentView(this);

ViewUtils.injectEvents(this);

}

@OnClick({R.id.btn1, R.id.btn2})

public void clickBtnInvoked(View view) {

switch (view.getId()) {

case R.id.btn1:

Toast.makeText(this, “Button1 OnClick”, Toast.LENGTH_SHORT).show();

break;

case R.id.btn2:

Toast.makeText(this, “Button2 OnClick”, Toast.LENGTH_SHORT).show();

break;

}

}

}

布局文件如下:

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android=“http://schemas.android.com/apk/res/android”

xmlns:tools=“http://schemas.android.com/tools”

android:layout_width=“match_parent”

android:layout_height=“match_parent”

android:paddingBottom=“@dimen/activity_vertical_margin”

android:paddingLeft=“@dimen/activity_horizontal_margin”

android:paddingRight=“@dimen/activity_horizontal_margin”

android:paddingTop=“@dimen/activity_vertical_margin”

android:background=“#70DBDB”

android:orientation=“vertical”

tools:context=“statusbartest.hpp.cn.statusbartest.MainActivity”>

<Button

android:id=“@+id/btn1”

android:layout_width=“wrap_content”

android:layout_height=“wrap_content”

android:text=“Test1”/>

<Button

android:id=“@+id/btn2”

android:layout_width=“wrap_content”

android:layout_height=“wrap_content”

android:text=“Test2”/>

最后

现在都说互联网寒冬,其实无非就是你上错了车,且穿的少(技能),要是你上对车,自身技术能力够强,公司换掉的代价大,怎么可能会被裁掉,都是淘汰末端的业务Curd而已!现如今市场上初级程序员泛滥,这套教程针对Android开发工程师1-6年的人员、正处于瓶颈期,想要年后突破自己涨薪的,进阶Android中高级、架构师对你更是如鱼得水!

为什么某些人会一直比你优秀,是因为他本身就很优秀还一直在持续努力变得更优秀,而你是不是还在满足于现状内心在窃喜!

Android架构师之路很漫长,一起共勉吧!

参考docs.qq.com/doc/DSkNLaERkbnFoS0ZF

  • 5
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值