Strange delay on start my android app - java

I should warn you I'm newbie of android developing.
The problem: After my app starts, it has black screen and after few seconds, it starts to draw what I need. I've checked drawing thread already started, and already drew content several times, but screen is still black :(
What I'm missing?
Here is my code:
Activity
public class MainActivity extends Activity {
protected SurfaceView surface;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
surface = new GameSurfaceView(this);
setContentView(surface);
}
}
SurfaceView
public class GameSurfaceView extends SurfaceView implements SurfaceHolder.Callback {
protected DrawThread drawThread;
public GameSurfaceView(Context context) {
super(context);
getHolder().addCallback(this);
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
drawThread = new DrawThread(getHolder());
drawThread.start();
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
drawThread.interrupt();
}
}
Drawing thread
public class DrawThread extends Thread {
public static final long FPS = 30;
protected SurfaceHolder surfaceHolder;
public DrawThread(SurfaceHolder surfaceHolder) {
super();
this.surfaceHolder = surfaceHolder;
}
#Override
public void run() {
while (!isInterrupted()) {
Canvas canvas = null;
try {
long renderStartedAt = SystemClock.elapsedRealtime();
canvas = surfaceHolder.lockCanvas();
if (canvas != null) {
canvas.drawColor(Color.CYAN);
// TODO DRAW
}
long duration = (1000 - (SystemClock.elapsedRealtime() - renderStartedAt) * FPS) / FPS;
if (duration > 0) {
sleep(duration);
}
} catch (InterruptedException e) {
interrupt();
} finally {
if (canvas != null) {
surfaceHolder.unlockCanvasAndPost(canvas);
}
}
}
}
}

I found the solution of my problem! unlockCanvasAndPost() does not send invalidate to SurfaceView, so just adding surface.postInvalidate() right after unlockCanvasAndPost() fix delay on startup.

You can use traceview to find where the holdup is.
Check out the profiling with traceview introduction.
Cheers!

Related

OnClickListener in SurfaceView Android

I'm trying to add an Onclicklistener to my SurfaceView. I've put two png images in a loop that looks like a bird flapping its wings. I want a sound to be played when the user clicks on the bird but currently, nothing is happening. I'm not really sure how I would implement soundpool yet but for now, I've just added a toast message just to see if the onClick works. Unfortunately, nothing happens when I click on the bird in the emulator.
Any help on how to implement an on-click listener and soundpool to my surfaceView is much appreciated!
public class PlayActivity extends AppCompatActivity {
surfaceView view;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
view = new surfaceView(this);
setContentView(view);
}
public class surfaceView extends SurfaceView implements View.OnClickListener {
public surfaceView(Context context) {
super(context);
new Anim().start();
}
#Override
public void onClick(View v) {
Toast.makeText(getApplicationContext(),"Bird Clicked",Toast.LENGTH_SHORT).show();
}
private class Anim extends Thread {
int counter = 0;
#Override
public void run() {
long last_updated_time = 0;
long delay = 250;
int[] img_ids = {
R.drawable.bird1,
R.drawable.bird2
};
while (true) {
boolean playing = true;
if (playing) {
long current_time = System.currentTimeMillis();
if (current_time > last_updated_time + delay) {
if (counter >= 2) {
counter = 0;
}
draw(img_ids[counter]);
last_updated_time = current_time;
counter++;
}
}
}
}
private void draw (int img_ids) {
SurfaceHolder holder = getHolder();
Canvas canvas = holder.lockCanvas();
if (canvas != null) {
canvas.drawColor(Color.WHITE);
Paint paint = new Paint();
Bitmap bitmap = BitmapFactory.decodeResource(getContext().getResources(),
img_ids);
Bitmap resized = Bitmap.createScaledBitmap(bitmap,(int)(bitmap.getWidth()*0.2), (int)(bitmap.getHeight()*0.2), true);
canvas.drawBitmap(resized, 100, 100, paint);
holder.unlockCanvasAndPost(canvas);
}
}
}
}
}
It looks like you haven't set an OnClickListener anywhere. You can do so with View.setOnClickListener.

How to start new activity from another activity without button click in android

