For simpleness of the question, I'm drawing an integer on a SurfaceView which increases by 1 every draw.
The increasing actually happens, as I can see on the System.out.
The text on the screen stays on '0'.
Who can tell me what I'm doing wrong?
SurfaceViewTest.java
package com.niek.surfaceviewtest;
import android.app.Activity;
import android.os.Bundle;
public class SurfaceViewTest extends Activity {
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
}
StatusView.java
package com.niek.surfaceviewtest;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
public class StatusView extends SurfaceView implements SurfaceHolder.Callback {
private int tmp;
private DrawThread drawThread;
public StatusView(Context context, AttributeSet attrs) {
super(context, attrs);
getHolder().addCallback(this);
setFocusable(true);
drawThread = new DrawThread(getHolder());
}
#Override
public void onDraw(Canvas c) {
c.drawColor(Color.BLACK);
Paint p = new Paint();
p.setColor(Color.RED);
c.drawText(tmp + "", 10, 10, p);
tmp++;
System.out.println(tmp);
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
// TODO Auto-generated method stub
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
drawThread.setRunning(true);
drawThread.start();
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
// we have to tell thread to shut down & wait for it to finish, or else
// it might touch the Surface after we return and explode
boolean retry = true;
drawThread.setRunning(false);
while (retry) {
try {
drawThread.join();
retry = false;
} catch (InterruptedException e) {
// we will try it again and again...
}
}
}
protected class DrawThread extends Thread {
private SurfaceHolder surfaceHolder;
private boolean isRunning;
public DrawThread(SurfaceHolder surfaceHolder) {
this.surfaceHolder = surfaceHolder;
isRunning = false;
}
public void setRunning(boolean run) {
isRunning = run;
}
public void run() {
Canvas c;
while (isRunning) {
c = null;
try {
c = surfaceHolder.lockCanvas(null);
synchronized (surfaceHolder) {
onDraw(c);
}
} finally {
// do this in a finally so that if an exception is thrown
// during the above, we don't leave the Surface in an
// inconsistent state
if (c != null) {
surfaceHolder.unlockCanvasAndPost(c);
}
}
}
}
}
}
main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#FFFFFF">
<com.niek.surfaceviewtest.StatusView
android:id="#+id/statusview1"
android:layout_width="fill_parent"
android:layout_height="30dip"
android:background="#000000"
/>
</LinearLayout>
My only guess is that painting isn't being done on the surface because the view isn't invalidated. You're supposed to call invalidate() in order to draw, and then let the framework call onDraw(). Maybe that's why tmp is being incremented, but the paint operation only reaches the surface the first time.
It might be worth experimenting: maybe make Canvas c a member of StatusView, and then replace
synchronized (surfaceHolder) {
onDraw(c);
}
with
synchronized (surfaceHolder) {
invalidate();
}
Does that work?
The current solution is not right. You are using the SurfaceView in order to update the content from a separate thread and not using the invalidate() method that will run onDraw() method when the system refreshes the content. The problem is that you have set a background for your StatusView, try deleting that line
android:background="#000000"
apparently, you need to control the whole information displayed in that view.
Looks like you are showing your main.xml with setContentView(R.layout.main); instead of creating the surface and displaying that. unless i am missing code somewhere I don't see that as being the case.
Related
I am new to Android so I am making a coloring book app just to get myself acquainted to android programming. I have looked up my problem extensively and implemented the solutions but still no progress.
I have an activity 'ColoringActivity' which calls a class 'PaintView' which extends surfaceview. I am trying to update the canvas in a separate thread. I also have a button in the layout which takes the user to another activity for picking colors. The problem is that when the user returns after choosing the color, the canvas becomes empty and I cant draw on the canvas anymore. I think i somehow loose the thread in between activities and although the thread is running in the background, I have no access to it.
I read on this forum that I must implement pause() and resume() methods in the thread class and basically kill the thread when I go to another activity and restart it when I return. Also I read I have to override onPause() and onResume() method in activity class and construct the surfaceview in onResume() so that it is constructed every time user returns to this activity.
I am sorry if it doesnt make much sense because I am lost as well.
My 'ColoringActivity':
package com.ali.coloryourself;
import android.app.Activity;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Toast;
public class ColoringActivity extends Activity {
private static final int COLOR_REQUEST_CODE = 100;
public static String file;
public static Bitmap bitmap;
BitmapFactory.Options options;
PaintView paintView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_draw);
Intent intent = getIntent();
file = intent.getStringExtra("fileName");
// paintView = (PaintView) findViewById(R.id.drawingSurface);
}
#Override
protected void onResume() {
paintView = (PaintView) findViewById(R.id.drawingSurface);
paintView.getThread().resume();
super.onResume();
}
#Override
protected void onPause() {
paintView.getThread().pause();
super.onPause();
}
public void pickColor(View v) {
paintView.getThread().pause();
Intent colorIntent = new Intent(this, ColorPickerActivity.class);
startActivityForResult(colorIntent, COLOR_REQUEST_CODE);
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode != RESULT_CANCELED) {
if (requestCode == COLOR_REQUEST_CODE) {
int color = data.getIntExtra("Color", -1);
// paintView.getPaint().setColor(color);
}
}
}
}
My 'PaintView' class:
package com.ali.coloryourself;
import android.R.color;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
class PaintView extends SurfaceView implements SurfaceHolder.Callback {
private Paint paint = new Paint();
private Canvas canvas;
private PaintThread thread;
private Path path = new Path();
private Bitmap bitmap;
public PaintView(Context context, AttributeSet attrs) {
super(context, attrs);
SurfaceHolder holder = getHolder();
holder.addCallback(this);
paint.setColor(Color.WHITE);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeJoin(Paint.Join.ROUND);
paint.setStrokeCap(Paint.Cap.ROUND);
paint.setStrokeWidth(3);
setThread(new PaintThread(holder));
}
class PaintThread extends Thread {
private boolean mRun;
private SurfaceHolder mSurfaceHolder;
private int mMode;
public static final int STATE_PAUSE = 2;
public static final int STATE_RUNNING = 4;
public PaintThread(SurfaceHolder surfaceHolder) {
mSurfaceHolder = surfaceHolder;
}
#Override
public void run() {
while (mRun) {
try {
canvas = mSurfaceHolder.lockCanvas(null);
if (mMode == STATE_RUNNING) {
if (bitmap == null) {
bitmap = Bitmap.createBitmap(1, 1,
Bitmap.Config.ARGB_8888);
}
}
doDraw(canvas);
canvas.drawBitmap(bitmap, 0, 0, null);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (canvas != null) {
mSurfaceHolder.unlockCanvasAndPost(canvas);
}
}
}
}
private void doDraw(Canvas canvas) {
canvas.drawPath(path, paint);
}
public void setRunning(boolean b) {
mRun = b;
}
public void pause() {
if (mMode == STATE_RUNNING)
setState(STATE_PAUSE);
}
public void resume() {
setState(STATE_RUNNING);
}
public void setState(int mode) {
synchronized (mSurfaceHolder) {
mMode = mode;
}
}
}
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
// Log.d("Touch", "I am touching");
float eventX = event.getX();
float eventY = event.getY();
int action = event.getAction();
switch (action) {
case MotionEvent.ACTION_DOWN:
path.moveTo(eventX, eventY);
return true;
case MotionEvent.ACTION_MOVE:
path.lineTo(eventX, eventY);
break;
case MotionEvent.ACTION_UP:
// nothing to do
break;
default:
return false;
}
return true;
}
public void surfaceCreated(SurfaceHolder holder) {
if (getThread().getState() == Thread.State.NEW) {
getThread().setRunning(true);
getThread().start();
}
}
public void surfaceDestroyed(SurfaceHolder holder) {
boolean retry = true;
getThread().setRunning(false);
getThread().resume();
while (retry) {
try {
getThread().join();
retry = false;
} catch (InterruptedException e) {
}
}
}
public Paint getPaint() {
return paint;
}
public void setPaint(int color) {
this.paint.setColor(color);
}
public PaintThread getThread() {
return thread;
}
public void setThread(PaintThread thread) {
this.thread = thread;
}
}
my 'activity_draw.xml'
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<Button
android:id="#+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:layout_marginTop="10dp"
android:onClick="pickColor"
android:text="Pick Color" />
<com.ali.coloryourself.PaintView
android:id="#+id/drawingSurface"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="#+id/button1"
android:layout_marginTop="10dp"/>
</RelativeLayout>
I know I am missing some very basic thread concept. I need to allow the user to pick color and return and be able to continue drawing. I will be extremely grateful for your help.
I think I have found an answer although I am not sure if it is a good programming practice. I found out that my surface view and thread were created once 'ColoringActivity' was created and destroyed every time 'ColoringActivity' went to background. But once 'ColoringActivity' was restarted and resumed, surface view and thread were not recreated. So i moved the following line
setContentView(R.layout.activity_draw);
to onResume() method and now I can draw on the canvas every time. Now I just need to save the canvas and re load it when the activity comes back on to start off the coloring where the user left it.
I am trying to learn game development in android. First I am trying to appear and disappear an object on screen using game loop for every five second. But I did not get succeed. I have read different tutorials and forums. I applied all things as in tutorials but still object is drawing continuously. It is not disappearing. I a not getting what I am missing? Please guide me.
The complete code is here:
MainGameActivity.java
package com.example.showandhideobject;
import android.app.Activity;
import android.os.Bundle;
import android.view.Window;
import android.view.WindowManager;
public class MainGameActivity extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
setContentView(new MainGamePanel(this));
}
}
MainGamePanel .java
package com.example.showandhideobject;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
public class MainGamePanel extends SurfaceView implements
SurfaceHolder.Callback {
private MainGameThread thread;
private ImageObject image;
// private long gameStartTime;
public MainGamePanel(Context context) {
super(context);
// adding the callback (this) to the surface holder to intercept events
getHolder().addCallback(this);
// create the game loop thread
thread = new MainGameThread(getHolder(), this);
Bitmap imageBitMap = BitmapFactory.decodeResource(getResources(),
R.drawable.rose);
image = new ImageObject(imageBitMap, 100, 150);
image.setAppeared(false);
image.setDisappearTime(System.currentTimeMillis());
// make the GamePanel focusable so it can handle events
setFocusable(true);
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
// at this point the surface is created and
// we can safely start the game loop
thread.setRunning(true);
thread.start();
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
}
public void update() {
Log.i("Image Status::::::::::::: ",
Boolean.valueOf(image.isAppeared()).toString());
if (!image.isAppeared()
&& System.currentTimeMillis() - image.getDisappearTime() >= 5000) {
Log.i("Image Object::::::: ", "Showing");
image.setAppeared(true);
image.setAppearTime(System.currentTimeMillis());
}
if (image.isAppeared()
&& (System.currentTimeMillis() - image.getAppearTime() >= 5000)) {
Log.i("Image Object::::::: ", "Not Showing");
image.setAppeared(false);
image.setDisappearTime(System.currentTimeMillis());
}
}
public void render(Canvas canvas) {
if (image.isAppeared()) {
image.draw(canvas);
}
}
}
MainGameThread.java
package com.example.showandhideobject;
import android.graphics.Canvas;
import android.util.Log;
import android.view.SurfaceHolder;
public class MainGameThread extends Thread {
// Surface holder that can access the physical surface
private SurfaceHolder surfaceHolder;
// The actual view that handles inputs
// and draws to the surface
private MainGamePanel gamePanel;
// flag to hold game state
private boolean running;
public boolean isRunning() {
return running;
}
public void setRunning(boolean running) {
this.running = running;
}
public MainGameThread(SurfaceHolder surfaceHolder, MainGamePanel gamePanel) {
super();
this.surfaceHolder = surfaceHolder;
this.gamePanel = gamePanel;
}
#Override
public void run() {
Canvas canvas;
while (isRunning()) {
canvas = null;
// try locking the canvas for exclusive pixel editing
// in the surface
try {
canvas = this.surfaceHolder.lockCanvas();
synchronized (surfaceHolder) {
Log.i("With in :::::::::", "Game Loop");
// update game state
gamePanel.update();
// render state to the screen and draw the canvas on the
// panel
gamePanel.render(canvas);
// gamePanel.onDraw(canvas);
}
} finally {
// in case of an exception the surface is not left in an
// inconsistent state
if (canvas != null) {
surfaceHolder.unlockCanvasAndPost(canvas);
}
} // end finally
}
}
}
ImageObject.java
package com.example.showandhideobject;
import android.graphics.Bitmap;
import android.graphics.Canvas;
public class ImageObject {
private Bitmap bitmap; // the actual bitmap
private int x; // the X coordinate
private int y; // the Y coordinate
private boolean isAppeared;
private long appearTime;
private long disappearTime;
// Constructor for this class
public ImageObject(Bitmap bitmap, int x, int y) {
this.bitmap = bitmap;
this.x = x;
this.y = y;
}
public Bitmap getBitmap() {
return bitmap;
}
public void setBitmap(Bitmap bitmap) {
this.bitmap = bitmap;
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
public boolean isAppeared() {
return isAppeared;
}
public void setAppeared(boolean isAppeared) {
this.isAppeared = isAppeared;
}
public long getAppearTime() {
return appearTime;
}
public void setAppearTime(long appearTime) {
this.appearTime = appearTime;
}
public long getDisappearTime() {
return disappearTime;
}
public void setDisappearTime(long disappearTime) {
this.disappearTime = disappearTime;
}
/* Method to draw images on Canvas */
public void draw(Canvas canvas) {
canvas.drawBitmap(bitmap, x - (bitmap.getWidth() / 2),
y - (bitmap.getHeight() / 2), null);
}
}
in this part
if (image.isAppeared()) {
image.draw(canvas);
}
you never clear your canvas. What you are doing is actually drawing your image over and over on the same spot.
You probably need to redraw a background in cas isAppeared() is false
Edit
you can also use canvas.save() before drawing the image, and canvas.restore() when you don't want the image anymore.
Don't try to optimise too early, game rendering is usually inefficient as almost always most of the screen is expected to change.
Loop should be:
always draw the background to canvas
always draw all game objects to the canvas, let them decide if they are visible or not which will simplify the MainGamePanel class
finally always display canvas (by copying to the image as you are doing)
To expand on point 2:
/* Method to draw images on Canvas */
public void draw(Canvas canvas) {
if(!isAppeared) return; //let the object decide when it should be drawn
canvas.drawBitmap(bitmap, x - (bitmap.getWidth() / 2),
y - (bitmap.getHeight() / 2), null);
}
Change the method render in MainGamePanel.java to
if (image.isAppeared() && canvas != null) {
image.draw(canvas);
}
I write a simple game with the following structure. Main xml layout have user View:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/menuRL"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<com.sokolovlev.UFOtest03.MenuView
android:id="#+id/menuView"
android:layout_width="fill_parent"
android:layout_height="fill_parent" />
</RelativeLayout>
This View have two files. First is user MenuView:
package com.sokolovlev.UFOtest03;
import android.content.Context;
import android.util.AttributeSet;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
public class MenuView extends SurfaceView implements SurfaceHolder.Callback
{
private SurfaceHolder mSurfaceHolder; //Draw surface
public static MenuManager mMenuManager; //Draw manager
public MenuView(Context context, AttributeSet attrs)
{
super(context, attrs);
// Surface events registration
mSurfaceHolder = getHolder();
mSurfaceHolder.addCallback(this);
mMenuManager = new MenuManager(mSurfaceHolder, context);
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height)
{
mMenuManager.initPositions(height, width);
}
#SuppressWarnings("static-access")
#Override
public void surfaceCreated(SurfaceHolder holder)
{
mMenuManager.setRunning(true);
try
{
mMenuManager.start();
}
catch (Exception e) { }
}
#SuppressWarnings("static-access")
#Override
public void surfaceDestroyed(SurfaceHolder holder)
{
boolean retry = true;
mMenuManager.setRunning(false);
while (retry)
{
try
{
mMenuManager.join();
retry = false;
}
catch (InterruptedException e) { }
}
}
}
And second file is this draw manager:
package com.sokolovlev.UFOtest03;
import ...
public class MenuManager extends Thread
{
private SurfaceHolder mSurfaceHolder;
private static boolean mRunning;
private int _screenHeight;
private int _screenWidth;
private ...
Context c;
private ...
public MenuManager(SurfaceHolder surfaceHolder, Context context)
{
mSurfaceHolder = surfaceHolder;
mRunning = false;
c = context;
...
}
public static void setRunning(boolean running)
{
mRunning = running;
}
#Override
public void run()
{
while (mRunning)
{
Canvas canvas = null;
try
{
// подготовка Canvas-а
canvas = mSurfaceHolder.lockCanvas();
canvas.drawRGB(0, 0, 0);
synchronized (mSurfaceHolder)
{
//All drawing
}
}
catch (Exception e) { }
finally
{
if (canvas != null)
{
mSurfaceHolder.unlockCanvasAndPost(canvas);
}
}
}
}
}
Everything works fine! (step №1) But if I press central button, or I have incoming call, or I call task manager (step №2) and go back to my app - I haven't my drawing, only black screen (step №3). But if I go next to step №2 and then in my app, I see that everything works.
I don't understand, where there is a reloading which influences such on my drawings! Help please!
To solve this problem, I need to save the settings and restart my surface. Then load the settings. (See LunarLander Example)
It's a bit cheeky - but I was wondering if anyone could tell me what's wrong below.
This is messing around trying to understand android - not "real" code.
It's a surfaceView which is laid out in the main activity layout.
It works - until the phone's "off" button is tapped (sleep) and woken up again. Upon waking up, it goes crazy and android produces a "Force Close" diaglog.
I've been trying to follow the path with LogCat, but for some reason, some messages get dropped - OR - the path I think is being followed, isn't.
eg - on putting the phone to sleep, I will get surfaceDestroyed called (seems reasonable) but on waking, I do not get a surfaceCreated().
The basic logic is: the surfaceView creates a thread which paints the system time in seconds as text. That's it.
I've got a real app I'd like to write - but until I really understand the basics, that won't happen. I've been through a fair number of tutorials too.
Any pointers most gratefully recieved :)
Cheers
Tim
package net.dionic.android.bouncingsquid;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.os.SystemClock;
import android.util.AttributeSet;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import java.lang.System;
public class WidgetSeconds extends SurfaceView implements SurfaceHolder.Callback {
private class CanvasThread extends Thread {
private SurfaceHolder _surfaceHolder;
private WidgetSeconds _surfaceView;
private boolean _run = false;
public CanvasThread(SurfaceHolder surfaceHolder, WidgetSeconds surfaceView) {
Log.i("WidgetSecs.CanvasThread", "constructor");
_surfaceHolder = surfaceHolder;
_surfaceView = surfaceView;
}
public void setRunning(boolean run) {
_run = run;
}
#Override
public void run() {
Canvas c;
while (_run) {
c = null;
try {
c = _surfaceHolder.lockCanvas(null);
synchronized (_surfaceHolder) {
_surfaceView.onDraw(c);
try {
Thread.sleep(200);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
} finally {
// do this in a finally so that if an exception is thrown
// during the above, we don't leave the Surface in an
// inconsistent state
if (c != null) {
_surfaceHolder.unlockCanvasAndPost(c);
}
}
}
}
}
private CanvasThread canvasthread;
public void Initalise() {
Log.i("WidgetSecs", "Initialise");
}
public WidgetSeconds(Context context, AttributeSet attrs) {
super(context, attrs);
Log.i("WidgetSecs", "constructor");
this.Initalise();
getHolder().addCallback(this);
setFocusable(true);
}
#Override
public void onDraw(Canvas canvas) {
Paint textPaint;
canvas.drawColor(Color.GRAY);
textPaint = new Paint();
textPaint.setTextSize(32);
canvas.drawText(System.currentTimeMillis()/1000 + " S", 10, 50, textPaint);
canvas.restore();
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
Log.i("WidgetSecs", "surfaceChanged");
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
Log.i("WidgetSecs", "surfaceCreated");
Log.i("WidgetSecs.CanvasThread", "Thread create");
canvasthread = new CanvasThread(getHolder(), this);
canvasthread.setRunning(true);
canvasthread.start();
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
Log.i("WidgetSecs", "surfaceDestroyed");
boolean retry = true;
while (retry) {
try {
Log.i("WidgetSecs", "Thread destroyed");
canvasthread.join();
canvasthread = null;
retry = false;
} catch (InterruptedException e) {
Log.i("WidgetSecs", "Thread join failed");
// we will try it again and again...
}
}
}
}
I'm am doing a simple coding attempt trying to draw on a SurfaceView created on my main.xml layout. I can change background color and display an icon fine, but when I try to draw I get an error. I am a newbie so obvious I am missing something, please lend a helping hint, thanks!
main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/root" android:orientation="vertical"
android:layout_width="fill_parent" android:layout_height="fill_parent">
<SurfaceView android:id="#+id/Paper"
android:layout_height="fill_parent"
android:layout_width="fill_parent">
</SurfaceView>
</LinearLayout>
and code here;
package com.example.SurfaceViewTest;
import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.os.Bundle;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
public class SurfaceViewTest extends Activity implements SurfaceHolder.Callback {
private SurfaceView mSurfaceView;
private SurfaceHolder mSurfaceHolder;
private Paint paint;
Bitmap mDrawing;
boolean mRun;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mSurfaceView = (SurfaceView) this.findViewById(R.id.Paper);
mSurfaceHolder = mSurfaceView.getHolder();
mSurfaceHolder.addCallback(this);
mSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_NORMAL);
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
// TODO Auto-generated method stub
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
mSurfaceView.setBackgroundColor(Color.rgb(0, 255, 0));
mRun=true;
thread.start();
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
// TODO Auto-generated method stub
}
Thread thread = new Thread(){
public void doDraw(Canvas c){
mDrawing = Bitmap.createBitmap(200, 300, Bitmap.Config.RGB_565);
c.setBitmap(mDrawing);
paint = new Paint();
paint.setColor(Color.rgb(255, 255,255));
c.drawLine(1,1,200,300, paint);
}
public void run() {
while (mRun) {
Canvas c = null;
try {
c = mSurfaceHolder.lockCanvas(null);
synchronized (mSurfaceHolder) {
doDraw(c);
}
} finally {
// do this in a finally so that if an exception is thrown
// during the above, we don't leave the Surface in an
// inconsistent state
if (c != null) {
mSurfaceHolder.unlockCanvasAndPost(c);
}
}
}
}
};
}
UPDATE:
Ok I got it to works thanks!
package com.example.SurfaceViewTest;
import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.os.Bundle;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
public class SurfaceViewTest extends Activity implements SurfaceHolder.Callback {
private SurfaceView mSurfaceView;
private SurfaceHolder mSurfaceHolder;
Bitmap mDrawing;
Canvas tempCanvas = new Canvas();
Paint paint;
boolean mRun;
int intCanvasWidth, intCanvasHeight;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mSurfaceView = (SurfaceView) this.findViewById(R.id.Paper);
mSurfaceHolder = mSurfaceView.getHolder();
mSurfaceHolder.addCallback(this);
mSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_NORMAL);
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
intCanvasWidth = width;
intCanvasHeight = height;
mDrawing = Bitmap.createBitmap(intCanvasWidth, intCanvasHeight,
Bitmap.Config.RGB_565);
paint = new Paint();
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
if (thread.getState() == Thread.State.TERMINATED) {
thread = new Thread();
}
mRun = true;
thread.start();
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
boolean retry = true;
mRun = false;
while (retry) {
try {
thread.join();
retry = false;
} catch (InterruptedException e) {
// we will try it again and again...
}
}
}
Thread thread = new Thread() {
public void doDraw(Canvas c) {
tempCanvas.setBitmap(mDrawing);
paint.setColor(Color.rgb(255, 255,255));
tempCanvas.drawLine(1,1,200,300, paint);
c.drawBitmap(mDrawing, 0, 0, null);
}
#Override
public void run() {
Canvas c;
while (mRun) {
c = null;
try {
c = mSurfaceHolder.lockCanvas(null);
synchronized (mSurfaceHolder) {
doDraw(c);
}
} finally {
// do this in a finally so that if an exception is thrown
// during the above, we don't leave the Surface in an
// inconsistent state
if (c != null) {
mSurfaceHolder.unlockCanvasAndPost(c);
}
}
}
}
};
}
Here's how my SurfaceView works. I think your problem is doing your Bitmap in surfaceCreated().
#Override
public void surfaceCreated(SurfaceHolder holder) {
thread.start();
}
Thread thread = new Thread(){
...
public void doDraw(Canvas c){
//draw onto the canvas here
}
public void run() {
while (mRun) {
Canvas c = null;
try {
c = mSurfaceHolder.lockCanvas(null);
synchronized (mSurfaceHolder) {
doDraw(c);
}
} finally {
// do this in a finally so that if an exception is thrown
// during the above, we don't leave the Surface in an
// inconsistent state
if (c != null) {
mSurfaceHolder.unlockCanvasAndPost(c);
}
}
}
}
};