simple to achieve ripple effect
in fact, the effect of this article is very simple, write this blog focus is to say another thing, play a bit: about memory leaks.
first, the implementation of the effect:
principle:the principle is only one, is the use of shader. shader I see others translated into shaders, in fact it is the role of the brush to increase the color of the gradient, the brush default is a color painting to the end, but the use of shader can be achieved from one color gradient to another color.
to learn more about shader's posture, recommended blog: Portal
with the shader, can be very simple to draw a ripple effect, as for the animation effect, only the dynamic change the size of the picture.
HD Feed Code:
(1) Initializeoverriding construction methods:
Public Bowenview (context context, AttributeSet Attrs) {Super (context, attrs); init ();}
perform the necessary initialization:
private void Init () {//Brush initialization mpaint = new Paint (); Mpaint.setantialias (true);//Send message to start animation loop mhandler.sendemptymessage (0) ;}
Here are some of the needs of the view size as a parameter initialization, I have rewritten the Onsizechanged method, the method is the name of the view is changed when the size of the call will be called, the first time to join the view tree will be called, but at this time the old value is 0 only:
protected void onsizechanged (int w, int h, int oldw, int oldh) {super.onsizechanged (W, H, OLDW, OLDH);//Calculate radius = 1/12 plus 1ra for longer edges Dius = w > H? W/12 + 1:h/12 + 1;//ICC coordinates cx = W/2;cy = h/2;//Initialize ring shader radialgradient = new Radialgradient (W/2, H/2, radius , 0x88ffffff, 0XAAFFFFFF, tilemode.repeat); Mpaint.setshader (radialgradient);//Initialize center image location BITMAPRECTF = new RECTF (CX- Radius, Cy-radius, CX + radius, CY + radius);}
to achieve our results we need a ring shader, plus a linear and rounded one, and more content to view the blogs that are recommended above.
simply say Radialgradient's construction parameters:radialgradient (x, Y, H, color0, Color1, tile)x and Y are the center coordinates, h is the radius of the gradient, here is set for our calculation of the small radius, with our set Tilemode.repeat mode, will have the above lap of the effect, if H is set to the width or height of the view, then the display only a circle. As for the Tilemode there are 3 modes, interested can try different modes under the difference of effect. Color0 is the start color and will fade to the terminating color color1. It's all set to white, but the transparency is different.
(2) Center imageprovide a way to set the center image to be displayed externally, and then draw it in the OnDraw method, as the position has been computed at the time of the previous initialization:
Private Bitmap centerbitmap;public void Setcenterbitmap (Bitmap Bitmap) {centerbitmap = Bitmap;invalidate ();}
(3) animation implementationas I said before, animation only changes the circle size of the picture dynamically, and here we use a handler to loop the message:
Handler Mhandler = new Handler (new Handler.callback () {@Overridepublic Boolean handlemessage (Message msg) {LOG.E ("Bowen" , "Handlemessage"); if (scale >= 6) {scale = 0;} Scale++;invalidate (); mhandler.sendemptymessagedelayed (0, +); return false;}});
The size of the circle to be drawn is controlled by the value of the scale.
(4) Start painting
protected void OnDraw (canvas canvas) {//Draw circles, control size canvas.drawcircle (CX, CY, CX > CY) according to Sacle? CX * SCALE/6: CY * Scale /6, Mpaint);//If you have an image set, just draw it in the middle if (centerbitmap! = null) {Canvas.drawbitmap (Centerbitmap, NULL, BITMAPRECTF, NULL);}}
Well, finish it and put it in the activity experiment:
protected void OnCreate (Bundle savedinstancestate) {super.oncreate (savedinstancestate); Setcontentview ( R.layout.activity_main);//Set Center image ((Bowenview) Findviewbyid (R.id.bowen)). Setcenterbitmap ( Bitmapfactory.decoderesource (Getresources (), R.drawable.dun));}
The effect came out, everything was gone, two plates and then went to bed.
The mobile phone also shows the activity of the demo, click the Home button to return to the desktop. Just then, the horrible thing happened, Logcat also has been printing the Handlemessage method of printing information. This means that handler is not recycled, handler is a member variable of Bowenview,handler cannot be recycled, which means bowenview cannot be recycled, and Bowenview has an activity reference. means that the entire activity cannot be recycled until the application is actually closed (that is, before the process is destroyed), which is not a memory leak, I actually built a bomb.
an oft-made mistake:
in fact, the use of handler in the activity of the same problem, this problem occurs because:
understand the following two sentences before continuing to look down:(1) Garbage collection based rule: only objects that are not referenced are recycled.
(2) in Java: Non-static (anonymous) inner classes refer to external class objects.
When you send a delay message, the message is added to a global message queue, and the message is sent to our handler when the time arrives to be delayed. (For those unfamiliar with the handler mechanism, please refer to my other blog: portal)
If, in the middle of the process, we exit the activity, when the garbage collector is ready to recycle the activity, it is found that there is a reference to the handler in the global Message queue .so the handler cannot be recycled.
If this is the case, handler is the member variable of the view,that is, handler refers to view, and view refers to activity,activity reference a lot of things, so a lot of things will occupy the memory, and we also can not access,The garbage collector is not recyclable.
if it is in the same is true of the use of handler in activity, that is, handler is a non-static inner class of activity, that is, handler refers to activity, that is, Handler's inability to recycle will also cause the activity to not be recycled.
If the activity accounts for memory, then memory leaks accumulate, which can easily cause oom, and the cause is hard to troubleshoot. (from the point of view of destruction, I did a very good job)
Workaround:in fact, my findings are based on this blog: Portal This blog also provides a workaround by writing handler as a static class and preserving a soft reference to the activity inside the handler.
Here's my workaround:
(1) Use handler in view:The onwindowvisibilitychanged method can be overridden in the view class, and when the window to which the activity belongs becomes invisible, the message that we send is removed from the message queue and the code is modified as follows:
protected void onwindowvisibilitychanged (int visibility) {super.onwindowvisibilitychanged (visibility); visibility = = View.gone) {log.e ("Bowen", "Window-gone"); mhandler.removemessages (0);} else if (visibility = = view.visible) {log.e ("Bowen", "window-visible"); mhandler.sendemptymessage (0);}}
Remember to remove the previous statement that sent the message in the Init method:
private void Init () {//Brush initialization mpaint = new Paint (); Mpaint.setantialias (true);//Send message to start animation loop//mhandler.sendemptymessage ( 0);}
(2) Use handler in activity:similar to the above, override the OnStop method and remove the message in the OnStop method.
I am the legend of the//slightly ...
Demo Download
Android Curious baby _ watch face World _06