Android Draw SurfaceView In Thread Example

SurfaceView is a view with a surface. It is a sub class of android.view.View. So it is similar with other views, it can receive user input on the screen, it also inherits all view life cycle callback functions.

1. SurfaceView Overview.

SurfaceView has independent surface from window object. So you can draw on the surface in a child thread which is so called rendering thread. After rendering you need to post a message to the main thread to let the surface canvas drawing be drawn on the main thread UI view canvas again.

surfaceview and view

Surface can be destroyed. It only works in between SurfaceHolder.Callback.surfaceCreated() and SurfaceHolder.Callback.surfaceDestroyed() method. The two methods will be invoked when the surface is created and destroyed.

SurfaceHolder.CallBack instance is added to SurfaceHolder by using SurfaceHolder’s addCallback method. And you can call SurfaceView’s getHolder() method to get it’s SurfaceHolder.

Generally we let’s the custom SurfaceView class implement SurfaceHolder.CallBack interface and add the SurfaceView class instance to the SurfaceHolder, the SurfaceView can then listen to the creation and destruction of this Surface.

2. SurfaceHolder Overview.

SurfaceHolder is the wrapper for SurfaceView’s Surface.¬†SurfaceHolder is not only responsible for Surface creation and destruction callbacks in the SurfaceHolder.callback interface, but also for thread-safe wrapping of key methods of Surface such as LockCanvas () and unLockCanvasAndPost ().

So SurfaceHolder is the owner of the Surface object and is responsible for calling methods that operate on the Surface during the Surface’s life cycle. For example the SurfaceHolder’s lockCanvas(Rect Rect) method can specify a rectangle area as invalidate data in the rectangle and redraw some data on it.

surfaceview surfaceholder surface relation

3. SurfaceView Usage Steps.

  1. Get the SurfaceView related SurfaceHolder object and add a SurfaceHolder.Callback object to the SurfaceHolder.
  2. Create the rendering thread object.
  3. Start drawing on the Surface in the child thread.
  4. Because we can not get the Surface object directly, so we should use the SurfaceHolder’s lockCanvas () to get the Canvas of the specified area above the Surface and draw graphics on the canvas.
  5. When the painting is finished, use the SurfaceHolder’s unlockCanvasAndPost () method to unlock the Canvas and let the UI thread draw the Surface canvas drawing to the view’s canvas.
READ :   Android SurfaceView Drawing Example

4. Android SurfaceView Use Thread Drawing Example.

When you input a text in the input text box and click enter key, the text will be drawn with move animation from top left to bottom right in the blue rectangle at bottom.

5. Draw In SurfaceView Use Thread Example Source Code.

draw surfaceview use thread source files

5.1 Main Activity.

MainActivity.java

package com.dev2qa.surfaceviewthread;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.KeyEvent;
import android.view.View;
import android.view.WindowManager;
import android.widget.EditText;
import android.widget.LinearLayout;

import java.security.Key;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        setTitle("dev2qa.com - Android Draw SurfaceView In Thread Example.");

        // Hide app title bar.
        getSupportActionBar().hide();

        // Make app full screen to hide top status bar.
        this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);

        // Create the SurfaceViewThread object.
        final SurfaceViewThread surfaceViewThread = new SurfaceViewThread(getApplicationContext());

        // Get text drawing LinearLayout canvas.
        LinearLayout drawTextCanvas = (LinearLayout)findViewById(R.id.drawTextCanvas);

        // Add surfaceview object to the LinearLayout object.
        drawTextCanvas.addView(surfaceViewThread);

        // Get the edittext input text box.
        final EditText inputText = (EditText)findViewById(R.id.inputText);

        // Add key listener to listen to key type event.
        inputText.setOnKeyListener(new View.OnKeyListener() {
            @Override
            public boolean onKey(View view, int keyCode, KeyEvent keyEvent) {

                // If user input enter key.
                if(keyCode == KeyEvent.KEYCODE_ENTER) {
                    // Get user input text.
                    String userInputText = inputText.getText().toString();
                    // Set the text to custom SurfaceView object.
                    surfaceViewThread.setText(userInputText);
                    // Means the key event has been processed.
                    return true;
                }else
                {
                    return false;
                }
            }
        });
    }
}

