"Android" Android dynamic agent adds hooks for Surfaceholder

Source: Internet
Author: User

This blog will describe a usage scenario for dynamic proxies in Android applications.

Proxy mode

The role of proxy mode is to provide a proxy for other objects to control access to this object. For example, users call a "eat" method, if you do not rely on the agent, the user may eat their own bowl of rice, and if through the agent, may not even bowl do not need the user to take, the user only need to open the mouth, agent to feed on the line, it is necessary to note that Here agent in addition to take the bowl and feeding outside can do anything else, such as help you to cool some of the food, or worry about your weight and secretly help you pour out half of the meal, or to add something strange things, who know, this is the agent of the job. In fact, in Java also provides a proxy this magic mode, but also divided into static and dynamic two, the difference is that the static agent structure before the program has been scheduled to run, and dynamic agent is in the process of running the program is specified, this article is the use of dynamic proxy method.

Mirror Flip

In a previous blog "Android" Android image rollover analyzed how to mirror a view to flip, that is to achieve the following effect:

Mirror horizontal rollover before and after effects

For general view, this effect is achieved directly with View.setscaley (-1), and for custom Surfaceview, you can also use

Canvas.scale ( -1,1,canvas.getwidth ()/2,canvas.getheight ()/2)

To flip them. However, if you are facing a third-party surfaceview and cannot get directly to the canvas object that Surfaceview uses to draw. For example, the implementation code on the left is shown below.

public class Testsurfaceview extends Surfaceview implements Surfaceholder.callback {public    Testsurfaceview ( Context context, AttributeSet Attrs) {        Super (context, attrs);        Getholder (). Addcallback (this);    }    @Override public    void surfacecreated (Surfaceholder holder) {        //get canvas canvas canvas        = Holder.lockcanvas ();        Canvas.drawcolor (Color.rgb (220,220,220));        Paint paint = new paint ();        Paint.settextsize ();        Draw text        canvas.drawtext ("Hello, this is Surfaceview", 200,600,paint);        Draw round        canvas.drawcircle (300,800,100,paint);        Display        holder.unlockcanvasandpost (canvas);    }    @Override public    void surfacechanged (surfaceholder holder, int format, int width, int height) {}    @Override 
   public void surfacedestroyed (Surfaceholder holder) {}}

Assume that the Testsurfaceview is in a third-party jar package and cannot be modified. So how to mirror the interface to flip it, the following is given by the dynamic Agent implementation of the scheme

SOURCE Analysis

In combination with the above code, we know that the Surfaceview drawing process is as follows:


Surfaceview Drawing Process

The usual calling code is as follows:

Get canvas canvas for canvas canvas = Holder.lockcanvas ();//Draw content ...//unlock canvas, display canvas content holder.unlockcanvasandpost (canvas);
What is holder, we can find Surfaceholder instance msurfaceholder and implement in the source code of Surfaceview.

public class Surfaceview extends View {...    Private final Surfaceholder Msurfaceholder = new Surfaceholder () {        private static final String Log_tag = "Surfaceholde R ";        @Override Public        Boolean iscreating () {            return miscreating;        }        ......        @Override public        Canvas Lockcanvas () {            return Internallockcanvas (null);        }        @Override public        Canvas Lockcanvas (Rect inoutdirty) {            return Internallockcanvas (Inoutdirty);        }        ......    };}

In the source code, we can see Msurfaceholder implemented the Lockcanvas method, and returned to the canvas, here is the breach.

Agent implementation

The goal of the agent is to monitor the Lockcanvas method in the Surfaceholder and add some action to its return value, that is, to change the original process to the following structure:


Dynamic Proxy Add access control

The first thing you need to implement is the agent processor, whose code is as follows:

public class Testinvocation implements Invocationhandler {    Object mobject;    Public Testinvocation (Object object) {        Mobject = object;    }    @Override Public    object Invoke (Object proxy, Method method, object[] args) throws Throwable {        //intercept Lockcanvas method call        if ("Lockcanvas". Equals (Method.getname ())) {            ///Lockcanvas method return value is the canvas canvas canvases canvas            = (canvas) Method.invoke (Mobject,args);            Add Mirror            Canvas.scale ( -1,1,canvas.getwidth ()/2,canvas.getheight ()/2);            return canvas;        }        Return Method.invoke (Mobject,args);}    }

The proxy processor does this by filtering out the Lockcanvas method at invoke, then executing the Lockcanvas method, and getting the return value, which is the canvas object, which is what Surfaceview is going to paint on. So here we can add a mirror rollover effect to the agent beforehand, and then return to the normal process to continue execution after the addition is complete.

After completing the agent processor, you can add the dynamic agent for Surfaceholder, it is important to note that surfaceholder in Surfaceview, the need to take out first, and then add the agent, the code is as follows:

Get Surfaceholdersurfaceholder msurfaceholder in Surfaceview = Mtestsurfaceview.getholder ();// Create an implementation of the Proxy interface testinvocation testinvocation = new Testinvocation (msurfaceholder);//Add a dynamic proxy for msurfaceholder and get the add agent Newsurfaceholdersurfaceholder Newsurfaceholder = (surfaceholder) proxy.newproxyinstance (MSurfaceHolder.getClass (). getClassLoader (), Msurfaceholder.getclass (). Getinterfaces (), testinvocation);
The newly generated newsurfaceholder is the surfaceholder that has been added on the dynamic proxy because Surfaceholder is a private property in Surfaceview and cannot be replaced directly. So here we need to use the reflection mechanism to Newsurfaceholder replace the original Msurfaceholder in Surfaceview, the code is as follows:

Get msurfaceholder Fieldfield Fieldholder = SurfaceView.class.getDeclaredField ("Msurfaceholder");// Change to accessible permission fieldholder.setaccessible (true);//replace Msurfaceholderfieldholder.set with Newsurfaceholder after adding the agent ( Mtestsurfaceview,newsurfaceholder);

After adding the dynamic agent, the Lockcanvas method that calls holder in Testsurfaceview gets the canvas that is testinvocation transpose, which realizes this strange need, that is, the effect of the picture on the right.


Source code Download the entire project source code is as follows

Android Dynamic Agent Practice


"Android" Android dynamic agent adds hooks for Surfaceholder

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.