Drawing to Canvas in Android throws Null Pointer Exception - android

I am trying to create a simple render of a background with an image on top to update roughly every 30seconds. I am using a canvas to get this done but when I try and print to the canvas it throws a NPE. As far as I can tell the canvas has been initialised. The activity starts the view which starts/stops the thread that runs the draw method. It is in the draw method that the NPE is thrown. This is the activity that starts it all:
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
view = new GameView(this);
setContentView(view);
view.onCreate();
}
public void onPause() {
super.onPause();
view.onPause();
}
public void onResume() {
super.onResume();
view.onResume();
}
These are the main functions of my Surface View:
public GameView(Context context) {
super(context);
getHolder().addCallback(this);
setFocusable(true);
}
public void onCreate() {
_drawThread = new DrawThread(getHolder(), this);
}
synchronized public void draw(Canvas canvas) {
canvas.getHeight(); //returns NPE
}
public void onResume() {
if (!_drawThread.isAlive()) {
_drawThread.setRunning(true);
_drawThread.start();
} else {
_drawThread.setRunning(true);
}
}
public void onPause() {
boolean retry = true;
_drawThread.setRunning(false);
while (retry) {
try {
_drawThread.join();
retry = false;
} catch (InterruptedException e) {
}
}
}
And my draw thread looks like:
public void run() {
Canvas c;
while (_running) {
c = null;
try {
c = _surfaceHolder.lockCanvas();
synchronized (_surfaceHolder) {
_game.draw(c);
try {
Thread.sleep(500);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
} finally {
if (c != null) {
_surfaceHolder.unlockCanvasAndPost(c);
}
}
}
}
From what I can tell the canvas somehow doesn't get initialised before the draw thread is created which causes the NPE but I can't see what is wrong with the code. A little help or advise would be great.

You need to register your own SurfaceHolder.Callback or SurfaceHolder.Callback2 with the SurfaceHolder and ensure the surface has been created before attempting to draw into it. If you attempt to lock the canvas before the surface has been created, it will not be able to give you a Canvas object. You usually don't need to override SurfaceView, but just use it as a mechanism to get access to the backing surface in which you wish to draw.

Related

surfaceview gives darker shade

I am new to graphics and surfaceviews etc. I have heard that it is better to draw on a seperate thread than on the main thread. i have 2 activities one which is drawn using ondraw of the view, the other uses surface view. both have the same code for drawing. however the latter gives a much darker backgroung color-even at max alpha setting(255). If I comment out the drawargb line I get a black background. I tried many things like setting background color of surfaceview object and setting pixelformat to rgb888 or transparent but none of these work.Following is the code:
SurfaceHolder ourHolder;Boolean isRunning=true;
Thread ourThread;ArrayList<Float> amtint=new ArrayList();float max;
String names[];String company;
public GraphSview(Context c) {
super(c);
ourHolder=getHolder();
ourThread=new Thread(this);
ourThread.start();}
public void pause(){
isRunning=false;
while(true){try {
ourThread.join();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}break;}ourThread=null;
}
public void Resume()
{
isRunning=true;
ourThread=new Thread(this);
ourThread.start();}
#Override
public void run() {
// TODO Auto-generated method stub
while(isRunning){
if(!ourHolder.getSurface().isValid())continue;
Canvas canvas=ourHolder.lockCanvas();
canvas.drawARGB(255, 33, 181, 238);
.... ourHolder.unlockCanvasAndPost(canvas);
code for the main activity is
public class GraphS extends Activity{
GraphSview ourSview;
#Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
ourSview=new GraphSview(this);
ourSview.getHolder().setFormat(PixelFormat.TRANSPARENT);
setContentView(ourSview);
//ourSview.setBackgroundColor(0Xffffffff);
}
#Override
protected void onPause() {
ourSview.pause();
super.onPause();
}
#Override
protected void onResume() {
ourSview.Resume(); // TODO Auto-generated method stub
super.onResume();
}
}
is there something wrong with the code?
is there any alternate way of creating and displaying graphs other than surface view?

Surfaceview android

I am new to Android. I'm trying to develop a game app using the surface view. The app runs properly but at the end when I exit it shows the null pointer exception on onDraw() method and the app gets crashed. Please help me out and thanks in advance.
Here is my code:-
public class Gameloopthread extends Thread {
private Gameview view;
static final long fps=30;
boolean running;
public Gameloopthread(Gameview view)
{
this.view=view;
}
// 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
public void setRunning(Boolean run)
{
running=true;
}
#Override
public void run() {
long tickps=3000/fps;
long startTime=0;
long sleepTime;
while(running)
{
Canvas c=null;
try{
c=view.getHolder().lockCanvas();
//Log.d("Canvas==>",""+c);
synchronized(view.getHolder()){
view.onDraw(c);
}
}finally{
if(c!=null){
view.getHolder().unlockCanvasAndPost(c);
}
}
sleepTime=tickps-(System.currentTimeMillis()-startTime);
try{
if(sleepTime>0)
{
sleep(sleepTime);
}else{
sleep(30);
}
}catch(Exception e){
}
}
super.run();
}
//
}
You should take a look at the lockCanvas call, the surface has probably been destroyed and you have passed a null canvas reference to view.onDraw(). There's some recommendations in the API on how to deal with surface state.
http://developer.android.com/reference/android/view/SurfaceHolder.html#lockCanvas()

SurfaceView implements Runnable - Thread does not start

Have been looking on some tutorials for drawing canvas using SurfaceView, but the only thing that shows up is a black background.
public class FighterActivity extends Activity implements OnTouchListener {
/** Called when the activity is first created. */
SurfaceController surface;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
surface = new SurfaceController(this);
surface.setOnTouchListener(this);
setContentView(surface);
}
#Override
protected void onPause() {
// TODO Auto-generated method stub
super.onPause();
surface.pause();
}
#Override
protected void onResume() {
// TODO Auto-generated method stub
super.onResume();
surface.resume();
}
public class SurfaceController extends SurfaceView implements Runnable{
Thread thread = null;
SurfaceHolder holder;
public SurfaceController(Context context) {
super(context);
// TODO Auto-generated constructor stub
holder = getHolder();
System.out.println("HERE");
}
public void run() {
// TODO Auto-generated method stub
System.out.println("Hello World2");
while(true){
if(!holder.getSurface().isValid()){
System.out.println("NOT VALID");
continue;
}
System.out.println("VALID!");
Canvas can = holder.lockCanvas();
can.drawARGB(255, 150, 150, 0);
holder.unlockCanvasAndPost(can);
}
}
public void pause(){
}
public void resume(){
}
}
public boolean onTouch(View view, MotionEvent me) {
// TODO Auto-generated method stub
return false;
}
}
It gets to the System.out.println("HERE"); and prints out HERE, but nothing more happends, In other words the thread does not get started since "Hello World2" is not printed, what is the problem?
Thanks for any help
I'm assuming you're building off of this: http://android-coding.blogspot.ca/2011/05/drawing-on-surfaceview.html
You'll notice there the onResumeMySurfaceView and onPauseMySurfaceView (resume and pause in your SurfaceController, respectively) start the actual thread. You'll need to do that in your code, too, e.g. in SurfaceController:
protected boolean running = false;
public void resume() {
running = true;
thread = new Thread(this);
thread.start();
}

Android application crashes when re-entering after the home button is pressed. This is the code

I've searched over and over in this forum & google about this issue, maybe it has to do something with my thread or the way how the game is starting.
This is the skeleton of the game application, please tell me what I'm doing wrong.
This is what I'm doing in thread;
public class GameThread extends Thread
{
static final long FPS = 30;
private GameView view;
private boolean running = false;
private SurfaceHolder surfaceHolder;
public boolean isSurfaceCreated = false;
private Object mPauseLock;
private boolean mPaused;
public GameThread(SurfaceHolder surfaceHolder, Handler handler, GameView view)
{
super();
mPauseLock = new Object();
mPaused = false;
this.surfaceHolder = surfaceHolder;
this.view = view;
}
public void setRunning(boolean run)
{
running = run;
}
/**
* pause thread.
*/
public void onPause() {
synchronized (mPauseLock) {
mPaused = true;
}
}
/**
* resume thread.
*/
public void onResume() {
synchronized (mPauseLock) {
mPaused = false;
mPauseLock.notifyAll();
}
}
#Override
public void run()
{
// run our thread on high priority to keep from getting slowdown
android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_URGENT_DISPLAY);
// wait for surface to become available # start
while (!isSurfaceCreated && running)
{
try {
sleep(50);
} catch (InterruptedException e) {}
}
long ticksPS = 1000 / FPS;
long startTime;
long sleepTime;
while (running){
Canvas c = null;
startTime = System.currentTimeMillis();
//long msSinceLastTick = System.currentTimeMillis() - view.lastTickMs;
try {
c = surfaceHolder.lockCanvas(null);
synchronized (surfaceHolder)
{
/*
* stop updating when pause is pressed
*/
if(mPaused == false)
{
view.update();
}
view.onDraw(c);
}
} finally {
if (c != null)
{
surfaceHolder.unlockCanvasAndPost(c);
}
}
sleepTime = ticksPS - (System.currentTimeMillis() - startTime);
try {
if (sleepTime > 0)
sleep(sleepTime);
else
sleep(10);
} catch (Exception e) {}
}
}
This is the start activity code;
import android.app.Activity;
import android.content.pm.ActivityInfo;
import android.os.Bundle;
public class test_game extends Activity {
/** Called when the activity is first created. */
private GameView Game;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Game = new GameView(this);
setContentView(Game);
}
#Override
public void onBackPressed()
{
super.onBackPressed();
//KILL ALL
finish();
System.runFinalizersOnExit(true);
System.exit(0);
}
// ===========================================================
// onPause
// ===========================================================
protected void onPause() {
super.onPause();
}
// ===========================================================
// onStop
// ===========================================================
protected void onStop() {
super.onStop();
}
// ===========================================================
// onDestroy
// ===========================================================
#Override
protected void onDestroy() {
super.onDestroy();
}
}
Added extra lines in AndroidManifest.xml
android:launchMode="singleTask"
android:alwaysRetainTaskState="true"
GameView looks like this:
public class GameView extends SurfaceView {
private SurfaceHolder holder;
private GameThread Thread = null;
private int testVar = 0;
private boolean isPaused = false;
public GameView(Context context)
{
super(context);
loadGameFiles();
holder = getHolder();
Thread = new GameThread(holder, new Handler(), this);
holder.addCallback(new SurfaceHolder.Callback()
{
#Override
public void surfaceDestroyed(SurfaceHolder holder)
{
boolean retry = true;
Thread.setRunning(false);
while (retry)
{
try {
Thread.join();
retry = false;
} catch (InterruptedException e)
{
}
}
}
#Override
public void surfaceCreated(SurfaceHolder holder)
{
Thread.isSurfaceCreated = true;
if(isPaused == true)
{
onResume();
}
Thread.setRunning(true);
Thread.start();
GameMenu();
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height)
{
}
});
setFocusable(true);
}
public boolean isPaused()
{
return this.isPaused;
}
/**
* Pauses the physics update & animation.
*/
public void onPause() {
synchronized (holder)
{
if(isPaused == false)
{
isPaused = true;
Thread.onPause();
}
}
}
public void onResume()
{
synchronized (holder)
{
if(isPaused == true)
{
isPaused = false;
Thread.onResume();
}
}
}
etc..
Thanks for the replies, the forum commentbox doesn't let me post this; anyway, here it is:
Hi Frankenstein, I've tried what you suggested here, still doesn't work. My resume code in the GameView looks like this;
public void onResume(){ synchronized (holder)
{ if(isPaused == true){
isPaused = false; //resume notification to the gameview
Thread.onResume(); //resume the thread
}
}
}
This is on the Activity class;
#Override
protected void onPause() {
super.onPause();
Game.onPause();
}
#Override
protected void onResume() {
super.onResume();
Game.onResume();
}
I have not used logcat, not sure how to use it, I can sure call it in each steps in java but where does it displays the error/logs? thanks in advance guys!
When I resume it shows following error in LogCat;
Added this line to avoid the previous problem;
Thread.isSurfaceCreated = true;
Thread.setRunning(true);
Thread.start();
loadGame();
UPDATE:
The application returns to black screen, but it's not frozen.
Errors (updated) in logcat;
12-14 16:54:52.176: ERROR/MediaPlayerService(3937): create PVPlayer
12-14 16:55:03.172: ERROR/dalvikvm(4619): Failed to write stack traces to /data/anr/traces.txt (1093 of 3526): Unknown error: 0
12-14 16:55:03.910: ERROR/dalvikvm(25464): Failed to write stack traces to /data/anr/traces.txt (2401 of 3332): Math result not representable
12-14 16:55:03.918: ERROR/dalvikvm(25279): Failed to write stack traces to /data/anr/traces.txt (-1 of 2354): Math result not representable
12-14 16:55:32.394: ERROR/imdg81(19379): IsShutDownStarted()
12-14 16:55:32.590: ERROR/imdg81(19379): IsShutDownStarted()
12-14 16:55:37.902: ERROR/MediaPlayer(19379): error (100, 0)
12-14 16:55:37.930: ERROR/SoundPool(5264): Unable to load sample: (null)
12-14 16:55:39.281: ERROR/SoundBooster(5328): readSBTable: file open error!
12-14 16:55:39.281: ERROR/AcousticEQ(5328): [AEQ] aeqcoe.txt: file open error!
12-14 16:55:39.500: ERROR/AudioService(19379): Media server died.
12-14 16:55:39.500: ERROR/AudioService(19379): Media server started.
12-14 16:55:39.996: ERROR/MediaPlayerService(5328): create PVPlayer
In your onSurfaceCreated method you have this block of code:
if(isPaused == true){
onResume();
}
Thread.setRunning(true);
Thread.start();
your call to Thread.start() is called no matter what (even if isPaused is true). Since your thread is already started in this case, you're trying to start it twice and thus getting an illegal state exception.
Thanks guys!
I've fixed this issue, the black screen was showing because the thread isn't created again but being manipulated when I entered 2nd time to the screen. Therefore, it showed an empty/null thread being manipulated as black screen. I've added following line to OnResume()
if(!Thread.isAlive())
{
Thread = new GameThread(holder, new Handler(), this);
}
This is the fix for my issue, but now I've to implement onSaveInstanceState & onRestoreInstanceState to avoid the from re-starting from beginnig.

Automatically Exit SurfaceView

I have a game I'm developing for Android 2.x. When the player looses, I want to automatically exit that and go back to the previous menu of the game. This may be a simple question, but how do I do that?
I have a MenuActivity, which calls GameActivity, which calls the GameView (implementation of SurfaceView) where the game logic is.
UPDATE: No, wait, it's more complex than that. To make this game I followed the MoonLander example, which used threads.
GameView:
public class GameActivity extends Activity
{
GameView gameView;
GameThread gThread;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
gameView = new GameView(this);
setContentView(gameView);
gThread = gameView.getThread();
gThread.doStart();
}
}
GameView:
package com.cp.balldrop;
public class GameView extends SurfaceView implements SurfaceHolder.Callback
{
class GameThread extends Thread
{
public GameThread(SurfaceHolder sHolder, Context context, Handler handler)
{
//Code
}
public void doStart()
{
synchronized (mSurfaceHolder)
{
}
}
#Override
public void run()
{
while (running)
{
Canvas c = null;
try
{
c = mSurfaceHolder.lockCanvas(null);
synchronized (mSurfaceHolder)
{
doDraw(c);
}
}
finally
{
if (c != null)
{
mSurfaceHolder.unlockCanvasAndPost(c);
}
}
}
}
protected void doDraw(Canvas canvas)
{
//code
}
}
/** 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 GameThread gThread;
public GameView(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()
gThread = new GameThread(holder, context, new Handler()
{
#Override
public void handleMessage(Message m)
{
// mStatusText.setVisibility(m.getData().getInt("viz"));
// mStatusText.setText(m.getData().getString("text"));
}
});
setFocusable(true);
}
public GameThread getThread()
{
return gThread;
}
public void surfaceCreated(SurfaceHolder holder)
{
gThread.start();
}
#Override
public void surfaceDestroyed(SurfaceHolder holder)
{
boolean retry = true;
gThread.setRunning(false);
while (retry)
{
try
{
gThread.join();
retry = false;
}
catch (InterruptedException e)
{
}
}
}
}
In my thread, I call the following method from my surfaceview's doTouch:
public void doLose() {
synchronized (mSurfaceHolder) {
//quit to mainmenu
((Activity) mContext).finish();
}
}
This seems to shut down the surfaceview and the activity hosting it, dumping me back in my main-menu activity. Note the casting and the predefined context.
What about calling finish() on the GameActivity?

Categories

Resources