Android advanced teach you to build the IOC framework "Viewinject" in Android (bottom)

Source: Internet
Author: User
Tags event listener eventbase

Previous blog We have brought you a simple blow to the IOC, the implementation of the activity in the layout of the view and control injection, if you do not understand, please refer to: Android Advanced teach you to build the IOC framework "Viewinject" (on) Android.

This blog will bring you to the view of the event injection.

1. Target effect

In the previous blog, the code for our event was written like this:

Package Com.zhy.zhy_xutils_test;import Android.app.activity;import Android.os.bundle;import Android.view.View; Import Android.view.view.onclicklistener;import Android.widget.button;import Android.widget.toast;import Com.zhy.ioc.view.viewinjectutils;import Com.zhy.ioc.view.annotation.contentview;import Com.zhy.ioc.view.annotation.ViewInject; @ContentView (value = r.layout.activity_main) public class mainactivity Extends Activity implements onclicklistener{@ViewInject (r.id.id_btn) private Button mBtn1; @ViewInject (R.ID.ID_BTN02) Private Button mBtn2; @Overrideprotected void OnCreate (Bundle savedinstancestate) {super.oncreate (savedinstancestate) ; Viewinjectutils.inject (This), Mbtn1.setonclicklistener (This), Mbtn2.setonclicklistener (this);} @Overridepublic void OnClick (View v) {switch (V.getid ()) {case R.id.id_btn:toast.maketext (mainactivity.this, Click me? ", Toast.length_short). Show (); Break;case R.id.id_btn02:toast.maketext (Mainactivity.this," I AM sleeping!!! " , Toast.length_short). Show (); BREak;}}} 

Light has a view of the injection can do, we write the purpose of the view, many are used to interact, you can click on the god Horse. Abandon the traditional God horse, setonclicklistener, and then implement anonymous classes or other ways of God horse, we change to:

Package Com.zhy.zhy_xutils_test;import Android.view.view;import Android.widget.button;import android.widget.Toast; Import Com.zhy.ioc.view.annotation.contentview;import Com.zhy.ioc.view.annotation.onclick;import Com.zhy.ioc.view.annotation.ViewInject; @ContentView (value = r.layout.activity_main) public class mainactivity Extends baseactivity{@ViewInject (r.id.id_btn) private button mBtn1; @ViewInject (r.id.id_btn02) Private button mbtn2;@ OnClick ({r.id.id_btn, r.id.id_btn02}) public void clickbtninvoked (view view) {switch (View.getid ()) {case R.ID.ID_BTN: Toast.maketext (This, "Inject Btn01!", Toast.length_short). Show (); Break;case R.id.id_btn02:toast.maketext (This, " Inject Btn02! ", Toast.length_short). Show (); break;}}}

Complete the injection of events for 1 or more controls directly by adding annotations on any of the methods in the activity. Here I moved the oncreate into the baseactivity, which calls the Viewinjectutils.inject (this);

2. Implementation 1, annotated file

Package Com.zhy.ioc.view.annotation;import Java.lang.annotation.elementtype;import Java.lang.annotation.Retention ; import Java.lang.annotation.retentionpolicy;import java.lang.annotation.Target; @Target (elementtype.annotation_ TYPE) @Retention (retentionpolicy.runtime) public @interface eventbase{class<?> Listenertype (); String Listenersetter (); String methodName ();}

Package Com.zhy.ioc.view.annotation;import Java.lang.annotation.elementtype;import Java.lang.annotation.Retention ; import Java.lang.annotation.retentionpolicy;import java.lang.annotation.target;import android.view.View; @Target ( Elementtype.method) @Retention (retentionpolicy.runtime) @EventBase (Listenertype = View.OnClickListener.class, Listenersetter = "Setonclicklistener", MethodName = "OnClick") public @interface onclick{int[] value ();}

Eventbase is mainly used to add annotations to the onclick annotation, after all, there are a lot of events, and the name of the listener, the type of listener, the calling method is fixed, corresponding to the above code:

Listenertype = View.OnClickListener.class, Listenersetter = "Setonclicklistener", MethodName = "OnClick"

The onclick is used to write on a method of activity:

@OnClick ({r.id.id_btn, r.id.id_btn02}) public void clickbtninvoked (view view)

If you remember, the previous blog of our Viewinjectutils.inject (this), there are two methods, this article one more:

public static void inject (activity activity) {Injectcontentview (activity); injectviews (activity); Injectevents ( activity);}

2, Injectevents

/** * Inject All Events * * @param activity */private static void injectevents (activity activity) {class<? extends activity> C Lazz = Activity.getclass (); Method[] methods = Clazz.getmethods ();//Traverse all methods for (method Method:methods) {annotation[] annotations = Method.getannotations ();//Get all annotations on the method for (Annotation annotation:annotations) {class<? extends annotation> Annotationtype = Annotation.annotationtype ();//Get annotations on annotations eventbase eventbaseannotation = annotationtype.getannotation (eventbase.class);//If Set to Eventbaseif (eventbaseannotation! = null) {//Remove set listener name, listener type, method name called string Listenersetter = Eventbaseannotation.listenersetter (); class<?> Listenertype = Eventbaseannotation.listenertype (); String methodName = Eventbaseannotation.methodname (); try{//gets the value in the onclick annotation method Amethod = Annotationtype.getdeclaredmethod ("value");//Remove all viewidint[] Viewids = (int[]) amethod.invoke (annotation, null);// Proxy Dynamichandler handler = new Dynamichandler (activity) via Invocationhandler; Handler.addmeThod (MethodName, method); Object listener = Proxy.newproxyinstance (Listenertype.getclassloader (), New class<?>[ ] {Listenertype}, handler);//Traverse all View, set event for (int viewid:viewids) {View view = Activity.findviewbyid (viewId); Method Seteventlistenermethod = View.getclass (). GetMethod (Listenersetter, Listenertype); Seteventlistenermethod.invoke (view, listener);}} catch (Exception e) {e.printstacktrace ();}}}}

Well, the comment is as detailed as possible, mainly by traversing all the methods, getting the onclick annotations of the method, and then getting the eventbase annotations on the annotations, getting the method name, type, and the name of the method to invoke for the event listener , the proxy object of the listener is obtained through proxy and Invocationhandler, the method is displayed, and the listener is set up by reflection.

Here is a difficult point, is about Dynamichandler and proxy appearance, if not understand nothing, will be explained in detail later.

3, Dynamichandler

A class Dynamichandler is used here, which is the implementation class of Invocationhandler:

Package Com.zhy.ioc.view;import Java.lang.ref.weakreference;import Java.lang.reflect.invocationhandler;import Java.lang.reflect.method;import Java.util.hashmap;public class Dynamichandler implements Invocationhandler{private Weakreference<object> handlerref;private final hashmap<string, method> methodmap = new HashMap<String, Method> (1);p ublic Dynamichandler (Object handler) {this.handlerref = new weakreference<object> (handler);} public void Addmethod (String name, method method) {Methodmap.put (name, method);} Public Object GetHandler () {return handlerref.get ();} public void SetHandler (Object handler) {this.handlerref = new weakreference<object> (handler);} @Overridepublic object Invoke (Object proxy, Method method, object[] args) throws Throwable{object handler = Handlerref.get (); if (handler! = null) {String methodName = Method.getname (); method = Methodmap.get (MethodName); if (Method! = null) {retur n Method.invoke (handler, args);}} return null;}}
Well, the code is so much, so we're done, the injection of our events ~ ~


Actually did not sprinkle good stickers, all the same ~ ~ ~

3, about the agent

So, the end of this article, there is no ~ ~ ~ about the following lines of code, I believe you must be confused, what have these lines done?

Set proxy Dynamichandler handler = new Dynamichandler (activity) via Invocationhandler, Handler.addmethod (MethodName, method ) Object listener = proxy.newproxyinstance (Listenertype.getclassloader (), new class<?>[] {Listenertype}, handler);


Invocationhandler and proxy into the appearance, I believe that if you are familiar with Java, will certainly think of Java dynamic proxy ~ ~ ~

About Invocationhandler and proxy articles, you can refer to: Http://www.ibm.com/developerworks/cn/java/j-lo-proxy1/ps:IBM technical articles are still quite good, After all, there was a review and a bonus.

But our implementation has a certain difference, why I say that people are puzzled, such as reflection realization:

Mbtn2.setonclicklistener (this); What are the difficulties in such a code?

1, MBTN2 's acquisition? So easy

2. Call Setonclicklistener? So easy

But, here, this is an instance of the Onclicklistener implementation class, Onclicklistener is an interface ~ ~ Your implementation class how the whole, heard of reflection Newinstance object, but you are now an interface!

Now you should understand what these lines of code have done? Implements a proxy object for the interface, and then, in invoke of the proxy class, processes the calling method of the interface.

4, the code is the best teacher

No one can understand the light, you are in this xx what?? Let's look at the code below and we'll simulate the implementation of a scenario like this:

The main class implements a Button,button with two methods, a setonclicklistener and an onclick, and when the onclick of the button is called, the event that is triggered is the click Method in the main class

4 classes are involved:

Button

Package Com.zhy.invocationhandler;public class Button{private Onclicklistener listener;public void Setonclicklisntener (Onclicklistener listener) {This.listener = listener;} public void Click () {if (listener! = null) {Listener.onclick ();}}}

Onclicklistener interface

Package Com.zhy.invocationhandler;public Interface Onclicklistener{void OnClick ();}

Onclicklistenerhandler, Invocationhandler's implementation class

Package Com.zhy.invocationhandler;import Java.lang.reflect.invocationhandler;import Java.lang.reflect.Method; Import Java.util.hashmap;import Java.util.map;public class Onclicklistenerhandler implements invocationhandler{ Private Object Targetobject;public Onclicklistenerhandler (Object object) {This.targetobject = object;} Private Map<string, method> methods = new hashmap<string, method> ();p ublic void Addmethod (String methodName, method) {Methods.put (MethodName, method);} @Overridepublic object Invoke (Object proxy, Method method, object[] args) throws throwable{string MethodName = Method.getn Ame (); Method Realmethod = Methods.get (methodName); return Realmethod.invoke (TargetObject, args);}}

Our main

Package Com.zhy.invocationhandler;import Java.lang.reflect.invocationtargetexception;import Java.lang.reflect.method;import java.lang.reflect.proxy;public class main{private button button = New button ();p ublic Main () throws SecurityException, IllegalArgumentException, Nosuchmethodexception, Illegalaccessexception, Invocationtargetexception{init ();} public void Click () {System.out.println ("button clicked!");} public void Init () throws Securityexception,nosuchmethodexception, Illegalargumentexception,illegalaccessexception, Invocationtargetexception{onclicklistenerhandler h = new Onclicklistenerhandler (this); method = Main.class.getMethod ("click", null); H.addmethod ("OnClick", method); Object Clickproxy = Proxy.newproxyinstance (OnClickListener.class.getClassLoader (), new class<?>[] {onclicklistener.class}, h); Method Clickmethod = Button.getclass (). GetMethod ("Setonclicklisntener", Onclicklistener.class); ClickMethod.invoke ( button, clickproxy);} public static void Main (string[] args)Throws Securityexception,illegalargumentexception, Nosuchmethodexception,illegalaccessexception, Invocationtargetexception{main main = new Main (); Main.button.click ();}}

We simulate the button click: Call Main.button.click (), the actual execution is the click method of Main.

Looking at Init, we first initialize a onclicklistenerhandler, pass in the current instance of main, and then get the click Method of main and add it to the map in Onclicklistenerhandler.

Then through the proxy.newproxyinstance to get Onclicklistener the interface of a proxy, so that all the methods of executing this interface, will call the Onclicklistenerhandler invoke method.

But what? After all, Onclicklistener is an interface, there is no method body ~ ~ So what? This is the time to reach the map in our Onclicklistenerhandler:

@Override
public object invoke (object proxy, Method method, object[] args)
Throws Throwable
{

String methodName = Method.getname ();
Method Realmethod = Methods.get (methodName);
Return Realmethod.invoke (TargetObject, args);
}

We show that the method to execute, through the key value of the store into the map, and so on call to invoke, in fact, through the name of the method passed in, the map stored in the method, and then call our default method ~.

In this way, we should understand that, in fact, through proxy to get an agent of the interface, and then use a map pre-Setup method in Invocationhandler, so that the button onclick, and main's click association.

Now look at the code in our injectevents:

Set proxy Dynamichandler handler = new Dynamichandler (activity) via Invocationhandler, or Add method Handler.addmethod to map ( MethodName, method); Object listener = Proxy.newproxyinstance (Listenertype.getclassloader (), new class<?>[] { Listenertype}, handler);

Is it like in our init?

Well, we'll explain how to relate the callback of the interface to the method in our activity.


Note: Part of the Code reference xutils this framework, after all, want to perfect the implementation of a complete injection is not one or two blog can be done, but the core and skeleton has been achieved ~ ~ Everyone is interested can continue to improve ~




SOURCE Click to download










Android advanced teach you to build the IOC framework "Viewinject" in Android (bottom)

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.