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?
Related
I'm trying to get an application to paint something on a canvas every half a second, but the SurfaceHolder.getSurface().isValid() returns false, and when I call SurfaceHolder.lockCanvas() this returns null.
As per this SO question, I should use a SurfaceHolder.Callback.surfaceCreated but the surface is never created.
The onCreate method from my main Activity
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
ChartPainter p = new ChartPainter(this);
}
And part of my ChartPainter.java
public ChartPainter(Context context) {
super(context);
holder = getHolder();
final boolean a[] = new boolean[1];
a[0] = false;
holder.addCallback(new Callback() {
#Override
public void surfaceCreated(SurfaceHolder holder) {
// TODO Auto-generated method stub
a[0] = true;
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format,
int width, int height) {
// TODO Auto-generated method stub
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
// TODO Auto-generated method stub
}
});
} [...]//more omitted code here
How do I create the surface for the SurfaceHolder?
Does ChartPainter extends SurfaceView?
Note: SurfaceHolder is usually used with SurfaceView. When the activity goes to the foreground and its SurfaceView is about to be rendered, WindowManager will ask SurfaceFlinger to create a new surface. Then SurfaceHolder's surfaceCreated() will be called.
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.
I am building a snake game app.
So fur it works, except for the what it shows.
For some reason it shows two snakes: the original snake that moves and can be controlled, and another begginging of a snake that doesn't do anything.
Before that I drew at every cycle in the loop a background color, so it would cover the last canvas, and there was no problem.
Then I decided to divide the snake from the background, so I have made the snake canvas's background transparent and that it would clear the canvas each time it wants to draw a new canvas (each loop-to move the snake).
Here is the code:
The run of the thread:
public void run() {
long stepPerSecond=1000/FPS;
long startTime;
long sleepTime;
while(isRunning){
Canvas c=null;
startTime=System.currentTimeMillis();
try{
c=this.getHolder().lockCanvas();
synchronized (this.getHolder()) {
this.onDraw(c);
}
}
catch(Exception e){
}
finally{
if(c!=null){
this.getHolder().unlockCanvasAndPost(c);
}
}
sleepTime= stepPerSecond-(System.currentTimeMillis()-startTime);
if(sleepTime>0)
try {
Thread.sleep(sleepTime);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
The snake's ondraw (it uses the snake's class on draw):
public void onDraw(Canvas canvas) {
// TODO Auto-generated method stub
super.onDraw(canvas);
canvas.drawColor(color.transparent, Mode.CLEAR);
snake.onDraw(canvas);
}
The snake's class onDraw:
public void onDraw(Canvas canvas){
switch(dirTransfare(dir)){
case 1://RIGHT
xLoc=xLoc+PART_SIZE;
break;
case 2://UP
yLoc=yLoc-PART_SIZE;
break;
case -1://LEFT
xLoc=xLoc-PART_SIZE;
break;
case -2://DOWN
yLoc=yLoc+PART_SIZE;
break;
}//swich
int x=xLoc;
int y=yLoc;
for(Brick bp:SnakeBody){
bp.setR(0+x, 0+y, PART_SIZE+x, PART_SIZE+y);
canvas.drawRect(bp.getR(),bp.getP());
int xtemp=bp.getX();
int ytemp=bp.getY();
bp.setX(x);
bp.setY(y);
x=xtemp;
y=ytemp;
}//for each
}//onDraw
Here is the mainActivity, which summons the snakeVew and the backgorundView (snake is the game view and the background is the arena)
public class MainActivity extends Activity {
GameView gv;
ImageView left;
ImageView right;
ImageView up;
ImageView down;
Arena a;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
/*requestWindowFeature(Window.FEATURE_NO_TITLE);
v= new GameView1(this);
setContentView(v);
*/
gv= new GameView(this);
a=new Arena(this);
setContentView(R.layout.game_view);
LinearLayout surface = new LinearLayout(this);
LinearLayout backGround = new LinearLayout(this);
surface = (LinearLayout)findViewById(R.id.surface);
backGround = (LinearLayout)findViewById(R.id.background);
surface.addView(gv);
backGround.addView(a);
left=(ImageView) findViewById(R.id.left);
right=(ImageView) findViewById(R.id.right);
up=(ImageView) findViewById(R.id.up);
down=(ImageView) findViewById(R.id.down);
left.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
if(gv.snake.getDir()!="LEFT"&&gv.snake.getDir()!="RIGHT"){
gv.snake.Left();
}
}
});
right.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
if(gv.snake.getDir()!="RIGHT"&&gv.snake.getDir()!="LEFT"){
gv.snake.Right();
}
}
});
up.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
if(gv.snake.getDir()!="UP"&&gv.snake.getDir()!="DOWN"){
gv.snake.Up();
}
}
});
down.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
if(gv.snake.getDir()!="DOWN"&&gv.snake.getDir()!="UP"){
gv.snake.Down();
}
}
});
}
The problem is not in the background (the arena class); I have alredy took it down and confirmed that (it worked the same away, with the bug, even without using the arena class).
Here is how it looks with the bug:
http://i.tinyuploads.com/q7oztz.jpg
(you can see two snakes - the long one is the real one)
The blue background is from class arena.
Any ideas? Tnx for help :D
I have a problem with a thread in surfaceview. I can't understand how to onPause/onResume when I lock my phone. Whatever I do, the thread doesn't respond after locking/unlocking the phone.
In the activity:
#Override
protected void onResume() {
// TODO Auto-generated method stub
super.onResume();
surfaceView.SurfaceView_OnResume();
}
#Override
protected void onPause() {
// TODO Auto-generated method stub
super.onPause();
surfaceView.SurfaceView_OnPause();
}
In the surfaceview
public void SurfaceView_OnResume() {
if (null != surfaceViewThread) {
surfaceViewThread.setRunning(true);
surfaceViewThread.notify();
}
}
public void MySurfaceView_OnPause() {
surfaceViewThread.setRunning(false);
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
// TODO Auto-generated method stub
boolean retry = true;
myGameThread.setRunning(false);
while (retry) {
try {
myGameThread.join();
retry = false;
} catch (InterruptedException e) {
}
}
}
In the thread:
public void setRunning(boolean run) {
runFlag = run;
}
Thread.setRunning(boolean b) is not in the Android API.
You can check it here. http://developer.android.com/reference/java/lang/Thread.html
And if I need a Thread, I prefer to use Runnable(Interface), not Thread(Object).
To control my Thread cycle, I will design my method:run() like this...
run(){
while(threadRun){
...//What you want to do in the thread.
while(threadPause){
}
}
}
The Boolean:threadRun will turn to false in Activity.onDestroy(), or any other time you really want to shut down the thread.
The Boolean:threadPause ... turn to false in Activity.onPause() and turn to true in Activity.onResume().
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();
}