I made a simple game, where whenever my object reaches end of the screen current activity stops and another activity stars.
I have created a simple boolean method called collisionDetection() which checks whether an object is hitting the end of the screen or not. However, I don't know where I should use that method collisionDetection() .
Should I check for collision at onResume? And when collision is detected, how to start another activity and stop the main one?
My class for first activity
public class ZmijicaCrtanje extends AppCompatActivity implements View.OnTouchListener{
ZmijicaSV zmija;
private static int score=0;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
zmija=new ZmijicaSV(this);
zmija.setOnTouchListener(this);
setContentView(zmija);
}
#Override
protected void onPause() {
super.onPause();
zmija.pause();
}
#Override
protected void onResume() {
super.onResume();
zmija.resume();
}
#Override
public boolean onTouch(View v, MotionEvent event) {
boolean up=zmija.sp.isUp();
boolean right=zmija.sp.isRight();
boolean down=zmija.sp.isDown();
boolean left=zmija.sp.isLeft();
switch(event.getAction()) {
case MotionEvent.ACTION_DOWN:
if(up) {
zmija.sp.setUp(false);
zmija.sp.setRight(true);
update();
break;
}
if(right) {
zmija.sp.setRight(false);
zmija.sp.setDown(true);
update();
break;
}
if(down) {
zmija.sp.setDown(false);
zmija.sp.setLeft(true);
update();
break;
}
if(left) {
zmija.sp.setLeft(false);
zmija.sp.setUp(true);
update();
break;
}
}
return true;
}
public void update()
{
score++;
}
public int getScore()
{
return score;
}
}
public class ZmijicaSV extends SurfaceView implements Runnable {
private boolean Collision;
Thread t=null;
Pravougaonik pr;
SurfaceHolder holder;
boolean isRunning=false;
SnakeParts sp;
ZmijicaCrtanje zc;
public ZmijicaSV(Context context) {
super(context);
holder=getHolder();
pr=new Pravougaonik(context);
sp=new SnakeParts();
zc=new ZmijicaCrtanje();
Collision=false;
}
public void run()
{
Paint p=new Paint();
p.setColor(Color.BLUE);
p.setStyle(Paint.Style.FILL);
while(isRunning)
{
if(!holder.getSurface().isValid()) {
continue;
}
Canvas c=holder.lockCanvas();
c.drawColor(Color.BLACK);
sp.Draw(c);
pr.onDraw(c);
sp.update();
drawText(c);
holder.unlockCanvasAndPost(c);
try {
t.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public void resume()
{
isRunning=true;
t=new Thread(this);
t.start();
}
public void pause()
{
isRunning=false;
while(true)
{
try {
t.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
break;
}
t=null;
}
public void drawText(Canvas canvas)
{
Paint paint=new Paint();
paint.setColor(Color.WHITE);
paint.setTextSize(50);
paint.setTypeface(Typeface.create(Typeface.DEFAULT,Typeface.BOLD));
canvas.drawText("Score:"+zc.getScore(),getWidth()-230,getHeight()-25,paint);
}
public boolean checkCollision()
{
if((sp.getHeadX()<-1)||(sp.getHeadX()>getWidth())||(sp.getHeadY()>getHeight())||(sp.getHeadY()<-1))
Collision=true;
return Collision;
}
}
Put the collisionDetection() method in your public void update() method like
public void update()
{
score++;
collisionDetection();
}
And when collition is detected in collisionDetection() start next activity by Intent like
Intent next=new Intent(this.class,your_class_for_secondactivity.class);
startActivity(next);

How do I take a photo in the onCreate method in Android instead of onClick?

I am working on a project that takes a photo. It is currently working fine when I leave it as is, but when I try to change it so that the picture is attempted to be taken in a different method (rather than being activated by an onClick() method), it errors out every time. Currently the WORKING code is as follows:
public class Testing123 extends Activity {
private SurfaceView preview=null;
private SurfaceHolder previewHolder=null;
private Camera camera=null;
private boolean inPreview=false;
private boolean cameraConfigured=false;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
preview = (SurfaceView)findViewById(R.id.preview);
previewHolder = preview.getHolder();
previewHolder.addCallback(surfaceCallback);
previewHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
testing(); //HERE is where I am testing, but cannot get it to work. [See part 2]
}
public void onResume() {
super.onResume();
if (camera == null) {
camera=Camera.open();
L.m("Camera open in onResume");
}
startPreview();
}
public void onPause() {
if (inPreview) {
camera.stopPreview();
}
camera.release();
camera=null;
inPreview=false;
super.onPause();
}
public boolean onCreateOptionsMenu(Menu menu) {
new MenuInflater(this).inflate(R.menu.options, menu);
return(super.onCreateOptionsMenu(menu));
}
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == R.id.camera) {
if (inPreview) {
camera.takePicture(null, null, photoCallback); //THIS IS WHERE THE PHOTO IS BEING TAKEN
inPreview=false;
}
}
return(super.onOptionsItemSelected(item));
}
private void initPreview(int width, int height) {
if (camera != null && previewHolder.getSurface() != null) {
try {
camera.setPreviewDisplay(previewHolder);
}
catch (Throwable t) {
Log.e("PreviewDemo-surfaceCallback", "Exception in setPreviewDisplay()", t);
}
if (!cameraConfigured) {
Camera.Parameters parameters=camera.getParameters();
setCameraResolution(); //Leaving this method out for now
camera.setParameters(parameters);
cameraConfigured=true;
}
}
}
private void startPreview() {
camera.startPreview();
}
SurfaceHolder.Callback surfaceCallback=new SurfaceHolder.Callback() {
public void surfaceCreated(SurfaceHolder holder) {
}
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
initPreview(width, height);
startPreview();
}
public void surfaceDestroyed(SurfaceHolder holder) {
}
};
Camera.PictureCallback photoCallback = new Camera.PictureCallback() {
public void onPictureTaken(byte[] data, Camera camera) {
//This part is no problem, I am able to write it to the file and use the data from the output of the camera
}
}
The issue comes when I try to make a new call, as you see in the onCreate() method, called testing(); Whenever I call the testing method, which is an attempt to bypass a need to press a button, it errors out. Here is the testing() code:
private void testing() {
try{
cameraConfigured=true;
inPreview=true;
camera=Camera.open();
Camera.Parameters parameters=camera.getParameters();
setCameraResolution();
camera.setParameters(parameters);
camera.setPreviewDisplay(previewHolder);
startPreview();
camera.takePicture(null, null, photoCallback); //THIS IS WHERE THE PHOTO IS BEING TAKEN
} catch (Exception e) {
L.m(e.toString());
}
}
And it errors out after that, specifically saying:
java.lang.RuntimeException: takePicture failed
Just to reiterate, it takes photos just fine when I click an icon/ button to do so, what I am trying to accomplish is for it to run that code WITHOUT the need for the button/ icon to be hit. I figure it is something very simple I am missing, I just can't seem to figure it out.
Call testing() at SurfaceHolder.Callback#onSurfaceCreated.
:-)

