Android advanced tutorial teaches you how to build the IOC framework [ViewInject] (lower) and androidviewinject in Android

Source: Internet
Author: User

Android advanced tutorial teaches you how to build the IOC framework [ViewInject] (lower) and androidviewinject in Android

In the previous blog, we have brought you a simple idea of IoC, implementing the View layout and Control Injection in the Activity. If you do not know about it, refer: android advanced tutorial teaches you how to build the IOC framework [ViewInject] (I) in Android ).

This blog will show you how to inject View events.

1. Target results

In the previous blog, we wrote the event Code as follows:

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, "Why do you click me ?",Toast.LENGTH_SHORT).show();break;case R.id.id_btn02:Toast.makeText(MainActivity.this, "I am sleeping !!!",Toast.LENGTH_SHORT).show();break;}}}

Can we inject a View? We write a View for interaction purposes. You have to click Shenma. Instead of the traditional Shenma, setOnClickListener, and then implement the Anonymous class or other methods of Shenma, we changed:

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;}}}

Add annotations directly to any method in the Activity to inject events of one or more controls. Here I moved onCreate to BaseActivity, which calls ViewInjectUtils. inject (this );

2. Implementation 1. annotation 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 for OnClick annotations. After all, there are many events, and the listener name, listener type, and called method names are fixed, corresponding to the above Code:

ListenerType = View. OnClickListener. class, listenerSetter = "setOnClickListener", methodName = "onClick"

Onclick is used to write data in a method of Activity:

@OnClick({ R.id.id_btn, R.id.id_btn02 })public void clickBtnInvoked(View view)

If you still remember, we already have two methods in the previous blog's ViewInjectUtils. inject (this); and there is one more in this article:

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> clazz = activity. getClass (); Method [] methods = clazz. getMethods (); // traverses all methods for (Method method: methods) {Annotation [] annotations = method. getAnnotations (); // get all the annotations on the method for (Annotation annotation: annotations) {Class <? Extends Annotation> annotationType = annotation. annotationType (); // get the Annotation EventBase eventBaseAnnotation = annotationType. getAnnotation (EventBase. class); // if it is set to EventBaseif (eventBaseAnnotation! = Null) {// retrieve the listener name, listener type, and call method name String listenerSetter = eventBaseAnnotation. listenerSetter (); Class <?> ListenerType = eventBaseAnnotation. listenerType (); String methodName = eventBaseAnnotation. methodName (); try {// get the value Method aMethod = annotationType In The Onclick annotation. getDeclaredMethod ("value"); // retrieve all viewIdint [] viewIds = (int []) aMethod. invoke (annotation, null); // set the proxy DynamicHandler handler = new DynamicHandler (activity) through InvocationHandler; handler. addMethod (methodName, method); Object listener = Proxy. n EwProxyInstance (listenerType. getClassLoader (), new Class <?> [] {ListenerType}, handler); // traverses all views and sets the event for (int viewId: viewIds) {View = activity. findViewById (viewId); Method setEventListenerMethod = view. getClass (). getMethod (listenerSetter, listenerType); setEventListenerMethod. invoke (view, listener) ;}} catch (Exception e) {e. printStackTrace ();}}}}}

Well, the annotation is as detailed as possible, mainly to traverse all the methods, get the OnClick annotation of the method, and then get the EventBase Annotation on the annotation, obtain the name, type, and name of the method to be called for event listening. Obtain the Proxy object of the listener through Proxy and InvocationHandler, and display the set method, finally, set the listener through reflection.

The difficulty here is about the emergence of DynamicHandler and Proxy. If you don't understand it, I will explain it in detail later.

3. DynamicHandler

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);public 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){return method.invoke(handler, args);}}return null;}}
Well, there are so many codes, so we can implement the event injection ~~

:


In fact, they are all the same ~~~

3. About proxy

So, is this article over? No ~~~ I'm sure you are confused about the following lines of code. What have you done?

// Use InvocationHandler to set the proxy DynamicHandler handler = new DynamicHandler (activity); handler. addMethod (methodName, method); Object listener = Proxy. newProxyInstance (listenerType. getClassLoader (), new Class <?> [] {ListenerType}, handler );


InvocationHandler and Proxy appear in pairs. If you are familiar with Java, you will surely think of Java's 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 is still quite good, after all, someone review there are bonuses ~

However, there are some differences in our implementation. Why do we have doubts, such as reflection implementation:

MBtn2.setOnClickListener (this); where are the difficulties of such code?

1. Obtain mBtn2? So easy

2. Call setOnClickListener? So easy

But, this, this is an instance of the OnClickListener implementation class, OnClickListener is an interface ~~ How is your implementation class rounded up? I have heard of reflection on the newInstance object, but now you are an interface!

Yes ~ Now I should understand what the above lines of code have done? Implements a proxy object for the interface, and then processes the interface call method in the invoke of the proxy class.

4. Code is the best teacher

No one can understand it. What are you doing here ?? The following code is used to simulate the implementation of this scenario:

The Main class implements a Button. The Button has two methods: setOnClickListener and onClick. When the Button onClick is called, the event triggered is the click method in the Main class.

Four 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 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>();public void addMethod(String methodName, Method method){methods.put(methodName, method);}@Overridepublic Object invoke(Object proxy, Method method, Object[] args)throws Throwable{String methodName = method.getName();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();public 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 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();}}

Click the simulated button: Call main. button. click (), but the actual execution is the Main click method.

In init, we first Initialize an OnClickListenerHandler, pass in the current instance of Main, get the click method of Main, and add it to the Map in OnClickListenerHandler.

Then, the Proxy. newProxyInstance is used to obtain a Proxy for the OnClickListener interface. In this way, all methods for executing this interface will call the OnClickListenerHandler invoke method.

But what? OnClickListener is an interface after all, and there is no method body ~~ What should we do? At this time, we reached out in the Map in 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 be executed is saved to the Map through key-value pairs. When invoke is called, the stored method in the Map is obtained through the passed method name, then call our preset method ~.

In this way, you should understand that, in fact, you get a Proxy of the interface through the Proxy, and then use a Map pre-setting method in InvocationHandler to implement The onClick of the Button, is associated with the click of Main.

Now let's look at the code in InjectEvents:

// Use InvocationHandler to set the proxy DynamicHandler handler = new DynamicHandler (activity); // Add the method handler to map. addMethod (methodName, method); Object listener = Proxy. newProxyInstance (listenerType. getClassLoader (), new Class <?> [] {ListenerType}, handler );

Is it similar to the one in init ~~

Now, we have explained how to reconcile the interface and link the methods in our Activity ~~~


Note: Some codes refer to the xUtils framework. After all, it is not enough to implement a complete injection for one or two blogs, but the core and skeleton have been implemented ~~ If you are interested, you can continue to improve it ~




Download source code











What are common android design patterns or frameworks? I am talking about the most common SSH frameworks, such as those in j2ee.

There is no framework in android.
Just do it well by following the mvc layering principle. Some open-source libraries such as facebook also have a lot of open-source libraries. You can consider using it.

Familiar with Android Application and framework development. I hope to use the Android system from top to bottom to provide a tutorial on android embedded underlying development.

Baidu liberal arts, Netease video College, Baidu course, Youku, and 51 search on the self-learning network, there should be
Open Courses on various websites
------------------ @ Select a satisfactory answer @------------------
 

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.