The Android app uses Surfaceview to make a walkthrough of a multithreaded Animation _android

Source: Internet
Author: User
Tags clear screen time interval

1. Definition of Surfaceview
Typically, the view and user responses of a program are handled in the same thread, which is why handling long time events (such as accessing a network) needs to be placed in another thread (preventing the current UI thread from being manipulated and drawn). However, you cannot modify UI elements in other threads, such as updating custom view with a background thread (calling view's OnDraw function in Custom view) is not allowed.

If it takes a long time to draw an interface on another thread, require a quick update interface, or render a UI interface, it will take surfaceview. The Surfaceview contains a surface object, and surface can be drawn in a background thread. The nature of Surfaceview determines that it is suitable for some scenes: the need for a rapid interface update, a higher frame rate requirements. The following are some things to note when using Surfaceview:
Both the Surfaceview and Surfaceholder.callback functions are called from the current Surfaceview window thread (typically the main thread of the program). Note the synchronization between the resource state and the drawing thread.
In the drawing thread, the surface must be legally acquired before the content can begin to be drawn, in SurfaceHolder.Callback.surfaceCreated () and SurfaceHolder.Callback.surfaceDestroyed The status between () is valid and is not valid in addition to the surface type for surface_type_push_buffers.
Additional drawing threads consume the resources of the system and should be noted when using Surfaceview.


2. Use of Surfaceview
First inherits the Surfaceview, and implements the Surfaceholder.callback interface, realizes its three methods: Surfacecreated,surfacechanged,surfacedestroyed.
(1) surfacecreated (surfaceholder holder): surface when created, typically starts the drawing thread in the method.
(2) surfacechanged (surfaceholder holder, int format, int width,int height): Surface the size of the change when the call, such as the screen switch.
(3) surfacedestroyed (surfaceholder holder): Surface is destroyed when called, such as exit the game screen, generally stop the drawing thread in the method.
You also need to get surfaceholder and add a callback function so that the three methods are executed.
As long as you inherit the Surfaceview class and implement the Surfaceholder.callback interface, you can implement a custom Surfaceview, Surfaceholder.callback notify surface when the underlying VIEW,SURFA state changes. Ceholder.callback has the following interfaces:
(1) surfacecreated (Surfaceholder holder): The function is called immediately after surface is first created. The program can do some initialization work related to the drawing interface in the function, usually in other threads to draw the interface, so do not draw surface in this function.
(2) surfacechanged (surfaceholder holder, int format, int width,int height): This function is called when the state of the surface (size and format) changes. The function is called at least once after the surfacecreated call.
(3) surfacedestroyed (Surfaceholder holder): When surface is destroyed, the function is called, and the function is invoked so that it cannot continue to use surface, which is generally used to clean up the resource in use.
The Surfaceholder object can be obtained by the Getholder () function of the Surfaceview, Surface within the Surfaceholder object. Although surface preserves the pixel data for the current window, it does not deal directly with surface during use, by Surfaceholder canvas Lockcanvas () or canvas Lockcanvas (Rect dirty) function to get the canvas object and modify the data in the surface by drawing the content on the canvas. If surface is not editable or if the call has not yet been created returns NULL, the content surface in Unlockcanvas () and Lockcanvas () is not cached, so the contents of the surface need to be completely redrawn. In order to improve efficiency only redraw the changed part you can call the Lockcanvas (Rect dirty) function to specify a dirty area so that content outside the area is cached. After the call to the Lockcanvas function acquires Canvas, Surfaceview acquires a synchronous lock of surface until the unlockcanvasandpost (Canvas) function is invoked to release the lock. The synchronization mechanism here guarantees that it will not be altered (destroyed, modified) in the surface rendering process.
When the Canvas is drawn, the function unlockcanvasandpost (Canvas Canvas) is called to notify the system that surface has been drawn so that the system will display the finished content. In order to make full use of the resources of different platforms, the optimal effect of the platform can be set by the Surfaceholder Settype function, which is currently receiving the following parameters:
(1) Surface_type_normal: Common SURFACE with RAM to cache native data
(2) Surface_type_hardware: Applicable to DMA (Direct memory access) engine and hardware acceleration SURFACE
(3) Surface_type_gpu: Suitable for GPU acceleration SURFACE
(4) Surface_type_push_buffers: Indicates that the SURFACE does not contain native data, the data used by SURFACE is provided by other objects, and the SURFACE is used in camera Image preview. Camera is responsible for providing preview surface data so that the image preview will be smoother. If you set this type, you cannot call Lockcanvas to get the canvas object.
The underlying graphics of the access Surfaceview are implemented through the Surfaceholder interface, and the Surfaceholder object can be obtained by Getholder () method. You should implement surfacecreated (Surfaceholder) and surfacedestroyed (Surfaceholder) methods to know when the surface is created and destroyed during the display and hiding of windows.

Note: A surfaceview is available only between SurfaceHolder.Callback.surfaceCreated () and SurfaceHolder.Callback.surfaceDestroyed () calls. The other time is not getting the (null) of its canvas object.
3. Surfaceview Combat
below through a small demo to learn surfaceview in the actual project use, draw an Elf, the wizard has four directions of walking animation, so that the Elves walk the screen four weeks non-stop. Game of the wizard material and the final implementation of the effect diagram:

First create the core class Gameview.java, the source code is as follows:

public class Gameview extends Surfaceview implements Surfaceholder.callback {//Screen wide-high public static int Screen_w
  Idth;
 
  public static int screen_height;
  Private context Mcontext;
  Private Surfaceholder Mholder;
 
  Maximum frame number (1000/30) private static final int draw_interval = 30;
  Private Drawthread Mdrawthread;
  Private Frameanimation []spriteanimations;
  Private Sprite Msprite;
  private int spritewidth = 0;
  private int spriteheight = 0;
  private float spritespeed = (float) ((* screen_width/480) * 0.001);
  private int row = 4;
 
  private int col = 4;
    Public Gamesurfaceview {Super (context);
    This.mcontext = context;
    Mholder = This.getholder ();
    Mholder.addcallback (this);
 
    Initresources ();
  Msprite = new Sprite (spriteanimations,0,0,spritewidth,spriteheight,spritespeed); } private void Initresources () {bitmap[][] Spriteimgs = Generatebitmaparray (Mcontext, R.drawable.sprite, Row, col
    ); Spriteanimations = New Frameanimation[row];
      for (int i = 0; i < row; I + +) {Bitmap []spriteimg = Spriteimgs[i];
      Frameanimation spriteanimation = new Frameanimation (spriteimg,new int[]{150,150,150,150},true);
    Spriteanimations[i] = spriteanimation; {bitmapfactory.options opt = new Bitmapf Bitmap decodebitmapfromres (context context, int resourseid) Actory.
    Options ();
    Opt.inpreferredconfig = Bitmap.Config.RGB_565;
    Opt.inpurgeable = true;
 
    Opt.ininputshareable = true;
    InputStream is = Context.getresources (). Openrawresource (Resourseid);
  Return Bitmapfactory.decodestream (IS, null, opt);
    Public Bitmap CreateBitmap (context context, Bitmap source, int row, int col, int rowtotal, int coltotal) { Bitmap Bitmap = Bitmap.createbitmap (source, (COL-1) * Source.getwidth ()/Coltotal, (row-1) * source.
    GetHeight ()/Rowtotal, Source.getwidth ()/Coltotal, source.getheight ()/rowtotal); return bitmap; Bitmap[][] Generatebitmaparray (context, int resourseid, int row, int col) {Bitmap bitmaps[
    ] [] = new Bitmap[row][col];
    Bitmap Source = decodebitmapfromres (context, Resourseid);
    This.spritewidth = Source.getwidth ()/col;
    This.spriteheight = Source.getheight ()/row; for (int i = 1; I <= row, i++) {for (int j = 1; J <= Col; j +) {Bitmaps[i-1][j-1] = CreateBitmap
      (context, source, I, J, Row, col);
      } if (source!= null &&!source.isrecycled ()) {source.recycle ());
    Source = null;
  return bitmaps; public void surfacechanged (surfaceholder holder, int format, int width, int height) {} public void surf
      Acecreated (Surfaceholder holder) {if (null = = Mdrawthread) {mdrawthread = new drawthread ();
    Mdrawthread.start (); }} public void Surfacedestroyed (Surfaceholder holder) {if (null!= mdrawthread) {Mdrawthread.sTopthread ();
 
    } private class Drawthread extends Thread {public Boolean isrunning = false;
    Public Drawthread () {isrunning = true;
      public void Stopthread () {isrunning = false;
      Boolean workisnotfinish = true;
          while (Workisnotfinish) {try {this.join ()//Guaranteed Run method completed} catch (Interruptedexception e) {
        TODO auto-generated Catch block E.printstacktrace ();
      } Workisnotfinish = false;
      } public void Run () {long deltatime = 0;
      Long ticktime = 0;
      Ticktime = System.currenttimemillis ();
        while (isrunning) {Canvas Canvas = null;
            try {synchronized (mholder) {canvas = Mholder.lockcanvas ();
            Set direction msprite.setdirection ();
            Update wizard location msprite.updateposition (deltatime);
          Drawsprite (canvas); The catch (Exception e) {e). Printstacktrace ();
          finally {if (null!= mholder) {mholder.unlockcanvasandpost (canvas);
        } deltatime = System.currenttimemillis ()-ticktime;
          if (Deltatime < Draw_interval) {try {thread.sleep (draw_interval-deltatime);
          catch (Interruptedexception e) {e.printstacktrace ();
      } ticktime = System.currenttimemillis ();
    }} private void Drawsprite (Canvas Canvas) {//Clear screen operation Canvas.drawcolor (Color.Black);
  Msprite.draw (canvas);
 }
 
}

The

Gameview.java contains a drawing thread drawthread, locking canvas in the thread's Run method, drawing the wizard, updating the wizard location, releasing canvas, and so on. Because the sprite material is a large picture, it is cropped to produce a two-dimensional array. Using this two-dimensional array to initialize the sprite four-direction animation, below look at the Sprite.java source.

public class Sprite {public static final int down = 0;
  public static final int left = 1;
  public static final int right = 2;
 
  public static final int up = 3;
  public float x;
  public float y;
  public int width;
  public int height;
  Elf walking speed public double speed;
  The wizard is currently walking direction public int direction;
 
  Sprite four-direction animation public frameanimation[] frameanimations;
    Public Sprite (frameanimation[] frameanimations, int positionx, int positiony, int width, int height, float speed) {
    This.frameanimations = frameanimations;
    This.x = Positionx;
    This.y = Positiony;
    This.width = width;
    This.height = height;
  This.speed = speed; Updateposition (long deltatime) {switch (direction) {case Left://Let the object move speed is not affected by machine performance, each frame wizard needs
      The distance to move is: move speed * time interval this.x = this.x-(float) (this.speed * deltatime);
    Break
      Case DOWN:THIS.Y = this.y + (float) (this.speed * deltatime);
    Break Case right:this.x = ThiS.x + (float) (this.speed * deltatime);
    Break
      Case UP:THIS.Y = this.y-(float) (this.speed * deltatime);
    Break }/** * According to the current position of the wizard to determine whether to change the direction of walking/public void setdirection () {if (this.x <= 0 && (thi
      S.y + this.height) < Gamesurfaceview.screen_height) {if (this.x < 0) this.x = 0;
    This.direction = Sprite.down; else if ((This.y + this.height) >= gamesurfaceview.screen_height && (this.x + this.width) < Gamesu Rfaceview.screen_width) {if (This.y + this.height) > gamesurfaceview.screen_height) this.y = GAMESURFAC
      Eview.screen_height-this.height;
    This.direction = Sprite.right; else if ((this.x + this.width) >= gamesurfaceview.screen_width && this.y > 0) {if (this.x
      + this.width) > gamesurfaceview.screen_width) this.x = gamesurfaceview.screen_width-this.width;
    This.direction = Sprite.up; } else {if (This.y < 0) This.y = 0;
    This.direction = Sprite.left;
    } public void Draw (Canvas Canvas) {frameanimation frameanimation = frameanimations[this.direction];
    Bitmap Bitmap = Frameanimation.nextframe ();
    if (null!= bitmap) {canvas.drawbitmap (bitmap, x, y, null);
 }
  }
}

The

Wizard class is primarily based on the current position to determine the direction of walking, and then according to the direction of the Walk to update the wizard's position, and then draw their own animation. Because the sprite animation is a frame of a frame of the play picture, so here is encapsulated Frameanimation.java, the source code is as follows:

public class frameanimation{/** animated display of the required resources * * Private bitmap[] bitmaps;
  /** animation per frame display time * * Private int[] duration;
  /** animation on the previous frame display time */protected long lastbitmaptime;
  /** the index value of the animated display to prevent the array from crossing the bounds */protected int step;
  /** Animation Repeat * * protected boolean repeat;
 
  /** animation repeat number of times * * protected int repeatcount;
   /** * @param bitmap: Pictures displayed <br/> * @param duration: Time of picture Display <br/> * @param repeat: Whether to repeat the animation process <br/>
    * * Public frameanimation (bitmap[] bitmaps, int duration[], Boolean repeat) {this.bitmaps = bitmaps;
    this.duration = Duration;
    This.repeat = repeat;
    Lastbitmaptime = null;
  Step = 0;  Public Bitmap NextFrame () {//Judge if step is out of bounds if (step >= bitmaps.length) {//If not infinite loop if (!repeat
      ) {return null;
      else {lastbitmaptime = null;
      } if (null = = Lastbitmaptime) {//First execution lastbitmaptime = System.currenttimemillis ();
    return bitmaps[step = 0]; }//X-time execution Long nowtime = System.currenttimemillis (); if (Nowtime-lastbitmaptime <= Duration[step]) {//If it is still in the duration time period, continue to return the current bitmap//If the value of duration is less than 0, it indicates
    Never fail, generally used for background return bitmaps[step];
    } lastbitmaptime = Nowtime;
 Return bitmaps[step++];//returns next Bitmap}}

Frameanimation returns the current picture frame based on the display time of each frame, and returns to the current frame if it does not exceed the specified time, otherwise the next frame is returned.
The next thing you need to do is let activty display the view that we created before Gameview and then set the full screen display.

public void OnCreate (Bundle savedinstancestate) {
   super.oncreate (savedinstancestate);
 
   GetWindow (). SetFlags (WindowManager.LayoutParams.FLAG_FULLSCREEN,
       WindowManager.LayoutParams.FLAG_ fullscreen);
   Requestwindowfeature (window.feature_no_title);
   GetWindow (). SetFlags (WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON,
       WindowManager.LayoutParams.FLAG_KEEP_ SCREEN_ON);
 
   Displaymetrics outmetrics = new Displaymetrics ();
   This.getwindowmanager (). Getdefaultdisplay (). Getmetrics (outmetrics);
   Gamesurfaceview.screen_width = Outmetrics.widthpixels;
   Gamesurfaceview.screen_height = Outmetrics.heightpixels;
   Gamesurfaceview Gameview = new Gamesurfaceview (this);
   Setcontentview (Gameview);
 }

Now that you're running the Android project, you should see a warrior with a sword walking down the screen.

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.