The ubiquitous design pattern in Android development--Dynamic proxy mode

Source: Internet
Author: User

Continue to update the design pattern series, the main reason to write this pattern is recently saw the dynamic agent code.
Let's look at the first 5 modes:
-Ubiquitous design pattern in Android development--Singleton mode
-Ubiquitous design pattern--builder mode in Android development
-Ubiquitous design patterns in Android development--Viewer mode
-Ubiquitous design patterns in Android development-prototype mode
-Ubiquitous design patterns in Android development--Strategy mode

The application of dynamic proxy mode in the Java Web is ubiquitous, especially in the spring framework, where dynamic proxies are used extensively, and one of the most important design patterns is the most difficult to understand.

So what is a dynamic agent?

The proxy class does not exist before the program runs, and the proxy mode that is dynamically generated by the program is called a dynamic proxy.

The current network request library is diverse, where Square's okhttp is a perfect network request library, and it encapsulates a layer of retrofit libraries, providing a quick way to quickly and easily invoke restful APIs. If you've ever used retrofit, you'll never forget that there is a process:

    • First, define an interface, define the specific method of the network request in the interface, and configure the Host,header,params information through annotations on the method.

    • Then create a new retrofit object that produces an interface object that you define.

    • A specific method is called through the interface object to complete the request.

It looks like this:

 > Listrepos (@Path ("user") String user);}" Data-snippet-id= " ext.fadc3883ecfd2cd1a1ca67e15e7b1971 "data-snippet-saved=" false "data-csrftoken=" 5vgx1wh4-w-l4cpyta7c6psnrxdn_ HUUX6FK ">public  interface  githubservice  {  @GET   ( "Users/{user}/repos" ) Call<list<repo>> Listrepos ( @Path  () String user);  
retrofit Retrofit = new Retrofit () .baseurl  ( "https:// Api.github.com ") .build  ()  Githubservice service = Retrofit.create  (Githubservice.class )   
Call<List<Repo>> repos = service.listRepos("octocat");

Then you have not thought of a problem, interface is not directly new out, Githubservice interface instance is how to produce, retrofit.create method inside exactly what did it. Yes, the answer is dynamic proxy. The object is the proxy object generated by the program's run time.

Dynamic Proxy Although in the Java Web A lot of use, but in the client, due to the performance of the problem, so with dynamic agent will be considered carefully, but once the dynamic agent with good, will have a different effect, such as this retrofit library. Below, we implement the most simple version of a retrofit. The principle of a dynamic agent. Because it is a simple version, so a lot of things and retrofit still have a gap, and naturally there is no retrofit so convenient, this disregard is good. Let's take the example above:

First of all, our request is asynchronous, so the return value we use void, add a callback parameter, the last argument is a callback.

public interface Callback<T> {    void onSuccess(Object t);    void onFailed(Exception e);}

The final interface definition will look like this.

 > Callback); /** * Convention The last parameter is callback */} "data-snippet-id=" Ext.f115dcec337f47ddaaf65522ab40a2e0 "data-snippet-saved=" false "dat A-csrftoken= "Hoczseoz-2rnrlcsbrh9aw4trrluk_l6c1d4" >public  interface   Githubservice  {  @GET  () void  listrepos ( @Path  ( "user" ) string user,callback<list<repo>> Callback); /** * Convention the last parameter is callback */}  

Two annotations are used, one is the method annotation, the other is the parameter annotation

@Retention(RetentionPolicy.RUNTIME)@Target({ElementType.METHOD})public @interface GET {    valuedefault"";}
@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.PARAMETER)public @interface Path {    value();}

The repo entity class is automatically generated using Gsonformat based on JSON.

