The use of Butterknife greatly facilitates the development of Android programmers, in fact, we can imitate the implementation of their own.
The first is to understand the use of Java annotations.
We will first declare a @interface, which is the annotation class:
@Target (Elementtype.field)// = used on field s @Retention (retentionpolicy.runtime)// Indicates that the life cycle is run-time public @Interface viewbinder { intdefault -1 ; default ""; default "";}
@interface is used for custom annotations, the declaration of a method defined in it cannot have parameters, cannot throw an exception, and the return value of the method is limited to simple type, String, Class, Emnus, @interface, and arrays of these types.
The annotation @Target is also a meta-annotation used to modify annotations, which has an attribute ElementType is also an enumeration type with values of: Annotation_type,constructor, Field,local_variable, Method,package,parameter and type, such as a @Target (elementtype.method)-modified annotation, indicate that the annotation can only be used to decorate the method.
@RetentionRetention annotations indicate the level at which this comment information needs to be saved to describe the life cycle of the annotation, which has a value of type Retentionpolicy, is an enumeration type, and has several values as follows:
1. With @retention (retentionpolicy.source) modified annotations, the specified annotations are retained only in the source file, compiled into a class file, the annotations are removed;
2. Annotated with @retention (Retentionpolicy.class), specifies that annotations are retained only in the source file and the compiled class file, and the annotations are removed when the JVM loads the class;
3. With @retention (retentionpolicy.runtime) modified annotations, the specified annotations can be retained in the JVM so that the information can be obtained using reflection.
The default is runtime, so that we can get through reflection and do the corresponding logic processing when we run.
The next step is to use reflection to get the attributes of the annotations and to do the appropriate processing:
Public classViewbinderparserImplementsparsable {PrivateViewbinderparser () {} Public Static voidinject (Object object) {Viewbinderparser parser=NewViewbinderparser (); Try{Parser.parse (object); } Catch(Exception e) {LOGUTIL.E (e.tostring ()); }} @Override Public voidParseFinalObject object)throwsException {View View=NULL; FinalClass<?> Clazz =Object.getclass (); Field[] Fields= Clazz.getdeclaredfields ();//get the fields declared in activity for(Field field:fields) {//See if this field has our own custom annotation class flags. if(Field.isannotationpresent (Viewbinder.class) {Viewbinder inject= Field.getannotation (Viewbinder.class); intID =inject.id (); if(ID < 0) { Throw NewException ("ID must not is null"); } if(ID > 0) {field.setaccessible (true); if(ObjectinstanceofView) {View=( (View) object). Findviewbyid (ID); } Else if(ObjectinstanceofActivity) {View=( Activity) object). Findviewbyid (ID); } Field.set (object, view);//set the value for the field we're looking for.String MethodName =Inject.method (); if(!methodname.equals ("") {Oneventlistener listener=NewOneventlistener (object); String type=Inject.type (); if(Type.equals ("")) { Throw NewException ("Please input the type of Method,such as ' Method=onclick '"); } if(Type.equals ("OnClick") {Listener.setonclick (ID, methodName); } } } } } }}
We pass the annotated object through inject and enter the parsing method of the annotation attribute.
Use reflection to get all the declared fields, and then use the Isannotationpresent method to see if the field has an annotated type added, then get the annotations from that field and get the corresponding property values by a defined method. We get the ID of the corresponding view here, and then we initialize the view here, as well as the binding of the event.
The binding of the completion event also requires a class:
Public classOneventlistener {PrivateObject object; PublicOneventlistener (Object object) { This. Object =object; } Public voidSetonclick (intIdFinalString MethodName) {View View=NULL; if(ObjectinstanceofView) {View=( (View) object). Findviewbyid (ID); } Else if(ObjectinstanceofActivity) {View=( Activity) object). Findviewbyid (ID); } view.setonclicklistener (NewView.onclicklistener () {@Override Public voidOnClick (View v) {Methodmodel Methodmodel=NewMethodmodel (); Class Clazz=Methodmodel.getclass (); Try{Method Method= Clazz.getmethod (MethodName,Newclass[]{}); Method.invoke (Methodmodel,Newobject[]{}); } Catch(nosuchmethodexception e) {e.printstacktrace (); } Catch(InvocationTargetException e) {e.printstacktrace (); } Catch(illegalaccessexception e) {e.printstacktrace (); } } }); }}
Currently only the binding of the Click event is implemented.
Then we can use our custom annotations like this:
Public classMainactivityextendsactionbaractivity {@ViewBinder (id=r.id.cet_receiver)protectedCustomedittext Cetreceiver; @ViewBinder (ID=r.id.cet_cc)protectedCustomedittext CETCC; @ViewBinder (ID=r.id.cet_content)protectedCustomedittext cetcontent; @ViewBinder (ID=r.id.cet_subject)protectedCustomedittext Cetsubject; @ViewBinder (ID=r.id.iv_receiver)protectedImageView Ivreceiver; @Overrideprotected voidonCreate (Bundle savedinstancestate) {Super. OnCreate (savedinstancestate); Setcontentview (R.layout.activity_main); Viewbinderparser.inject ( This); Ivreceiver.setonclicklistener (NewView.onclicklistener () {@Override Public voidOnClick (View v) {cetcc.setvisibility (view.visible); } }); }}
The use of annotations can make our code more concise, but only if this premise is necessary.
The first step of Android annotation programming---mimic the viewbinder mechanism of Butterknife