android surfaceview runnable proper way to delay?

Ok, so I can't quite seem to get this to work, I'm trying to find the proper way to add a delay to a surfaceview runnable. I originally started by using just Thread.sleep, but with so many entries on google saying that using a Thread.sleep for a runnable is bad, I've been trying to "properly" use a handler to achieve essentially the same goal. Here is my code so far that I've tested, notice the handler postdelayed notes and placement
public class demosf extends Activity {
OurView v;
int Measuredwidth;
int Measuredheight;
WindowManager w;
Bitmap whatever;
LinearLayout llMain;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Measuredwidth = 0;
Measuredheight = 0;
whatever = BitmapFactory
.decodeResource(getResources(), R.raw.dragarrow);
llMain = new LinearLayout(this);
setContentView(llMain);
v = new OurView(demosf.this);
llMain.post(new Runnable() {
#Override
public void run() {
Measuredwidth = llMain.getWidth();
Measuredheight = llMain.getHeight();
llMain.addView(v);
}
});
}
//the Runnable:
public class OurView extends SurfaceView implements Runnable {
Thread t = null;
SurfaceHolder holder;
boolean isItOK;
Handler handler = new Handler();
public OurView(Context context) {
super(context);
holder = getHolder();
}
#Override
public void run() {
//handler.postDelayed placed here freezes app
while (isItOK) {
if (!holder.getSurface().isValid()) {
continue;
}
Canvas c = holder.lockCanvas();
c.drawARGB(255, 0, 0, 0);
c.drawBitmap(
whatever,
((float) this.getWidth() - (float) whatever.getWidth()),
((float) this.getHeight() - (float) whatever
.getHeight()), null);
holder.unlockCanvasAndPost(c);
//handler.postDelayed placed here also freezes app
}
//this one isn't reached
handler.postDelayed(this, 100);
}
public void pause() {
isItOK = false;
while (true) {
try {
t.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
break;
}
t = null;
}
public void resume() {
isItOK = true;
t = new Thread(this);
t.start();
}
}
#Override
protected void onPause() {
super.onPause();
v.pause();
}
#Override
protected void onResume() {
super.onResume();
v.resume();
}
}
so do I just stick with using a Thread.sleep? Or how would I use a Handler here? I'm a newb so any help would be very appreciated =)
You are creating the Handler when instantiating OurView, which means the handler will use the current thread, in this case the UI thread - which is not what you want.
See Looper for how to properly create a Looper on a background Thread, which can then be used to create a background Handler.
There is a helper class called HandlerThread in the framework to do this boilerplate for you.

