先贴上所有代码
布局文件
xml version="1.0" encoding="utf-8"?>xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/activity_main" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="anmin.calendar.xiaomi.proxxy.MainActivity">
使用代理的Activity
package anmin.calendar.xiaomi.proxxy; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.support.v7.widget.AppCompatButton; import android.view.View; import android.widget.Button; import android.widget.Toast; @ContentView(R.layout.activity_main) public class MainActivity extends AppCompatActivity{ @ViewInject(R.id.one) Button one; @ViewInject(R.id.two) Button two; @ViewInject(R.id.three) Button three; @ViewInject(R.id.four) Button four; @ViewInject(R.id.five) Button five; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); InjectView.ViewInject(this); InjectView.InjectView(this); one.setText("ONE"); two.setText("TWO"); three.setText("THREE"); four.setText("Four"); five.setText("FIVE"); } @Event(id ={R.id.one,R.id.two,R.id.three,R.id.four,R.id.five}, enventType = View.OnClickListener.class) private void click(View pView){ Toast.makeText(this,"成功点击",Toast.LENGTH_LONG).show(); if (pView instanceof AppCompatButton){ Button btn= (Button) pView; Toast.makeText(this,btn.getText().toString(),Toast.LENGTH_LONG).show(); } } }
setContentView注解类
package anmin.calendar.xiaomi.proxxy; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * Created by Administrator on 2016/11/18. */ @Documented @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) public @interface ContentView { int value(); }
findViewbyid注解类
package anmin.calendar.xiaomi.proxxy; import android.renderscript.Sampler; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import javax.xml.validation.Validator; /** * Created by Administrator on 2016/11/18. */ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.FIELD) public @interface ViewInject { int value(); }
实现点击事件的注解类
package anmin.calendar.xiaomi.proxxy; import android.view.View; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * Created by Administrator on 2016/11/18. */ @Documented @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface Event { int[] id(); Class> enventType() default View.OnClickListener.class; }
实现注解功能的类
setContentView和findViewbyid都是通过反射方式来实现的,比较简单。
package anmin.calendar.xiaomi.proxxy; import android.app.Activity; import android.view.View; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Proxy; /** * Created by Administrator on 2016/11/18. */ public class InjectView { private final static String onClick=View.OnClickListener.class.getSimpleName(); private final static String onLongClick=View.OnLongClickListener.class.getSimpleName(); public static void ViewInject(Activity pActivity){ if (pActivity!=null){ Class extends Activity> cls = pActivity.getClass(); if (cls.isAnnotationPresent(ContentView.class)){ ContentView lContentView=cls.getAnnotation(ContentView.class); int layoutId=lContentView.value(); pActivity.setContentView(layoutId); InjectView.setClick(pActivity); } } } public static void setClick(Activity activity){ if (activity!=null){ Class extends Activity> cls = activity.getClass(); Method[] method = cls.getDeclaredMethods(); for (Method m : method){ if (m.isAnnotationPresent(Event.class)){ Event lEvent=m.getAnnotation(Event.class); int[] ids=lEvent.id(); Class> css=lEvent.enventType(); String name=css.getSimpleName(); try{ for (int id :ids){ if (name.equals(onClick)){ View lView=activity.findViewById(id); MyInvocationHandler handler=new MyInvocationHandler(); handler.setView(lView); handler.setMethod(m); handler.setActivity(activity); Class extends View> cl = lView.getClass(); Method lMethod=cl.getMethod("setOnClickListener",new Class>[]{View.OnClickListener.class}); Object proxy = Proxy.newProxyInstance(lEvent.enventType().getClassLoader(), new Class>[]{lEvent.enventType()},handler); lMethod.setAccessible(true); lMethod.invoke(lView,proxy); } } } catch (Exception e){ } if (name.equals(onLongClick)){ } } } } } public static void InjectView(Activity pActivity){ if (pActivity!=null){ Class extends Activity> cls = pActivity.getClass(); Field[] field = cls.getFields(); for (Field f :field){ if (f.isAnnotationPresent(ViewInject.class)){ ViewInject lViewInject=f.getAnnotation(ViewInject.class); int viewId=lViewInject.value(); View v=pActivity.findViewById(viewId); f.setAccessible(true); try { f.set(pActivity,v); } catch (IllegalAccessException pE) { pE.printStackTrace(); } } } } } }
实现点击事件主要设计到两个类即InvocationHandler和Proxy来动态实现点击事件接口的代理。
package anmin.calendar.xiaomi.proxxy; import android.app.Activity; import android.view.View; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; /** * Created by Administrator on 2016/11/18. */ public class MyInvocationHandler implements InvocationHandler { private Method mMethod; private View mView; private Activity mActivity; public void setActivity(Activity pActivity) { mActivity = pActivity; } public Method getMethod() { return mMethod; } public void setMethod(Method pMethod) { mMethod = pMethod; } public View getView() { return mView; } public void setView(View pView) { mView = pView; } @Override public Object invoke(Object pO, Method pMethod, Object[] pObjects) throws Throwable { mMethod.setAccessible(true); return mMethod.invoke(mActivity,pObjects); } }