When I run my code below everything works fine. When I want to go back to the previous activity (using the emulator) I get a black screen and then the app shuts down. I also get a black screen when I exit the application and try to resume it.
The code:
package com.example.bono.as3;
import android.app.Activity;
import android.content.Context;
import android.content.res.AssetManager;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.os.Bundle;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import java.io.IOException;
import java.io.InputStream;
public class Main extends Activity {
DrawView drawView;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
drawView = new DrawView(this);
setContentView(drawView);
}
#Override public void onResume(){
super.onResume();
drawView.resume();
}
#Override public void onPause(){
super.onPause();
drawView.pause();
}
public class DrawView extends SurfaceView implements Runnable{
Thread gameloop = new Thread();
SurfaceHolder surface;
volatile boolean running = false;
AssetManager assets = null;
BitmapFactory.Options options = null;
Bitmap incect[];
int frame = 0;
public DrawView(Context context){
super(context);
surface = getHolder();
assets = context.getAssets();
options = new BitmapFactory.Options();
options.inPreferredConfig = Bitmap.Config.ARGB_8888;
incect = new Bitmap[2];
try {
for (int n = 0; n < incect.length; n++){
String filename = "incect"+Integer.toString(n+1)+".png";
InputStream istream = assets.open(filename);
incect[n] = BitmapFactory.decodeStream(istream,null,options);
istream.close();
}
} catch (IOException e){
e.printStackTrace();
}
}
public void resume(){
running = true;
gameloop = new Thread(this);
gameloop.start();
}
public void pause(){
running = false;
while (true){
try {
gameloop.join();
}
catch (InterruptedException e){}
}
}
#Override public void run (){
while (running){
if (!surface.getSurface().isValid())
continue;
Canvas canvas = surface.lockCanvas();
canvas.drawColor(Color.rgb(85, 107, 47));
canvas.drawBitmap(incect[frame], 0, 0, null);
surface.unlockCanvasAndPost(canvas);
frame++;
if (frame > 1) frame = 0;
try {
Thread.sleep(500);
} catch (InterruptedException e){
e.printStackTrace();
}
}
}
}
}
I dont get any error message in the log, what I do get is about 13 messages saying "suspending all threads took: X ms" so it has something to do with my gameloop Thread I think. Unfortunately I don't see what the problem is in my code...
If you need a context, use getApplicationContext() or Activity.this. (seems less buggy with my code)
While going back to a previously used activity, onCreate() is not called, only onResume(), so it might help if you move the following lines to there.
drawView = new DrawView(this);
setContentView(drawView);
Why use inner class at all? Activity is a class already. If you want to use the code multiple times, make it a class on its own.
This is what i use to navigate back. Maybe this is usefull for you 2!
Button backpressed = (Button) findViewById(R.id.btBack);
backpressed.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
onBackPressed();
}
});
The onBackPressed() is just a method that you can call if you want to return to the last page.
What it looks like for me:
Related
I am really new to Android Studio, and am trying to get up to speed. I got some code from the web and I have an errors I know it is because I am referencing a package that is not in my project but how could I resolve this.
The line that has the error is:
import com.androidmkab.randomsplash.MainActivity;
and this is the full code.
package org.quaestio.kotlinconvertedwebview;
import android.os.Bundle;
import android.app.Activity;
import android.content.Intent;
import android.widget.ImageView;
import com.androidmkab.randomsplash.MainActivity;
import java.util.Random;
public class Splashscreen extends Activity {
Thread splashTread;
ImageView imageView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_splashscreen);
imageView = (ImageView)findViewById(R.id.imageView2);
imageView.setScaleType(ImageView.ScaleType.FIT_XY);
int[] ids = new int[]{R.drawable.s_img,R.drawable.s_image_black, R.drawable.s_image_black2};
Random randomGenerator = new Random();
int r= randomGenerator.nextInt(ids.length);
this.imageView.setImageDrawable(getResources().getDrawable(ids[r]));
splashTread = new Thread() {
#Override
public void run() {
try {
int waited = 0;
// Splash screen pause time
while (waited < 3500) {
sleep(100);
waited += 100;
}
Intent intent = new Intent(Splashscreen.this,
MainActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
startActivity(intent);
Splashscreen.this.finish();
} catch (InterruptedException e) {
// do nothing
} finally {
Splashscreen.this.finish();
}
}
};
splashTread.start();
}
}
So import com.androidmkab.randomsplash.MainActivity means where the MainActivity is located, you need to replace that package with your own. To do this copy your package name(in the top of your activity) and add the activity you want to import, in this case MainActivity.java: import org.quaestio.kotlinconvertedwebview.MainActivity;
Hope it was helpful.
I am implementing a simple render view class for Android extending SurfaceView. My main activity class includes an infinite while loop for other operations.
However, the app shows a black screen when main activity is in the infinite loop. As far as I know, main activity and surface view classes have their own separate threads, so surface view class should keep rendering even when main activity class is busy. The app works just fine when I prevent infinite loop by setting 'running' boolean variable false in the code.
What might be the reason of that surface view class stops rendering when my main activity is in an infinite loop?
My main activity and surface view classes are as follows:
import android.app.Activity;
import android.os.Bundle;
import android.view.Window;
import android.view.WindowManager;
public class MainActivity extends Activity{
RenderSurfaceView renderView;
public boolean running = true;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate ( savedInstanceState );
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
renderView = new RenderSurfaceView(this);
setContentView(renderView);
loop();
}
public void loop(){
running = true;
while(running){
}
}
protected void onResume() {
super.onResume();
renderView.resume();
}
protected void onPause() {
super.onPause();
renderView.pause();
}
}
This my render class that extends SurfaceView:
import java.util.Random;
import android.content.Context;
import android.graphics.Canvas;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
public class RenderSurfaceView extends SurfaceView implements Runnable{
Thread renderThread = null;
SurfaceHolder holder;
volatile boolean running = false;
Random r = new Random();
public RenderSurfaceView(Context context) {
super(context);
holder = getHolder();
}
public void resume() {
running = true;
renderThread = new Thread(this);
renderThread.start();
}
public void run() {
while(running) {
if(!holder.getSurface().isValid())
continue;
render();
}
}
private void render(){
Canvas canvas = holder.lockCanvas();
canvas.drawRGB(r.nextInt(255), r.nextInt(255), r.nextInt(255));
holder.unlockCanvasAndPost(canvas);
}
public void pause() {
running = false;
while(true) {
try {
renderThread.join();
} catch (InterruptedException e) {
// retry
}
}
}
}
This
renderView = new RenderSurfaceView(this);
setContentView(renderView);
does not show the view immediately. Instead it has to go through a layout traversal first, which doesn't happen immediately but asynchronously to the Activity lifecycle methods, and it happens on the main thread. So running an infinite loop at the end of onCreate() prevents the layout traversal of the view hierarchy, which means your SurfaceView will never be shown.
In theory you could experiment with starting your infinite loop delayed using a Handler, for experimental purposes maybe. In general infinite loops on the main thread are a super bad idea and I can't see a reason why you would want to do this, apart from experiments maybe.
My self-answer to this question Modifying views in AsyncTask doInBackground() does not (always) throw exception has a bit more detail on what's going on behind the scenes. The question is not directly related to what you're asking here, but the background is the same I believe.
This is a simple Android game built on one Activity that is extended in my AndroidGame class. Most of my other classes extend my 'Screen' class to make things like the Menu, In-Game screen, Game Over screen, etc. I would like to create an instance of CountDownTimer, call it once the user presses play and the game is confirmed to be running (in my GameScreen class), and then return the user to the main menu after 30 seconds are up.
My main Activity looks like this. I've included the whole class but surrounded the important parts with comments:
package com.game.framework.implementation;
import android.app.Activity;
import android.content.Context;
import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.os.Bundle;
import android.os.CountDownTimer;
import android.os.PowerManager;
import android.os.PowerManager.WakeLock;
import android.view.Window;
import android.view.WindowManager;
import com.game.framework.Audio;
import com.game.framework.FileIO;
import com.game.framework.Game;
import com.game.framework.Graphics;
import com.game.framework.Input;
import com.game.framework.Screen;
public abstract class AndroidGame extends Activity implements Game {
AndroidFastRenderView renderView;
Graphics graphics;
Audio audio;
Input input;
FileIO fileIO;
Screen screen;
WakeLock wakeLock;
//////// Timer variables ////////
public static boolean timerFinished = false;
public static MyCount counter;
////////////////////////////////////////
#SuppressWarnings("deprecation")
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
boolean isPortrait = getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT;
int frameBufferWidth = isPortrait ? 480: 800;
int frameBufferHeight = isPortrait ? 800: 480;
Bitmap frameBuffer = Bitmap.createBitmap(frameBufferWidth, frameBufferHeight, Config.RGB_565);
float scaleX = (float) frameBufferWidth / getWindowManager().getDefaultDisplay().getWidth();
float scaleY = (float) frameBufferHeight / getWindowManager().getDefaultDisplay().getHeight();
renderView = new AndroidFastRenderView(this, frameBuffer);
graphics = new AndroidGraphics(getAssets(), frameBuffer);
fileIO = new AndroidFileIO(this);
audio = new AndroidAudio(this);
input = new AndroidInput(this, renderView, scaleX, scaleY);
screen = getInitScreen();
setContentView(renderView);
PowerManager powerManager = (PowerManager) getSystemService(Context.POWER_SERVICE);
wakeLock = powerManager.newWakeLock(PowerManager.FULL_WAKE_LOCK, "MyGame");
//////// Instantiate counter ////////
counter = new MyCount(30000,1000);
//////////////////////////////////
}
#Override
public void onResume() {
super.onResume();
wakeLock.acquire();
screen.resume();
renderView.resume();
}
#Override
public void onPause() {
super.onPause();
wakeLock.release();
renderView.pause();
screen.pause();
if (isFinishing())
screen.dispose();
}
#Override
public Input getInput() {
return input;
}
#Override
public FileIO getFileIO() {
return fileIO;
}
#Override
public Graphics getGraphics() {
return graphics;
}
#Override
public Audio getAudio() {
return audio;
}
#Override
public void setScreen(Screen screen) {
if (screen == null)
throw new IllegalArgumentException("Screen must not be null");
this.screen.pause();
this.screen.dispose();
screen.resume();
screen.update(0);
this.screen = screen;
}
#Override
public void onBackPressed() {
getCurrentScreen().backButton();
}
public Screen getCurrentScreen() {
return screen;
}
//////// The Timer Class ////////////////////////////////
public class MyCount extends CountDownTimer{
public MyCount(long millisInFuture, long countDownInterval) {
super(millisInFuture, countDownInterval);
}
#Override
public void onFinish() {
timerFinished = true;
}
#Override
public void onTick(long millisUntilFinished) {
}
}
////////////////////////////////////////////////////////
}
Now once the timer runs out, as you see, I change the boolean timerFinished to true. In my GameScreen class I have a method called updateRunning that deals with user interaction once the game is live and running (play has been pressed).
private void updateRunning(List<TouchEvent> touchEvents, float deltaTime) {
///// Start the timer and go to menu if time is up /////
AndroidGame.counter.start();
if (AndroidGame.timerFinished == true) {
goToMenu();
}
///////////////////////////////////////////////////////
int len = touchEvents.size();
for (int i = 0; i < len; i++) {
TouchEvent event = (TouchEvent) touchEvents.get(i);
if (event.type == TouchEvent.TOUCH_DOWN) {
// Do lots of stuff based on which buttons the user presses
I am not getting an errors and the game is running fine, but it is not returning to the main menu after the 30 seconds are up. I have no idea why and would really appreciate any thoughts on the matter. Thanks!
EDIT 1: This is my goToMenu() method:
private void goToMenu() {
game.setScreen(new MainMenuScreen(game));
}
I cannot call this within AndroidGame because it references game, and making that static will cause a lot of issues.
EDIT 2:
Here's a TLDR version of what I'm trying to do - for clarity.
I have class1, where I extend Activity, and class2 where I deal with user input and paint items to the screen.
In my Android game, I want a function that will count down from 30 seconds. I want to pass the time remaining into a global variable so I can paint it in class2. Once the Timer reaches 0, I would like to run goToMenu(), which also has to exist in class2.
As of now, I have the CountDownTimer subclass in class1 and I instantiate it there. I have a global boolean that I set to True within the timer's onFinish() method. If the boolean is True, then I run goToMenu() in class2 but for some reason it does not work.
This code is too add a timer on the code.. but i am having a problem with my code when it comes to the timer code...
How will i improve the code for the timer inside the for loop of my code..
Hopefully you understand the my code.. and have improved my code.. Thanks!!!!
package com.thesis.americansignlanguage;
import java.io.IOException;
import java.io.InputStream;
import java.util.Timer;
import java.util.TimerTask;
import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.widget.ImageView;
import android.widget.TextView;
public class AlphabetCompareClass extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.alphabetcompare);
final String get;
Bundle gotWord = getIntent().getExtras();
get = gotWord.getString("key");
TextView Word = (TextView)findViewById(R.id.textView1);
final ImageView img = (ImageView)findViewById(R.id.image_alpha) ;
Word.setText(get);
for(int x = 0; x > gotWord.getString("key").length(); x++) {
final InputStream is;
Timer timer = new Timer();
TimerTask timertask = new TimerTask() {
#Override
public void run() {
try {
is = getResources().getAssets().open(get + ".png");
Bitmap bitmap = BitmapFactory.decodeStream(is);
img.setImageBitmap(bitmap);
} catch (IOException e) {
return;
}
}
};
}
};
}
Two problem found in current code:
First : Not using timer instance to schedule timerTask. do it as:
timer.schedule(timertask, 500, 3000);
Second : Updating UI from non- ui thread inside run method of TimerTask
Use runOnUiThread or Handler for updating Ui from run method of TimerTask
TimerTask runs on a different thread. Ui can be updated only from ui thread.
This img.setImageBitmap(bitmap); should be executed on the ui thread
Use runOnUiThread. You can also use a Handler. Also i do not understand the need for the for loop.
runOnUiThread(new Runnable() {
#Override
public void run() {
img.setImageBitmap(bitmap);
}
});
I created an Android app which draws a small image to the screen and exits if you tap in the bottom 50px of the screen. When I tap there, it exits fine, however, when I press the back (or home) button to exit the application, it exits, but then says, "Unfortunately, Game Development has stopped." I also checked LogCat, and it showed that a Java NullPointerException occurred each time it stopped working. The output from LogCat was:
10-30 01:13:28.280: E/AndroidRuntime(15294): FATAL EXCEPTION: Thread-1718
10-30 01:13:28.280: E/AndroidRuntime(15294): java.lang.NullPointerException
10-30 01:13:28.280: E/AndroidRuntime(15294): at tricrose.gamedev.GameView.onDraw(GameView.java:56)
10-30 01:13:28.280: E/AndroidRuntime(15294): at tricrose.gamedev.GameThread.run(GameThread.java:30)
I have three Java classes: Game.java (the Activity), GameView.java (the SurfaceView), and GameThread.java (the main Thread).
The code is as follows:
Game.java:
package tricrose.gamedev;
import android.os.Bundle;
import android.app.Activity;
import android.util.Log;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.Window;
import android.view.WindowManager;
public class Game extends Activity {
public static final String TAG = Game.class.getSimpleName();
#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 GameView(this));
Log.d(TAG, "View added");
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.activity_game, menu);
return true;
}
}
GameView.java:
package tricrose.gamedev;
import android.app.Activity;
import android.content.Context;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
public class GameView extends SurfaceView implements SurfaceHolder.Callback {
public static final String TAG = GameView.class.getSimpleName();
private GameThread thread;
public GameView(Context context) {
super(context);
getHolder().addCallback(this);
thread = new GameThread(getHolder(), this);
setFocusable(true);
}
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
public void surfaceCreated(SurfaceHolder holder) {
thread.setRunning(true);
thread.start();
}
public void surfaceDestroyed(SurfaceHolder holder) {
boolean retry = true;
while (retry) {
try {
thread.join();
retry = false;
} catch (Exception e) {}
}
}
public boolean onTouchEvent(MotionEvent e) {
if (e.getAction() == MotionEvent.ACTION_DOWN) {
if (e.getY() > getHeight() - 60) {
thread.setRunning(false);
((Activity)getContext()).finish();
}
}
return super.onTouchEvent(e);
}
protected void onDraw(Canvas canvas) {
canvas.drawColor(Color.BLACK);
canvas.drawBitmap(BitmapFactory.decodeResource(getResources(), R.drawable.droid_1), 10, 10, null);
}
}
GameThread.java:
package tricrose.gamedev;
import android.graphics.Canvas;
import android.view.SurfaceHolder;
public class GameThread extends Thread {
public static final String TAG = GameThread.class.getSimpleName();
private boolean running;
private SurfaceHolder surfaceHolder;
private GameView gameView;
public GameThread(SurfaceHolder surfaceHolder, GameView gameView) {
super();
this.surfaceHolder = surfaceHolder;
this.gameView = gameView;
}
public void setRunning(boolean running) {
this.running = running;
}
public void run() {
Canvas canvas;
while (running) {
canvas = null;
try {
canvas = this.surfaceHolder.lockCanvas();
synchronized (surfaceHolder) {
this.gameView.onDraw(canvas);
}
} finally {
if (canvas != null) {
surfaceHolder.unlockCanvasAndPost(canvas);
}
}
}
}
}
I've searched all over the internet for a solution, and I cannot find one which has actually worked, so any help is hugely appreciated.
I finally managed to find the solution! It turned out that I should have checked if the canvas was null before calling onDraw, and if it was null, then quit the application by finishing the activity. I found the solution on JavaCodeGeeks.com, where I was looking at an Android tutorial. Thanks everyone for all your answers!
why you have doing drawing from two places from onDraw and GameThread run method. I think you need to remove onDraw do every drawing from GameThread rlun method only.
This is just a guess, but your app might still be drawing while the app is trying to exit. In you onDraw method you call this line of code (which is probably your cause of problem):
canvas.drawBitmap(BitmapFactory.decodeResource(getResources(), R.drawable.droid_1), 10, 10, null);
In that case you might not have resuorces available anymore ;)
You can try to:
1. Put a class private bitmap variable into your GameView Class:
private Bitmap mBitmap;
2. Load the bitmap in your GameView constructor:
mBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.droid_1);
3. Draw using the (already loaded) bitmap:
canvas.drawBitmap(mBitmap, 10, 10, null);
Hope that helps!