5.2 SurfaceView Use Thread Java Class.

SurfaceViewThread.java

package com.dev2qa.surfaceviewthread;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.text.TextUtils;
import android.util.Log;
import android.view.SurfaceView;
import android.view.SurfaceHolder;

import java.util.logging.Logger;

/**
 * Created by zhaosong on 2018/6/17.
 */

public class SurfaceViewThread extends SurfaceView implements SurfaceHolder.Callback, Runnable {

    private SurfaceHolder surfaceHolder = null;

    private Paint paint = null;

    private Thread thread = null;

    // Record whether the child thread is running or not.
    private boolean threadRunning = false;

    private Canvas canvas = null;

    private float textX = 0;

    private float textY = 0;

    private String text = "";

    private int screenWidth = 0;

    private int screenHeight = 0;

    private static String LOG_TAG = "SURFACE_VIEW_THREAD";

    public SurfaceViewThread(Context context) {
        super(context);

        setFocusable(true);

        // Get SurfaceHolder object.
        surfaceHolder = this.getHolder();
        // Add current object as the callback listener.
        surfaceHolder.addCallback(this);

        // Create the paint object which will draw the text.
        paint = new Paint();
        paint.setTextSize(100);
        paint.setColor(Color.GREEN);

        // Set the SurfaceView object at the top of View object.
        setZOrderOnTop(true);

        //setBackgroundColor(Color.RED);
    }

    @Override
    public void surfaceCreated(SurfaceHolder surfaceHolder) {

        // Create the child thread when SurfaceView is created.
        thread = new Thread(this);
        // Start to run the child thread.
        thread.start();
        // Set thread running flag to true.
        threadRunning = true;

        // Get screen width and height.
        screenHeight = getHeight();
        screenWidth = getWidth();

    }

    @Override
    public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i1, int i2) {

    }

    @Override
    public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
        // Set thread running flag to false when Surface is destroyed.
        // Then the thread will jump out the while loop and complete.
        threadRunning = false;
    }

    @Override
    public void run() {
        while(threadRunning)
        {
            if(TextUtils.isEmpty(text))
            {
                text = "Input text in above text box.";
            }

            long startTime = System.currentTimeMillis();

            textX += 100;

            textY += 100;

            if(textX > screenWidth)
            {
                textX = 0;
            }

            if(textY > screenHeight)
            {
                textY = 0;
            }

            drawText();

            long endTime = System.currentTimeMillis();

            long deltaTime = endTime - startTime;

            if(deltaTime < 200)
            {
                try {
                    Thread.sleep(200 - deltaTime);
                }catch (InterruptedException ex)
                {
                    Log.e(LOG_TAG, ex.getMessage());
                }

            }
        }
    }

    private void drawText()
    {
        int margin = 100;

        int left = margin;

        int top = margin;

        int right = screenWidth - margin;

        int bottom = screenHeight - margin;

        Rect rect = new Rect(left, top, right, bottom);

        // Only draw text on the specified rectangle area.
        canvas = surfaceHolder.lockCanvas(rect);

        // Draw the specify canvas background color.
        Paint backgroundPaint = new Paint();
        backgroundPaint.setColor(Color.BLUE);
        canvas.drawRect(rect, backgroundPaint);

        // Draw text in the canvas.
        canvas.drawText(text, textX, textY, paint);

        // Send message to main UI thread to update the drawing to the main view special area.
        surfaceHolder.unlockCanvasAndPost(canvas);
    }

    public String getText() {
        return text;
    }

    public void setText(String text) {
        this.text = text;
    }
}

5.3 Main Activity Layout Xml File.

app / res / layout / activity_main.xml

<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <EditText
        android:id="@+id/inputText"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="Input a text here which will be drawn when click enter."/>

    <LinearLayout
        android:id="@+id/drawTextCanvas"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical">

    </LinearLayout>

</LinearLayout>

Reference

  1. Android SurfaceView Drawing Example
(Visited 549 times, 6 visits today)

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.