CameraView only works in emulator

I've written a litte Camera-Appliction after I have read this tutorial:
http://www.brighthub.com/mobile/google-android/articles/43414.aspx
In the emulator everything works fine (ok, there's no camera, but at least there are no errors ;) )
Then I tried to get it run on my HTC Wildfire S. But immediately after the start the app crashes.
Here's the code of my Activity, maybe somebody has an idea, how to solve the problem:
public class CameraView extends Activity implements SurfaceHolder.Callback {
android.hardware.Camera mCamera;
boolean mPreviewRunning = false;
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
getWindow().setFormat(PixelFormat.TRANSLUCENT);
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
setContentView(R.layout.camera_surface);
SurfaceView mSurfaceView = (SurfaceView)findViewById(R.id.surface_camera);
SurfaceHolder mSurfaceHolder = mSurfaceView.getHolder();
mSurfaceHolder.addCallback(this);
mSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
mCamera = android.hardware.Camera.open();
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
if(mPreviewRunning) {
mCamera.stopPreview();
}
android.hardware.Camera.Parameters params = mCamera.getParameters();
params.setPreviewSize(width, height);
mCamera.setParameters(params);
try {
mCamera.setPreviewDisplay(holder);
} catch (IOException ex) {
ex.printStackTrace();
}
mCamera.startPreview();
mPreviewRunning = true;
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
mCamera.stopPreview();
mPreviewRunning = false;
mCamera.release();
}
android.hardware.Camera.PictureCallback mPictureCallback = new android.hardware.Camera.PictureCallback() {
#Override
public void onPictureTaken(byte[] data, android.hardware.Camera camera) {
}
};
}
You are getting an exception because you are trying to make the camera use a width and height it doesn't support. You are asking it to use the width and height of the SurfaceView, which rarely matches one of the supported preview sizes. Instead, try using the following:
public class CameraView extends Activity implements SurfaceHolder.Callback {
android.hardware.Camera mCamera;
boolean mPreviewRunning = false;
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
getWindow().setFormat(PixelFormat.TRANSLUCENT);
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
setContentView(R.layout.camera_surface);
SurfaceView mSurfaceView = (SurfaceView)findViewById(R.id.surface_camera);
SurfaceHolder mSurfaceHolder = mSurfaceView.getHolder();
mSurfaceHolder.addCallback(this);
mSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
try {
mCamera.setPreviewDisplay(previewHolder);
}
catch (Throwable t) {
Log.e(TAG, "Exception in setPreviewDisplay()", t);
}
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
Camera.Parameters parameters=camera.getParameters();
Camera.Size size=getBestPreviewSize(width, height, parameters);
if (size!=null) {
parameters.setPreviewSize(size.width, size.height);
camera.setParameters(parameters);
camera.startPreview();
inPreview=true;
}
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
mCamera.stopPreview();
mPreviewRunning = false;
mCamera.release();
}
android.hardware.Camera.PictureCallback mPictureCallback = new android.hardware.Camera.PictureCallback() {
#Override
public void onPictureTaken(byte[] data, android.hardware.Camera camera) {
}
};
private Camera.Size getBestPreviewSize(int width, int height, Camera.Parameters parameters) {
Camera.Size result=null;
for (Camera.Size size : parameters.getSupportedPreviewSizes()) {
if (size.width<=width && size.height<=height) {
if (result==null) {
result=size;
}
else {
int resultArea=result.width*result.height;
int newArea=size.width*size.height;
if (newArea>resultArea) {
result=size;
}
}
}
}
return(result);
}
}
This code is all adapted from the one I wrote for my book. I changed some of your code, so some variable names and imports might need to be fixed, but it should work fine.
getBestPreviewSize() is the magic method here which calculates the optimum and best camera preview size to use.

Categories

Resources