I am trying to make a Simple Live wallpaper in which when user touch his screen a bitmap is drawn on that position. I am facing 2 problem, if i am drawing it in Runnable then it is continuously creating bitmaps and if i am drawing it outside then it continuously blinks. I have noticed that if i change my delay time for runnable blinking also changes and if i remove runnable completely then it is drawing fine but positions are getting weird.
Here is my code.
This one blinks continuously.
package com.example.live_wallpaper_p1;
import android.app.WallpaperManager;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.os.Bundle;
import android.os.Handler;
import android.service.wallpaper.WallpaperService;
import android.view.SurfaceHolder;
public class DemoWallpaperService extends WallpaperService {
#Override
public Engine onCreateEngine() {
return new DemoWallpaperEngine();
}
private class DemoWallpaperEngine extends Engine{
private boolean mVisible = false;
private final Handler mHandler = new Handler();
private Bitmap imm;
private float xcor;
private float ycor;
BitmapFactory.Options option;
DemoWallpaperEngine()
{
imm = Bitmap.createBitmap(BitmapFactory.decodeResource(getResources(), R.drawable.icon, option));
}
private final Runnable mUpdateDisplay = new Runnable() {
#Override
public void run() {
draw();
}};
#Override
public Bundle onCommand(String action, int x, int y, int z, Bundle extras, boolean resultRequested) {
if (action.equals(WallpaperManager.COMMAND_TAP)) {
xcor=x;
ycor=y;
final SurfaceHolder holder = getSurfaceHolder();
Canvas c = null;
try {
c = holder.lockCanvas();
if (c != null) {
c.drawBitmap(imm, xcor-(imm.getWidth()/2), ycor-(imm.getHeight()/2),null);
//drawCube(c);
}
} finally {
if (c != null)
holder.unlockCanvasAndPost(c);
}
}
return null;
}
private void draw() {
SurfaceHolder holder = getSurfaceHolder();
Canvas c = null;
try {
c = holder.lockCanvas();
if (c != null) {
//do something
}
} finally {
if (c != null)
holder.unlockCanvasAndPost(c);
}
mHandler.removeCallbacks(mUpdateDisplay);
if (mVisible) {
mHandler.postDelayed(mUpdateDisplay, 10);
}
}
#Override
public void onVisibilityChanged(boolean visible) {
mVisible = visible;
if (visible) {
draw();
} else {
mHandler.removeCallbacks(mUpdateDisplay);
}
}
#Override
public void onSurfaceChanged(SurfaceHolder holder, int format, int width, int height) {
draw();
}
#Override
public void onSurfaceDestroyed(SurfaceHolder holder) {
super.onSurfaceDestroyed(holder);
mVisible = false;
mHandler.removeCallbacks(mUpdateDisplay);
}
#Override
public void onDestroy() {
super.onDestroy();
mVisible = false;
mHandler.removeCallbacks(mUpdateDisplay);
}
}
}
You can try this sample code
here imageURL is http link to Image Location
Bitmap bitmap = BitmapFactory.decodeStream((InputStream)new URL(imageUrl).getContent());
holder.itemImage.setImageBitmap(bitmap);
If your Image is in Phone Memory.
use this
image.setImageResource(R.drawable.test2);
Related
In order to display a view with moving objects (from bitmaps) and touch events, I've been using the following code for a SurfaceView in Android. It has alwas worked fine on my development devices, but it turned out that lots of users just see a black box in place of that View. After quite a long time of (unsuccessful) debugging, I've come to the conclusion that it must be Android 4.1 which causes the SurfaceView to stop working correctly.
My development devices are Android 4.0 but users complaining about the black-only SurfaceView have Android 4.1. Checked that with a Android 4.1 emulator - and it's not working there, either.
Can you see what is wrong with the code? Is it caused by the "Project Butter" things in Android 4.1, perhaps?
Of course, I've checked that the Bitmap objects are valid (saved them to SD card in appropriate lines) and all methods for drawing are periodically called as well - everything's normal there.
package com.my.package.util;
import java.util.ArrayList;
import java.util.List;
import com.my.package.Card;
import com.my.package.MyApp;
import android.content.Context;
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.util.AttributeSet;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
public class MySurface extends SurfaceView implements SurfaceHolder.Callback {
private MyRenderThread mRenderThread;
private volatile List<Card> mGameObjects;
private volatile int mGameObjectsCount;
private int mScreenWidth;
private int mScreenHeight;
private int mGameObjectWidth;
private int mGameObjectHeight;
private int mHighlightedObject = -1;
private Paint mGraphicsPaint;
private Paint mShadowPaint;
private Rect mDrawingRect;
private int mTouchEventAction;
private Bitmap bitmapToDraw;
private int mOnDrawX1;
private BitmapFactory.Options bitmapOptions;
// ...
public MySurface(Context activityContext, AttributeSet attributeSet) {
super(activityContext, attributeSet);
getHolder().addCallback(this);
setFocusable(true); // touch events should be processed by this class
mGameObjects = new ArrayList<Card>();
mGraphicsPaint = new Paint();
mGraphicsPaint.setAntiAlias(true);
mGraphicsPaint.setFilterBitmap(true);
mShadowPaint = new Paint();
mShadowPaint.setARGB(160, 20, 20, 20);
mShadowPaint.setAntiAlias(true);
bitmapOptions = new BitmapFactory.Options();
bitmapOptions.inInputShareable = true;
bitmapOptions.inPurgeable = true;
mDrawingRect = new Rect();
}
public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) { }
public void surfaceCreated(SurfaceHolder arg0) {
mScreenWidth = getWidth();
mScreenHeight = getHeight();
mGameObjectHeight = mScreenHeight;
mGameObjectWidth = mGameObjectHeight*99/150;
mCurrentSpacing = mGameObjectWidth;
setDrawingCacheEnabled(true);
mRenderThread = new MyRenderThread(getHolder(), this);
mRenderThread.setRunning(true);
mRenderThread.start();
}
public void surfaceDestroyed(SurfaceHolder holder) {
boolean retry = true;
mRenderThread.setRunning(false); // stop thread
while (retry) { // wait for thread to close
try {
mRenderThread.join();
retry = false;
}
catch (InterruptedException e) { }
}
}
public void stopThread() {
if (mRenderThread != null) {
mRenderThread.setRunning(false);
}
}
#Override
public void onDraw(Canvas canvas) {
if (canvas != null) {
synchronized (mGameObjects) {
mGameObjectsCount = mGameObjects.size();
canvas.drawColor(Color.BLACK);
if (mGameObjectsCount > 0) {
mCurrentSpacing = Math.min(mScreenWidth/mGameObjectsCount, mGameObjectWidth);
for (int c = 0; c < mGameObjectsCount; c++) {
if (c != mHighlightedObject) {
try {
drawGameObject(canvas, mGameObjects.get(c).getDrawableID(), false, c*mCurrentSpacing, c*mCurrentSpacing+mGameObjectWidth);
}
catch (Exception e) { }
}
}
if (mHighlightedObject > -1) {
mOnDrawX1 = Math.min(mHighlightedObject*mCurrentSpacing, mScreenWidth-mGameObjectWidth);
try {
drawGameObject(canvas, mGameObjects.get(mHighlightedObject).getDrawableID(), true, mOnDrawX1, mOnDrawX1+mGameObjectWidth);
}
catch (Exception e) { }
}
}
}
}
}
private void drawGameObject(Canvas canvas, int resourceID, boolean highlighted, int xLeft, int xRight) {
if (canvas != null && resourceID != 0) {
try {
if (highlighted) {
canvas.drawRect(0, 0, mScreenWidth, mScreenHeight, mShadowPaint);
}
bitmapToDraw = MyApp.gameObjectCacheGet(resourceID);
if (bitmapToDraw == null) {
bitmapToDraw = BitmapFactory.decodeResource(getResources(), resourceID, bitmapOptions);
MyApp.gameObjectCachePut(resourceID, bitmapToDraw);
}
mDrawingRect.set(xLeft, 0, xRight, mGameObjectHeight);
canvas.drawBitmap(bitmapToDraw, null, mDrawingRect, mGraphicsPaint);
}
catch (Exception e) { }
}
}
#Override
public boolean onTouchEvent(MotionEvent event) {
synchronized (mRenderThread.getSurfaceHolder()) { // synchronized so that there are no concurrent accesses
mTouchEventAction = event.getAction();
if (mTouchEventAction == MotionEvent.ACTION_DOWN || mTouchEventAction == MotionEvent.ACTION_MOVE) {
if (event.getY() >= 0 && event.getY() < mScreenHeight) {
mTouchEventObject = (int) event.getX()/mCurrentSpacing;
if (mTouchEventObject > -1 && mTouchEventObject < mGameObjectsCount) {
mHighlightedObject = mTouchEventObject;
}
else {
mHighlightedObject = -1;
}
}
else {
mHighlightedObject = -1;
}
}
else if (mTouchEventAction == MotionEvent.ACTION_UP) {
if (mActivityCallback != null && mHighlightedObject > -1 && mHighlightedObject < mGameObjectsCount) {
try {
mActivityCallback.placeObject(mGameObjects.get(mHighlightedObject));
}
catch (Exception e) { }
}
mHighlightedObject = -1;
}
}
return true;
}
// ...
}
And this is the code for the thread that periodically calls the SurfaceView's onDraw():
package com.my.package.util;
import android.graphics.Canvas;
import android.view.SurfaceHolder;
public class MyRenderThread extends Thread {
private SurfaceHolder mSurfaceHolder;
private MySurface mSurface;
private boolean mRunning = false;
public MyRenderThread(SurfaceHolder surfaceHolder, MySurface surface) {
mSurfaceHolder = surfaceHolder;
mSurface = surface;
}
public SurfaceHolder getSurfaceHolder() {
return mSurfaceHolder;
}
public void setRunning(boolean run) {
mRunning = run;
}
#Override
public void run() {
Canvas c;
while (mRunning) {
c = null;
try {
c = mSurfaceHolder.lockCanvas(null);
synchronized (mSurfaceHolder) {
if (c != null) {
mSurface.onDraw(c);
}
}
}
finally { // when exception is thrown above we may not leave the surface in an inconsistent state
if (c != null) {
mSurfaceHolder.unlockCanvasAndPost(c);
}
}
}
}
}
The SurfaceView is included in my Activity's layout XML:
<com.my.package.util.MySurface
android:id="#+id/my_surface"
android:layout_width="fill_parent"
android:layout_height="#dimen/my_surface_height" />
Then in code it is accessed like this:
MySurface mySurface = (MySurface) findViewById(R.id.my_surface);
Rename your draw method to onDraw2(). Change the thread code to call onDraw2. This way you are not overidding the base class's ondraw. I think you might be getting 2 hits in your onDraw. One from the base class override and one from the thread.
This would explain why setting the z-order helps. You will reverse the order the 2 windows draw therefore avoiding the problem. As to the "why now" part of the question. Since you have the 2 pathways to onDraw I suspect this is unsupported android behavior, so no telling what might happen.
Also I saw you called setDrawingCache enabled. I don't think that is helping you. Usually you would call getDrawingCache at some point. Try removing it if it is not important.
The only other thing I see is that you create the thread and pass the holder in surface created. You might want to take action when surfaceChanged occurs, or at
Least verify that nothing important has changed.
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 am making an android game that needs to run a method continiously, kind of like a timer. I need that it is being called every second. How can i make this possible???
Java code:
import java.util.ArrayList;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.widget.TextView;
import android.widget.Toast;
public class ExampleView extends SurfaceView implements SurfaceHolder.Callback
{
class ExampleThread extends Thread
{
private ArrayList<Parachuter> parachuters;
private Bitmap parachuter;
private Paint black;
private boolean running;
private SurfaceHolder mSurfaceHolder;
private Context mContext;
private Handler mHandler;
private GameScreenActivity mActivity;
private long frameRate;
private boolean loading;
public ExampleThread(SurfaceHolder sHolder, Context context, Handler handler)
{
mSurfaceHolder = sHolder;
mHandler = handler;
mContext = context;
mActivity = (GameScreenActivity) context;
parachuters = new ArrayList<Parachuter>();
parachuter = BitmapFactory.decodeResource(getResources(), R.drawable.parachuteman);
black = new Paint();
black.setStyle(Paint.Style.FILL);
black.setColor(Color.WHITE);
running = true;
// This equates to 26 frames per second.
frameRate = (long) (1000 / 26);
loading = true;
}
#Override
public void run()
{
while (running)
{
Canvas c = null;
try
{
c = mSurfaceHolder.lockCanvas();
synchronized (mSurfaceHolder)
{
long start = System.currentTimeMillis();
doDraw(c);
long diff = System.currentTimeMillis() - start;
if (diff < frameRate)
Thread.sleep(frameRate - diff);
}
} catch (InterruptedException e)
{
}
finally
{
if (c != null)
{
mSurfaceHolder.unlockCanvasAndPost(c);
}
}
}
}
protected void doDraw(Canvas canvas)
{
canvas.drawRect(0, 0, canvas.getWidth(), canvas.getHeight(), black);
//Draw
for (int i = 0; i < parachuters.size(); i++)
{
canvas.drawBitmap(parachuter, parachuters.get(i).getX(), parachuters.get(i).getY(), null);
parachuters.get(i).tick();
}
//Remove
for (int i = 0; i < parachuters.size(); i++)
{
if (parachuters.get(i).getY() > canvas.getHeight())
parachuters.remove(i);
}
}
public boolean onTouchEvent(MotionEvent event)
{
if (event.getAction() != MotionEvent.ACTION_DOWN)
return false;
float x = event.getX();
float y = event.getY();
Parachuter p = new Parachuter(x, y);
parachuters.add(p);
Toast.makeText(getContext(), "x=" + x + " y=" + y, 15).show();
return true;
}
public void setRunning(boolean bRun)
{
running = bRun;
}
public boolean getRunning()
{
return running;
}
}
/** Handle to the application context, used to e.g. fetch Drawables. */
private Context mContext;
/** Pointer to the text view to display "Paused.." etc. */
private TextView mStatusText;
/** The thread that actually draws the animation */
private ExampleThread eThread;
public ExampleView(Context context)
{
super(context);
// register our interest in hearing about changes to our surface
SurfaceHolder holder = getHolder();
holder.addCallback(this);
// create thread only; it's started in surfaceCreated()
eThread = new ExampleThread(holder, context, new Handler()
{
#Override
public void handleMessage(Message m)
{
// mStatusText.setVisibility(m.getData().getInt("viz"));
// mStatusText.setText(m.getData().getString("text"));
}
});
setFocusable(true);
}
#Override
public boolean onTouchEvent(MotionEvent event)
{
return eThread.onTouchEvent(event);
}
public ExampleThread getThread()
{
return eThread;
}
#Override
public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3)
{
// TODO Auto-generated method stub
}
public void surfaceCreated(SurfaceHolder holder)
{
if (eThread.getState() == Thread.State.TERMINATED)
{
eThread = new ExampleThread(getHolder(), getContext(), getHandler());
eThread.start();
}
else
{
eThread.start();
}
}
#Override
public void surfaceDestroyed(SurfaceHolder holder)
{
boolean retry = true;
eThread.setRunning(false);
while (retry)
{
try
{
eThread.join();
retry = false;
}
catch (InterruptedException e)
{
}
}
}
}
I need to add a function or a socalled "method", a public void or something like that, that should be called every second and should do the exact same code as the MotionEvent event method, the onTouchEvent.
Following Rob's commented link, consider (which is not the accepted answer, though) reviewing this from the Android Developer's site, Resources section: http://developer.android.com/resources/articles/timed-ui-updates.html
It describes how to use the android os Handler class to implement a timer, rather than using the Timer and TimerTask classes themselves.
This pretty much what you are looking for.
How to run a Runnable thread in Android?
It does sth every 1000ms using a thread.
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);
}
}
}
}
};
onRestoreInstanceState(Bundle savedInstanceState)
is not geting called, I am pasting my code below. Actually I want to redraw all the points that are saved when my activity went in background.
package com.geniteam.mytest;
import java.util.ArrayList;
import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.os.Bundle;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.Window;
public class Tutorial2D extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(new Panel(this));
}
#Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
Panel panel = new Panel(this);
outState.putSerializable("test", panel._graphics);
}
#Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
Panel panel = new Panel(this);
panel.set_graphics((ArrayList<GraphicObject>) savedInstanceState.getSerializable("test"));
}
class Panel extends SurfaceView implements SurfaceHolder.Callback {
private TutorialThread _thread;
private ArrayList<GraphicObject> _graphics = new ArrayList<GraphicObject>();
public ArrayList<GraphicObject> get_graphics() {
return _graphics;
}
public void set_graphics(ArrayList<GraphicObject> graphics) {
_graphics = graphics;
}
public Panel(Context context) {
super(context);
getHolder().addCallback(this);
_thread = new TutorialThread(getHolder(), this);
setFocusable(true);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
synchronized (_thread.getSurfaceHolder()) {
// if (event.getAction() == MotionEvent.ACTION_DOWN) {
GraphicObject graphic = new GraphicObject(BitmapFactory.decodeResource(getResources(), R.drawable.icon));
graphic.getCoordinates().setX((int) event.getX() - graphic.getGraphic().getWidth() / 2);
graphic.getCoordinates().setY((int) event.getY() - graphic.getGraphic().getHeight() / 2);
_graphics.add(graphic);
//}
return true;
}
}
#Override
public void onDraw(Canvas canvas) {
canvas.drawColor(Color.BLACK);
Bitmap bitmap;
GraphicObject.Coordinates coords;
for (GraphicObject graphic : _graphics) {
bitmap = graphic.getGraphic();
coords = graphic.getCoordinates();
canvas.drawBitmap(bitmap, coords.getX(), coords.getY(), null);
}
}
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
// TODO Auto-generated method stub
}
public void surfaceCreated(SurfaceHolder holder) {
try{
_thread.setRunning(true);
_thread.start();
}catch(Exception ex){
_thread = new TutorialThread(getHolder(), this);
_thread.start();
}
}
public void surfaceDestroyed(SurfaceHolder holder) {
// simply copied from sample application LunarLander:
// 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;
_thread.setRunning(false);
while (retry) {
try {
_thread.join();
retry = false;
} catch (InterruptedException e) {
// we will try it again and again...
}
}
}
}
class TutorialThread extends Thread {
private SurfaceHolder _surfaceHolder;
private Panel _panel;
private boolean _run = false;
public TutorialThread(SurfaceHolder surfaceHolder, Panel panel) {
_surfaceHolder = surfaceHolder;
_panel = panel;
}
public void setRunning(boolean run) {
_run = run;
}
public SurfaceHolder getSurfaceHolder() {
return _surfaceHolder;
}
#Override
public void run() {
Canvas c;
while (_run) {
c = null;
try {
c = _surfaceHolder.lockCanvas(null);
synchronized (_surfaceHolder) {
_panel.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);
}
}
}
}
}
class GraphicObject {
/**
* Contains the coordinates of the graphic.
*/
public class Coordinates {
private int _x = 100;
private int _y = 0;
public int getX() {
return _x + _bitmap.getWidth() / 2;
}
public void setX(int value) {
_x = value - _bitmap.getWidth() / 2;
}
public int getY() {
return _y + _bitmap.getHeight() / 2;
}
public void setY(int value) {
_y = value - _bitmap.getHeight() / 2;
}
public String toString() {
return "Coordinates: (" + _x + "/" + _y + ")";
}
}
private Bitmap _bitmap;
private Coordinates _coordinates;
public GraphicObject(Bitmap bitmap) {
_bitmap = bitmap;
_coordinates = new Coordinates();
}
public Bitmap getGraphic() {
return _bitmap;
}
public Coordinates getCoordinates() {
return _coordinates;
}
}
}
onRestoreInstanceState only gets called if the app is destroyed and re-created. Putting the app in the background then bringing it up again will call onResume, but not onRestoreInstanceState.