Then we write the retrofit class, this class should be a builder mode, which can be set baseurl, ignoring all the other parameters. There is also a create method, the prototype is as follows:

 Public classRetrofit {PrivateString BaseUrl;Private Retrofit(Builder builder) { This. baseUrl = Builder.baseurl; } Public<T> TCreate(Class<t> clazz) {return NULL}StaticClass Builder {PrivateString BaseUrl; Builder BaseUrl (String host) { This. BASEURL = host;return  This; } Retrofit Build () {return NewRetrofit ( This); }    }}

The most critical content is the implementation of the Create method. The principle is to get the last parameter, that is, the callback, then get the annotation on the method, get the concrete value, then get the other parameters except the callback, get the annotation on the parameter, and then get the corresponding value according to the annotation, and the original parameter value, and replace the value of the annotation on the method. Use Okhttp to construct the request, after the request is completed, according to the type that resolves the result to the callback. The whole process is as follows

 Public<T> TCreate(Class<t> clazz) {/** * Cache in the go * /Object o = servicemap.get (clazz);/** * Do not fetch the construction agent object * /        if(O = =NULL) {o = (T) proxy.newproxyinstance (Retrofit.class.getClassLoader (),NewClass[]{clazz},NewInvocationhandler () {@Override                 PublicObjectInvoke(Object Proxy, Method method, object[] args)throwsThrowable {FinalCallback<?> Callback = (callback<?>) args[args.length-1];FinalGet get = Method.getannotation (Get.class);if(Get! =NULL) {/** * Get the value of Get annotations */String GetValue = Get.value (); System.out.println (GetValue);/** * Get annotations on all parameters */annotation[][] Methodparameterannotationarrays = Method.getparameterannotations ();if(Methodparameterannotationarrays! =NULL) {intCount = Methodparameterannotationarrays.length; for(inti =0; I < count; i++) {/** * Get annotations on a single parameter */annotation[] methodparameterannotations = methodparameterannotationarrays[i];if(Methodparameterannotations! =NULL) { for(Annotation methodparameterannotation:methodparameterannotations) {/** * If it is path annotation */                                        if(methodparameterannotationinstanceofPath) {/** * Get the value on the path annotation */Path PATH = (path) methodparameterannotation;                                            String Pathvalue = Path.value (); System.out.println (Pathvalue);/** * This is the value of the corresponding parameter */System.out.println (Args[i]); Request.builder Builder =NewRequest.builder ();/** * Replace the values in the Get annotations with the path annotations as parameter values * /String result = Getvalue.replaceall ("\\{"+ Pathvalue +"\\}", (String) args[i]); SYSTEM.OUT.PRINTLN (result);/** * Start Construction request * /Request Request = Builder.get (). URL (baseUrl +"/"+ result). Build (); Okhttpclient.newcall (Request). Enqueue (NewOKHTTP3. Callback () {@Override                                                 Public void onfailure(Call call, IOException e) {/** * Failed callback method */Callback.onfailed (e); }@Override                                                 Public void Onresponse(Call call, Response Response)throwsIOException {if(Response.issuccessful ()) {/** * Request succeeded */String BODY = Response.body (). String ();/** * Zhuan conversion with Fastjson */Type type = Callback.getclass (). Getgenericinterfaces () [0]; Object O1 = json.parse (body);/** * Callback succeeded */Callback.onsuccess (O1);                                        }                                                }                                            });                        }                                    }                                }                            } }                    }return NULL; }            });/** * Thrown into the cache * /Servicemap.put (Clazz, O); }return(T) O; }

And then we can call it according to retrofit.

new Retrofit.Builder()        .baseUrl("https://api.github.com")        .build();GithubService githubService = retrofit.create(GithubService.class);githubService.listRepos("lizhangqu"new Callback<List<Repo>>() {    @Override    publicvoidonSuccess(Object t) {        System.out.println(t);    }    @Override    publicvoidonFailed(Exception e) {    }});

This is just the simplest of the retrofit module implementation, if you are interested in other content, you can read the source code of retrofit.

The ubiquitous design pattern in Android development--Dynamic proxy mode

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.