Android Custom Annotation Framework

Source: Internet
Author: User

ObjectiveIn our project, we deal with some fixed code almost every day, for example, in the activity you write Findviewbyid (int) method to find the control, but this kind of code for a slightly qualified programmer, is no nutrition, You can't learn anything at all, but you have to write. This is the appearance of the annotated framework, which greatly simplifies the programmer's work and makes the code concise. Perhaps you have already used the annotated framework, so will you write it yourself? All right, let's get to the framework of an annotation today .read the knowledge you need to master

Knowledge of 1.Java Reflection

Knowledge of 2.Java annotations


common wording.XML layout file, just a button
<relativelayout 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 "    tools:context= "${relativepackage}.${activityclass}" >    <button        android:id= "@+id/bt"        Android:layout_width= "Match_parent"        android:layout_height= "wrap_content"        android:text= "point Me"/></ Relativelayout>

code in the activity
public class Mainactivity extends Activity implements Onclicklistener {/** * button */private button BT = null; @Overrideprotec Ted void OnCreate (Bundle savedinstancestate) {super.oncreate (savedinstancestate); Setcontentview (r.layout.activity_ Main);//Find Button BT = (button) Findviewbyid (R.ID.BT);//Set Click event Bt.setonclicklistener (this);} @Overridepublic void OnClick (View v) {Toast.maketext (this, "point me Up", Toast.length_long). Show ();}}

It's also very simple, and then it's

The above is our usual way of writing, then we take a look at the annotated framework of the wording, first experience, and then write the annotated frameworkusing the notation framework.
public class Mainactivity extends Activity {/** * button */@Injection (value = R.id.bt,click = "ClickView") private Button BT = null; @Overrideprotected void OnCreate (Bundle savedinstancestate) {super.oncreate (savedinstancestate); Setcontentview (R.layout.activity_main);//Make annotations work viewinjectionutil.injectview (this);} public void ClickView () {Toast.maketext (this, "dot me, with annotated frame", Toast.length_long). Show ();}}


Just so little code? Yes, you're right, that's the exact code, just like the normal one.just a little more code to make the annotations work, see the effect of using the annotated framework

As you can see, there is no problem with the program, so let's implement it!
Ideas1. First make it clear that the framework must help you do these operations for Findviewbyid (int) and Setonclicklistener (View.onclicklistener), otherwise the code will not work properly2. TheFindviewbyid (int) method requires the ID of the control, which, from the use of the framework, is the ID of the control that tells the framework using annotations
@Injection (value = R.id.bt,click = "ClickView")
the r.id.bt here is value, so we can tell that this is what the framework is, and our click events work, and here we tell the name of the method that the framework needs to call so that one of our common methods can be called
Summary of Ideasso the annotation is a message, it will be read by the framework and the framework will help you do some tedious work, so that your code editing concise, so after using annotations, such as the framework to read, so this is why there is a very strange statement:
Make annotations work Viewinjectionutil.injectview (this);
the code is that the framework reads the information from the annotations and helps you find the control and registers the appropriate event
Start writing codefirst define create an annotationThis is the annotation used above: @Injection, you can understand the concept of creating a class, but the two are different, you have to be clear oh
/** * Operating period is valid, and for the field *  * @author Xiaojinzi * */@Target (Elementtype.field) @Retention (retentionpolicy.runtime)  Public @interface Injection {/** * field corresponds to the ID of the layout file *  * @return */int value ();/** * Click event * @return */string click () default "";/** * Long Press the Click event * @return */string Longclick () Default "";}
Here's an explanation of the code @target (Elementtype.field) means that the annotations we declare are scoped to the field, and you must have seen annotations that work on methods, such as: @Override is this a stranger?@Retention (retentionpolicy.runtime) This indicates that the annotations we declared are valid at the time of operation, and there are other situations where there is no further
Well, our annotations are written, and there are three properties in the annotations that are available, namely:the 1.value int type represents the control's ID2.click String Type Click event's method name3.longClick String type long by event method nameWell, our annotations are finished, you can use this annotation on any field, it will not be an error, but it has no practical effect .
Writing Core Codefirst, create a class that allows the annotations to work, that is, to read the information in the annotations, and then complete the tedious operation.I have a name for: Viewinjectionutil, you can start a different name on your ownThe framework helps you to do Findviewbyid (int), so is it necessary to pass the current Activity object to the framework?
/*** injects fields into activity * * @param act*/public static void Injectview (Activity Act) {//Get all fields in this activity Fie        ld[] fields = Act.getclass (). Getdeclaredfields ();                for (int i = 0; i < fields.length; i++) {//Loop get each field fields field = Fields[i];                        if (Field.isannotationpresent (Injection.class)) {//If this field has an injected annotation//Get annotation Object                        Injection injection = field.getannotation (Injection.class);                        int value = Injection.value (); Field.setaccessible (TRUE);                        You can set the data Object view = null Even if it is private;                                try {view = Act.findviewbyid (value);                        Set the properties of a field Field.set (act, view);                                } catch (Exception e) {e.printstacktrace (); L.s (TAG, "injected property failed:" + field.getcLass (). GetName () + ":" + field.getname ());                                        } try {if (view instanceof view) {                                        View V = (view) view;                                        Gets the method name of the trigger of the Click event String methodName = Injection.click ();                                        EventListener eventlistener = null; If not an empty string if (! "".                                                Equals (MethodName)) {EventListener = new EventListener (act); Set the Click event V.setonclicklistener (eventlist                                                Ener);                                        Eventlistener.setclickmethodname (MethodName);                 } methodName = Injection.longclick ();                       if (! "".                                                        Equals (MethodName)) {if (EventListener = = null) {                                                EventListener = new EventListener (act); }//Set Click event V.setonlongclick                                                Listener (EventListener);                                        Eventlistener.setlongclickmethodname (MethodName);                                        }}} catch (Exception e) {                                E.printstacktrace (); }                        }                }}

/** * Created by Cxj on 2016/1/21. * * @author Small Gold */public class EventListener implements View.onclicklistener, View.onlongclicklistener {/** * class identification */priv ATE String tag = "EventListener";/** * Sets whether there is a log output */private Boolean islog = false;/** * Reflection in the object to be called method, by constructing the method in */private Ob Ject receiver = null;/** * Click event method Name */private string clickmethodname = "";/** * Long Press the name of the event method */private String Longclickmeth Odname = "";/** * Set the method of the click event name * * @param clickmethodname */public void Setclickmethodname (String clickmethodname) {this.cl Ickmethodname = Clickmethodname;} /** * Set Long press the name of the method of the Click event * * @param longclickmethodname */public void Setlongclickmethodname (String longclickmethodname) {th Is.longclickmethodname = Longclickmethodname;} /** * constructor * * @param receiver * control activity or fragment */public EventListener (Object receiver) {this.receive R = Receiver;} @Overridepublic void OnClick (View V) {Method method = Null;try {method = Receiver.getclass (). GetMethod (Clickmethodname); if (Method! = null) {Call the method Method.invoke (receiver);}} catch (Exception e) {if (islog) l.s (tag, "Look for a method with no argument list:" + Clickmethodname + "failed");} try {if (method = = null) {method = Receiver.getclass (). GetMethod (Clickmethodname, View.class); if (Method! = null) {method. Invoke (receiver, v);}}} catch (Exception e) {if (islog) l.s (tag, "Look for a method with the view type parameter:" + Clickmethodname + "failed");}} @Overridepublic boolean Onlongclick (View V) {Method method = Null;try {method = Receiver.getclass (). GetMethod ( Longclickmethodname); if (Method! = null) {//Call the method Method.invoke (receiver);}} catch (Exception e) {if (islog) l.s (tag, "Look for a method with no argument list:" + Longclickmethodname + "failed");} try {if (method = = null) {method = Receiver.getclass (). GetMethod (Longclickmethodname, View.class); if (Method! = null) {Met Hod.invoke (receiver, v);}}} catch (Exception e) {if (islog) l.s (tag, "Look for a method with the view type parameter:" + Longclickmethodname + "failed");} return true;}}

Class EventListener: This class mainly deals with view events, such as click events, Long press events, and classes that implement these interfaceswhen creating the class, it is necessary to pass in the activity object or the Fragment object, such as the method the OnClick (View) method implemented in the class is invoked when the Click event is triggered, but not the method that the user specifies the method name. So here we need to have the click String information in the annotations, that is, the method name of the method that the activity needs to invoke, and with the method name and activity, you can use reflection to invoke the method of specifying the method name from the activity, thus reaching the time when we started the presentation, When you click the button, the method name corresponding to the click written in the note on the BT field in the activity is called.


Here is a detailed explanation of the code in method Injectview (Activity Act):1. Use reflection to get all the fields in the activity2. Loop through all the fields and filter out the fields with injection annotations3. Read the information in the annotations in the field:a) Get the ID information of the control, call Findviewbyid (int) in Act to find the control, assign a value to the field using reflection, the process is equivalent to the normal code:BT = (Button) Findviewbyid (R.ID.BT);b) Get the method name of the method called when the Click event and long press event is triggered, then create the EventListener object, let this object save the method name of the Click event and the method name of the long press event and the activity reference, and register the corresponding event for the View object. EventListener has implemented the corresponding interface, so when registering, the incoming object is EventListener object, the subsequent event is effective when the above class EventListener function.
here actually our code is finished, in fact you understand the knowledge of reflection, the code is not difficult, it will look very quickly, of course, if you do not understand the knowledge of reflection, it is recommended that you go to learn, as a javacoder, I think reflection so great content, you should not miss! Because in the Java world is full of its shadow!
Summarybloggers only introduce click events and long-press events, you can tiger to join other more events, let your framework support more operations, but also more powerfulIn addition, this blog actually give everyone a train of thought, I believe you can write a better small frame!just to make the coding easier!
Small Frame DownloadAnnotated frame: https://github.com/xiaojinzi123/xiaojinzi-openSource-viewAnnotation

Android Custom Annotation Framework

Related Article

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.