Draw bitmap programmatically for SurfaceView

This exercise create Bitmap programmatically, then draw the bitmap on SurfaceView by calling canvas.drawBitmap().

Draw bitmap programmatically for SurfaceView


I show two approachs in the example:
  • prepareBitmap_A:
    - Create a array of int, fill in data point-by-point, then createBitmap from the array.
  • prepareBitmap_B:
    - Create a bitmap, then fill in pixels by calling setPixel.

I also add code to display the (approximate) processing time in various steps for reference. The videos on the bottom show the result.

MySurfaceView.java
package com.example.androidsurfaceview;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.util.AttributeSet;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

public class MySurfaceView extends SurfaceView {

private SurfaceHolder surfaceHolder;
private MyThread myThread;

MainActivity mainActivity;

long timeStart;
long timeA;
long timeB;
long timeFillBackground;
long timeDrawBitmap;
long timeTotal;

long numberOfPt;

public MySurfaceView(Context context) {
super(context);
init(context);
}

public MySurfaceView(Context context,
AttributeSet attrs) {
super(context, attrs);
init(context);
}

public MySurfaceView(Context context,
AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(context);
}

private void init(Context c){
mainActivity = (MainActivity)c;
numberOfPt = 0;
myThread = new MyThread(this);

surfaceHolder = getHolder();


surfaceHolder.addCallback(new SurfaceHolder.Callback(){

@Override
public void surfaceCreated(SurfaceHolder holder) {
myThread.setRunning(true);
myThread.start();
}

@Override
public void surfaceChanged(SurfaceHolder holder,
int format, int width, int height) {
// TODO Auto-generated method stub

}

@Override
public void surfaceDestroyed(SurfaceHolder holder) {
boolean retry = true;
myThread.setRunning(false);
while (retry) {
try {
myThread.join();
retry = false;
} catch (InterruptedException e) {
}
}
}});
}

private Bitmap prepareBitmap_A(int w, int h, long cnt){
int[] data = new int[w*h];

//fill with dummy data
for(int x=0; x<w; x++){
for(int y=0; y<h; y++){
//data[x + y*w] = 0xFF000000 + x;

if(cnt>=0){
data[x + y*w] = 0xFFff0000;
cnt--;
}else{
data[x + y*w] = 0xFFa0a0a0;
}

}
}
timeA = System.currentTimeMillis();
Bitmap bm = Bitmap.createBitmap(data, w, h, Bitmap.Config.ARGB_8888);
timeB = System.currentTimeMillis();
return bm;
}

private Bitmap prepareBitmap_B(int w, int h, long cnt){

Bitmap bm = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
timeA = System.currentTimeMillis();

//fill with dummy data
for(int x=0; x<w; x++){
for(int y=0; y<h; y++){
//data[x + y*w] = 0xFF000000 + x;

if(cnt>=0){
bm.setPixel(x, y, 0xFFff0000);
cnt--;
}else{
bm.setPixel(x, y, 0xFFa0a0a0);
}

}
}
timeB = System.currentTimeMillis();
return bm;
}

protected void drawSomething(Canvas canvas) {

numberOfPt += 500;
if(numberOfPt > (long)((getWidth()*getHeight()))){
numberOfPt = 0;
}

timeStart = System.currentTimeMillis();
Bitmap bmDummy = prepareBitmap_A(getWidth(), getHeight(), numberOfPt);

canvas.drawColor(Color.BLACK);
timeFillBackground = System.currentTimeMillis();
canvas.drawBitmap(bmDummy,
0, 0, null);
timeDrawBitmap = System.currentTimeMillis();

mainActivity.runOnUiThread(new Runnable() {

@Override
public void run() {
mainActivity.showDur(
timeA - timeStart,
timeB - timeA,
timeFillBackground - timeB,
timeDrawBitmap - timeFillBackground,
timeDrawBitmap - timeStart);
}
});
}

}

Modify activity_main.xml to add TextView to display processing time.
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="com.example.androidsurfaceview.MainActivity" >

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:autoLink="web"
android:text="http://arteluzevida.blogspot.com/"
android:textStyle="bold" />

<TextView
android:id="@+id/durA"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Duration: " />
<TextView
android:id="@+id/durB"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Duration: " />
<TextView
android:id="@+id/durFillBack"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Duration: " />
<TextView
android:id="@+id/durDrawBM"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Duration: " />
<TextView
android:id="@+id/durTotal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Duration: " />

<com.example.androidsurfaceview.MySurfaceView
android:layout_width="match_parent"
android:layout_height="match_parent" />

</LinearLayout>

MainActivity.java
package com.example.androidsurfaceview;

import android.app.Activity;
import android.os.Bundle;
import android.widget.TextView;

public class MainActivity extends Activity {

TextView textDurA, textDurB, textDurFillBack,
textDurDrawBM, textDurTotal;

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

textDurA = (TextView)findViewById(R.id.durA);
textDurB = (TextView)findViewById(R.id.durB);
textDurFillBack = (TextView)findViewById(R.id.durFillBack);
textDurDrawBM = (TextView)findViewById(R.id.durDrawBM);
textDurTotal = (TextView)findViewById(R.id.durTotal);

}

protected void showDur(long dA, long dB, long dFill, long dDraw, long dTotal){
textDurA.setText("Duration(ms) - A: " + dA);
textDurB.setText("Duration(ms) - B: " + dB);
textDurFillBack.setText("Duration(ms) - Fill Background: " + dFill);
textDurDrawBM.setText("Duration(ms) - drawBitmap: " + dDraw);
textDurTotal.setText("Duration(ms) - Total: " + dTotal);
}

}

MyThread.java refer to last exercise, "Create animation on SurfaceView in background Thread".


download filesDownload the files.

prepareBitmap_A:

prepareBitmap_B: