My 'game' keeps crashing after I resume it. Basically, I launch the app and everything works. Then I press the home button and go back to my home screen. Still all the normal stuff. But THEN when I open the app back up, it just freezes and after 1 minute or so, I get a not responding message.
Here is my main activity:
package com.amzoft.android.starraider;
import android.app.Activity;
import android.content.Context;
import android.graphics.Canvas;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Bundle;
import android.util.Log;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.View.OnKeyListener;
import android.view.View.OnTouchListener;
import android.view.Window;
import android.view.WindowManager;
public class StarRaiderMain extends Activity implements OnTouchListener, OnKeyListener, SensorEventListener{
FastRenderView renderView;
SensorManager sensorManager;
Sensor accelerometer;
Thread mainGameThread;
Player player;
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
renderView = new FastRenderView(this);
renderView.setOnKeyListener(this);
renderView.setFocusableInTouchMode(true);
renderView.requestFocus();
setContentView(renderView);
sensorManager = (SensorManager)getSystemService(Context.SENSOR_SERVICE);
accelerometer = sensorManager.getSensorList(Sensor.TYPE_ACCELEROMETER).get(0);
mainGameThread = new Thread(new mainGameThread());
player = new Player(this);
}
#Override
protected void onResume()
{
super.onResume();
renderView.resume();
renderView.requestFocus();
sensorManager.registerListener(this, accelerometer, SensorManager.SENSOR_DELAY_GAME);
}
#Override
protected void onPause()
{
super.onPause();
renderView.pause();
sensorManager.unregisterListener(this);
}
#Override
public void onAccuracyChanged(Sensor sensor, int accuracy)
{
}
#Override
public void onSensorChanged(SensorEvent event)
{
player.onSensorChanged(event);
}
#Override
public boolean onKey(View v, int keyCode, KeyEvent event)
{
player.onKey(v, keyCode, event);
return true;
}
#Override
public boolean onTouch(View v, MotionEvent event)
{
return true;
}
class FastRenderView extends SurfaceView implements Runnable
{
Thread renderThread = null;
SurfaceHolder holder;
volatile boolean running = false;
public FastRenderView(Context context)
{
super(context);
holder = getHolder();
}
public void resume()
{
running = true;
renderThread = new Thread(this);
renderThread.start();
}
public void pause()
{
running = false;
while(true)
{
try{
renderThread.join();
}catch(InterruptedException e){
Log.d("StarRaider", e.getMessage());
}
}
}
#Override
public void run()
{
while(running)
{
if(!holder.getSurface().isValid())
continue;
Canvas canvas = holder.lockCanvas();
onDraw(canvas);
holder.unlockCanvasAndPost(canvas);
}
}
public void onDraw(Canvas canvas)
{
canvas.drawRGB(255, 255, 255);
player.onDraw(canvas);
}
}
class mainGameThread extends Thread
{
mainGameThread()
{
super("mainGameThread");
start();
}
public void run()
{
try{
player.onUpdate();
}catch(Exception e){
}
}
}
}
Any help would be greatly appreciated.
Here is my logcat output: http://pastebin.com/3b09YAkP
I have a main game thread, because I read that if the render thread gets stuck for 2 seconds, it crashes.
It looks like it might be one of two things.
You should probably be explicitly pausing your thread in onPause(). That might cause application deadlock if it tries to resume without having been paused.
You should also take a look at the Google I/O presentation on Replica Island. It's about an hour long. Take note of the part where he talks about garbage collection. This might be what's happening and causing your app to crash because of an ANR error.
I hope this helps!
May be related to this bug http://code.google.com/p/android/issues/detail?id=2566
Related
MainActivity.java
import android.content.Intent;
import android.os.Bundle;
import android.support.wearable.activity.WearableActivity;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;
public class MainActivity extends WearableActivity {
private TextView mTextView;
private static MainActivity instance;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mTextView = (TextView) findViewById(R.id.text);
// Enables Always-on
setAmbientEnabled();
final TextView text = findViewById(R.id.text);
text.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (text.getText().toString().equals("Started")) {
text.setText("Stoped");
stopService(new Intent(MainActivity.this,service.class));
} else {
text.setText("Started");
startService(new Intent(MainActivity.this,service.class));
}
}
});
}
public static MainActivity getInstance() {
return instance;
}
public void showToast(String toastMsg){
Toast.makeText(MainActivity.this, toastMsg, Toast.LENGTH_SHORT).show();
}
}
Service.java
import android.app.Service;
import android.content.Intent;
import android.os.Handler;
import android.os.IBinder;
import android.util.Log;
import android.widget.Toast;
import androidx.annotation.MainThread;
import java.util.Random;
import java.util.Timer;
import java.util.TimerTask;
public class service extends Service {
private boolean started = false;
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.i("serviceTest", "Service started by user.");
start();
return START_STICKY;
}
#Override
public void onDestroy() {
//Toast.makeText(this, "Service destroyed by user.", Toast.LENGTH_LONG).show();
Log.i("serviceTest", "Service destroyed by user.");
stop();
super.onDestroy();
}
private Timer timer;
private TimerTask timerTask = new TimerTask() {
#Override
public void run() {
if(started) {
start();
}
Log.i("serviceTest", "ServiceCalled!");
}
};
public void start() {
if(timer != null) {
return;
}
timer = new Timer();
timer.scheduleAtFixedRate(timerTask, 0, 10000);
}
public void stop() {
timer.cancel();
timer = null;
}
}
The code runs okay for about 13 or 14 times (i.e. the timer keeps on running for about 13 or 14 times) but suddenly the service stops and onDestroy is called.
Also, during debugging, I have noticed one strange condition: If I delete/comment the onDestroy() method form the code then the service runs always. It never closes on its own. (it only closes upon user input, which is fine)
Please suggest a solution so that the services do not get killed/ destroyed. Or if the OS/ System kills it, then the service starts again on its own.
Thnx
You will have to turn that background service into a foreground service, because of the limitations called Background Execution Limits that started from android Oreo.
Please check out this link for more better understanding: https://developer.android.com/about/versions/oreo/background
I made 2D game and it worked just fine. I decided to create a simple "Start Screen" that ought to show high score and "Start" button that should start the game.
I thought I could use just a regular intent to go from one activity to another, but it doesn't work. App simply crashes after I click "Start" button.
I'm using Scene Manager so not all code is written in Game Panel.
Here's my MainActivity
package com.example.korisnik_pc.a2dgame;
import android.app.Activity;
import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.DisplayMetrics;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.widget.Button;
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
Button button;
super.onCreate(savedInstanceState);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); // MAKE IT FULLSCREEN
this.requestWindowFeature(Window.FEATURE_NO_TITLE); // REMOVES TOOLBAR
// setting the screen dimensions
DisplayMetrics dm = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(dm);
Constants.SCREEN_HEIGHT = dm.heightPixels;
Constants.SCREEN_WIDTH = dm.widthPixels;
setContentView(R.layout.activity_main);
button = (Button) findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
Intent intent = new Intent(MainActivity.this, GamePanel.class);
startActivity(intent);
}
});
}
Game Panel
public class GamePanel extends SurfaceView implements SurfaceHolder.Callback {
private MainThread thread;
private SceneManager sceneManager;
public GamePanel(Context context) {
super(context);
getHolder().addCallback(this);
thread = new MainThread(getHolder(), this);
sceneManager = new SceneManager();
setFocusable(true);
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
thread = new MainThread(getHolder(), this);
thread.setRunning(true);
thread.start();
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
boolean retry = true;
while (true) {
try {
thread.setRunning(false);
thread.join();
} catch (Exception e) {
e.printStackTrace();
}
retry = false;
}
}
#Override
public boolean onTouchEvent(MotionEvent event) {
sceneManager.receiveTouch(event);
return true;
}
public void update() {
sceneManager.update();
}
public void draw(Canvas canvas) {
super.draw(canvas);
sceneManager.draw(canvas);
}
}
I created a SurfaceView (you can see it in the following) and started in from my Main Activity. I overwrote the onTouchEvent method in the SurfaceView and the problem is that the data I want to have logged with Log.d isn't logged, I don't get any Message...
Does anyone have an idea how I can fix this?
My SurfaceView:
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.util.Log;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
public class MainGamePanel extends SurfaceView implements SurfaceHolder.Callback {
private float top;
private float left;
private float bottom;
private float right;
private MainThread thread;
MainGamePanel(Context context) {
super(context);
getHolder().addCallback(this);
thread = new MainThread(getHolder(), this);
setFocusable(true);
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
setWillNotDraw(false);
thread.setRunningMode(MainThread.RUNNING);
thread.start();
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
boolean retry = true;
while (retry) {
try {
thread.join();
retry = false;
} catch (Exception e) {
}
}
}
#Override
public boolean onTouchEvent(MotionEvent event) {
float x = event.getX();
float y = event.getY();
right = x + 30;
left = x - 30;
top = y - 30;
bottom = y + 30;
Log.d("tag", x + " " + y);
return true;
}
#Override
protected void onDraw(Canvas canvas) {
}
}
My Main Activity:
import android.app.Activity;
import android.os.Bundle;
import android.os.PersistableBundle;
public class MainActivity extends Activity {
#Override
public void onCreate(Bundle savedInstanceState, PersistableBundle persistentState) {
super.onCreate(savedInstanceState, persistentState);
setContentView(new MainGamePanel(getApplicationContext()));
}
}
Try changing "getApplicationContext()" to "this" in following part of code:
setContentView(new MainGamePanel(getApplicationContext()));
to
setContentView(new MainGamePanel(this));
I am using the following code with IOIO to act as a motion detector, the problem is the IOIO is disconnected whenever my phone screen goes off! I do not want the screen to stay on all the time to keep the IOIO connected!
any solution please?
package com.LookHin.ioio_pir_motion_sensor;
import ioio.lib.api.AnalogInput;
import ioio.lib.api.DigitalOutput;
import ioio.lib.api.exception.ConnectionLostException;
import ioio.lib.util.BaseIOIOLooper;
import ioio.lib.util.IOIOLooper;
import ioio.lib.util.android.IOIOActivity;
import android.content.Intent;
import android.graphics.Color;
import android.media.Ringtone;
import android.media.RingtoneManager;
import android.net.Uri;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.TextView;
import android.widget.Toast;
import android.widget.ToggleButton;
public class MainActivity extends IOIOActivity {
private ToggleButton toggleButton1;
private TextView textView1;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView1 = (TextView) findViewById(R.id.textView1);
toggleButton1 = (ToggleButton) findViewById(R.id.toggleButton1);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item)
{
switch (item.getItemId())
{
case R.id.action_about:
//Toast.makeText(getApplicationContext(), "Show About", Toast.LENGTH_SHORT).show();
Intent about = new Intent(this, AboutActivity.class);
startActivity(about);
return true;
default:
return super.onOptionsItemSelected(item);
}
}
class Looper extends BaseIOIOLooper {
private DigitalOutput digital_led0;
private AnalogInput deigital_input;
int i = 0;
private float InputStatus;
#Override
protected void setup() throws ConnectionLostException {
digital_led0 = ioio_.openDigitalOutput(0,true);
deigital_input = ioio_.openAnalogInput(45);
runOnUiThread(new Runnable() {
public void run() {
Toast.makeText(getApplicationContext(), "IOIO Connect", Toast.LENGTH_SHORT).show();
}
});
}
#Override
public void loop() throws ConnectionLostException {
try{
digital_led0.write(!toggleButton1.isChecked());
InputStatus = deigital_input.getVoltage();
runOnUiThread(new Runnable() {
#Override
public void run() {
textView1.setText(String.format("%.02f",InputStatus)+" v.");
if(InputStatus >= 3.0){
textView1.setBackgroundColor(Color.RED);
if (i == 0){
Uri notification = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
Ringtone r = RingtoneManager.getRingtone(getApplicationContext(), notification);
r.play();
i = 1;
};
}else{
textView1.setBackgroundColor(Color.TRANSPARENT);
i = 0;
}
}
});
Thread.sleep(100);
}catch(InterruptedException e){
e.printStackTrace();
}
}
}
#Override
protected IOIOLooper createIOIOLooper() {
return new Looper();
}
}
Option 1) Lock the screen so it always stays awake
public void onCreate(Bundle savedInstanceState) {
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
Option 2) Fix your response to onPause().
When the screen goes off the onPause() method is called and you should handle it as otherwise your activity will be closed.
#Override
protected void onPause() {
// Your code
super.onPause();
}
The onPause() normally calls the ioio.disconnect() so this should be overrode.
IOIOService let´s you run your code on the background even if application goes to the background.
I am an amateur programmer, and have been playing around with android development. I am currently trying my hand at generating a fractal heightmap. In order to test if teh map is generating properly I need to be able to draw the map to the screen. This is where I've been running into trouble.
Here's the code for my MainActivity, DrawMap class (where my onDraw() is), and my CanvasThread() class.
Main Activity:
package com.psstudios.HMG;
import android.app.*;
import android.os.*;
import android.view.*;
import android.widget.*;
import android.view.View.OnClickListener;
import android.util.Log;
public class MainActivity extends Activity
{
/** Called when the activity is first created. */
Button Startgen = null;
Boolean run=true;
private void log(String text) {
Log.d("heightmap",text);
AppendLog app = new AppendLog(text);
}
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.main);
Startgen = (Button) findViewById(R.id.startgen);
log("loop");
Startgen.setOnClickListener(new View.OnClickListener(){
public void onClick(View v){
log("Starting world generation");
WorldGen world=new WorldGen(200,200);
log("World generation complete, drawing heightmap");
setContentView(new DrawMap(MainActivity.this, world));
log("Went too far");
}
});
run=false;
}
}
DrawMap:
package com.psstudios.HMG;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Bitmap;
import android.graphics.Bitmap.*;
import android.graphics.Paint;
import android.graphics.Color;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.util.Log;
import android.util.*;
public class DrawMap extends SurfaceView implements SurfaceHolder.Callback
{
int drawtype=1; //variable for which type of map to draw
Bitmap drawbitmap=null;
CanvasThread canvasThread=null;
Boolean run= true;
int Worldx=200;
int Worldy=200;
WorldGen _world=null;
public void log(String text){
Log.d("Heightmap", text);
AppendLog app = new AppendLog(text);
}
public void init(){
log("init();");
canvasThread=new CanvasThread(getHolder(), this);
setFocusable(true);
log("Post-CanvasThread");
}
public DrawMap(Context context){
super(context);
log("DrawMap(Context context)");
getHolder().addCallback(this);
init();
}
public DrawMap(Context context, AttributeSet attrs) {
super(context, attrs);
log("DrawMap(Context context, AttributeSet attrs)");
getHolder().addCallback(this);
init();
}
public DrawMap(Context context,WorldGen world){
super(context);
log("DrawMap(Context context, WorldGen world)");
getHolder().addCallback(this);
_world=world;
init();
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format,int width, int height){
log("surfaceChanged()");
}
#Override
public void surfaceCreated(SurfaceHolder holder){
log("Surface Created");
canvasThread.setRunning(true);
canvasThread.run();
}
#Override
public void surfaceDestroyed(SurfaceHolder holder){
log("Surface Destroyed");
Boolean retry = true;
canvasThread.setRunning(false);
while(retry){
try {
canvasThread.join();
retry=false;
} catch (InterruptedException e) {
//we will try again and again
}
}
}
#Override
public void onDraw(Canvas canvas){
log("onDraw()");
Paint paint = new Paint();
Paint paint2 = new Paint();
//canvas.drawColor(Color.BLACK);
paint.setColor(Color.WHITE);
paint.setStrokeWidth(10);
paint2.setColor(Color.BLUE);
for(int x=0; x<Worldx-1; x++){
for(int y=0; y<Worldy-1; y++){
//log(x + " : " + y);
canvas.drawPoint(x+20, y+20, paint);
canvas.drawPoint(x+220, y+220, paint2);
}
}
}
}
CanvasThread:
package com.psstudios.HMG;
import android.graphics.Canvas;
import android.view.*;
import android.util.Log;
public class CanvasThread extends Thread
{
private SurfaceHolder _surfaceHolder;
private DrawMap _drawMap;
private Boolean _run = false;
private void log(String text){
Log.d("HeightmapGen",text);
AppendLog app = new AppendLog(text);
}
public CanvasThread(SurfaceHolder surfaceHolder, DrawMap drawMap){
_surfaceHolder=surfaceHolder;
_drawMap=drawMap;
log("CanvasThread()");
}
public void setRunning(Boolean run){
log("setRunning()");
_run=run;
}
#Override
public void run() {
log("run()");
Canvas c;
while(_run){
c=null;
try{
c=_surfaceHolder.lockCanvas(null);
synchronized (_surfaceHolder) {
_drawMap.onDraw(c);
}
} finally {
if(c != null){
_surfaceHolder.unlockCanvasAndPost(c);
}
}
}
}
}
The program makes it to the onDraw(); function, and runs through the for loop, but nothing is showing up on the screen. I imagine I'm missing something pretty stupid, but I cannot seem to figure out what's wrong.
Thanks in advance for any help you guys can give me.