Android UI How to - Draw texture with thread








The following code shows how to Draw texture with thread.

Code revised from
Android Recipes:A Problem-Solution Approach
http://www.apress.com/9781430234135
ISBN13: 978-1-4302-3413-5

Example

Main layout xml file

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <Button
        android:id="@+id/button_transform"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Rotate" />
    <TextureView 
        android:id="@+id/surface"
        android:layout_width="300dp"
        android:layout_height="300dp"
        android:layout_gravity="center" />

</FrameLayout>

Main Activity Java code

package com.java2s.myapplication3.app;
// w w  w .  jav a  2 s  .c  o m
import java.util.ArrayList;

import android.annotation.SuppressLint;
import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.SurfaceTexture;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Message;
import android.view.MotionEvent;
import android.view.Surface;
import android.view.TextureView;
import android.view.View;

public class MainActivity extends Activity implements View.OnClickListener, View.OnTouchListener, TextureView.SurfaceTextureListener {

    private TextureView mSurface;
    private DrawingThread mThread;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        findViewById(R.id.button_transform).setOnClickListener(this);
        mSurface = (TextureView) findViewById(R.id.surface);
        mSurface.setOnTouchListener(this);
        mSurface.setSurfaceTextureListener(this);
    }

    @Override
    public void onClick(View v) {
        mSurface.animate()
                .rotationBy(180.0f)
                .setDuration(750);
    }

    public boolean onTouch(View v, MotionEvent event) {
        if (event.getAction() == MotionEvent.ACTION_DOWN) {
            mThread.addItem((int) event.getX(), (int) event.getY());
        }
        return true;
    }

    @Override
    public void onSurfaceTextureAvailable(SurfaceTexture surface, int width,
                                          int height) {
        mThread = new DrawingThread(new Surface(surface),
                BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher));
        mThread.updateSize(width, height);
        mThread.start();
    }

    @Override
    public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width,
                                            int height) {
        mThread.updateSize(width, height);
    }

    @Override
    public void onSurfaceTextureUpdated(SurfaceTexture surface) {

    }

    @Override
    public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
        mThread.quit();
        mThread = null;
        return true;
    }

    private static class DrawingThread extends HandlerThread implements Handler.Callback {
        private static final int MSG_ADD = 100;
        private static final int MSG_MOVE = 101;
        private static final int MSG_CLEAR = 102;

        private int mDrawingWidth, mDrawingHeight;

        private Surface mDrawingSurface;
        private Rect mSurfaceRect;
        private Paint mPaint;

        private Handler mReceiver;
        private Bitmap mIcon;
        private ArrayList<DrawingItem> mLocations;

        private class DrawingItem {
            int x, y;
            boolean horizontal, vertical;

            public DrawingItem(int x, int y, boolean horizontal, boolean vertical) {
                this.x = x;
                this.y = y;
                this.horizontal = horizontal;
                this.vertical = vertical;
            }
        }

        public DrawingThread(Surface surface, Bitmap icon) {
            super("DrawingThread");
            mDrawingSurface = surface;
            mSurfaceRect = new Rect();
            mLocations = new ArrayList<DrawingItem>();
            mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
            mIcon = icon;
        }

        @Override
        protected void onLooperPrepared() {
            mReceiver = new Handler(getLooper(), this);
            mReceiver.sendEmptyMessage(MSG_MOVE);
        }

        @Override
        public boolean quit() {
            mReceiver.removeCallbacksAndMessages(null);
            return super.quit();
        }

        @Override
        public boolean handleMessage(Message msg) {
            switch (msg.what) {
                case MSG_ADD:
                    DrawingItem newItem = new DrawingItem(msg.arg1, msg.arg2,
                            Math.round(Math.random()) == 0,
                            Math.round(Math.random()) == 0);
                    mLocations.add(newItem);
                    break;
                case MSG_CLEAR:
                    mLocations.clear();
                    break;
                case MSG_MOVE:
                    try {
                        Canvas c = mDrawingSurface.lockCanvas(mSurfaceRect);
                        if (c == null) {
                            break;
                        }
                        c.drawColor(Color.BLACK);
                        for (DrawingItem item : mLocations) {
                            item.x += (item.horizontal ? 1 : -1);
                            c.drawBitmap(mIcon, item.x, item.y, mPaint);
                        }
                        mDrawingSurface.unlockCanvasAndPost(c);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                    break;
            }
            mReceiver.sendEmptyMessage(MSG_MOVE);
            return true;
        }

        public void updateSize(int width, int height) {
            mDrawingWidth = width;
            mDrawingHeight = height;
            mSurfaceRect.set(0, 0, mDrawingWidth, mDrawingHeight);
        }

        public void addItem(int x, int y) {
            Message msg = Message.obtain(mReceiver, MSG_ADD, x, y);
            mReceiver.sendMessage(msg);
        }
        public void clearItems() {
            mReceiver.sendEmptyMessage(MSG_CLEAR);
        }
    }
}
null