Game doesn't Quit properly - java

I have an app that so far consists of two Activities:
The Main Menu Activity.
The Game Activity
The Main Menu Activity contains a button that starts the Game Activity with the following code:
public void onClick(View clickedButton)
{
switch(clickedButton.getId())
{
case R.id.buttonPlay:
Intent i = new Intent("apple.banana.BouncingBallActivity");
startActivity(i);
break;
}
When the user is done with the Game Activity, he presses the back button. This calls the onPause() method first, which pauses the animation thread of the game. It then calls the onStop() which calls finish() on the activity altogether. The user is returned to the Main Menu activity. The code is outlined below:
public class BouncingBallActivity extends Activity{
private BouncingBallView bouncingBallView;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
bouncingBallView = new BouncingBallView(this);
bouncingBallView.resume();
setContentView(bouncingBallView);
}
#Override
protected void onPause()
{
super.onPause();
bouncingBallView.pause();
}
#Override
protected void onResume()
{
super.onResume();
bouncingBallView.resume();
}
#Override
protected void onStop()
{
super.onStop();
this.finish();
}
}
The problem is that this only works if I launch the application from Eclipse.
When I click on the app icon, the game starts from the Game Activity. The main menu activity does not appear.
I am not clear about why this happens. It could be something to do with the manifest. I've pasted the relevant portions below:
<application
android:icon="#drawable/ic_launcher"
android:label="#string/app_name" >
<activity
android:name=".BouncingBallActivity"
android:label="#string/app_name"
android:screenOrientation="landscape" >
<intent-filter>
<action android:name="apple.banana.BouncingBallActivity" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
<activity
android:name=".MainMenu"
android:label="#string/app_name"
android:screenOrientation="portrait" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
I'd really appreciate any help with this. Thanks.

The call to finish() does not belong in your onStop() method. If you want to end the game when the user presses back, place it in your onPause(). The reason the app picks up from the game activity on subsequent launches (through the Android launcher interface) is it never left there.
If you only want to end the game when the user presses the Back key, and not from other pauses, then you'll need to catch incoming keys and finish() if the key is Back.

You can do this, when you press your back button.
#Override
public boolean onKeyDown(int keyCode, KeyEvent event)
{
if ((keyCode == KeyEvent.KEYCODE_BACK))
{
this.finish();
}
return super.onKeyDown(keyCode, event);
}
or
#Override
public void onBackPressed() {
this.finish();
}

Related

Launch-Activity onCreate() called again when start another Activity

My Android App launches with a simple Activity with shows a ProgressBar. Some data is initialized and then the MainActivity is loaded for the user to interact with.
The Problem:
When startActivity() in showMainActivity() is called, the onCreate() - Method in the InitActivity is called again. This causes the data to be initialized again and the MainActivity to be started twice. Strangely this does not end in an endless loop but happens only once.
Does anyone have an idea why startActivity() causes onCreate() of InitActivity to be called again?
Code:
public class InitActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
//GETS CALLED AGAIN AFTER showMainActivity()
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_init);
DatabaseInitTask databaseInitTask = new DatabaseInitTask(getApplicationContext(), new DatabaseInitTask.DatabaseInitCallback() {
#Override
public void onInitCompleted() {
showMainActivity();
});
}
});
databaseInitTask.execute("");
}
private void showMainActivity() {
Intent intent = new Intent(getApplicationContext(), MainActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
startActivity(intent);
}
}
Manifest:
<activity
android:name=".Ui.MainActivity"
android:label="#string/app_name"
android:windowSoftInputMode="adjustPan">
<intent-filter>
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.BROWSABLE"/>
<data
android:host="mydomain.com"
android:scheme="https"/>
</intent-filter>
</activity>
<activity
android:name=".Ui.InitActivity"
android:label="#string/app_name"
android:windowSoftInputMode="adjustPan">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
Have you made changes in the AndroidManifest file? If not, try this
<activity android:name="com.android.example.sleepcodelab.MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
Cut the intent-filter part from the "MainActivity" activity tag and paste it to the "InitActivity" activity tag.
I have found the solution in my case. I present my solution here in case someone has a similar problem.
The problem was that I called the following function in MainActivity:
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO);
This caused the complete activity stack (including InitActivity) to be recreated. savedInstanceState of InitActivity was null and I could not react to it.
The faulty program flow was as follows:
App starts with InitActivity -> Some data are initialized -> InitActivity starts MainAcitvity -> MainActivity calls setDefaultNightMode which results in InitActivity being restarted but savedInstanceState being null -> InitActivity starts MainAcitvity again
The reason why this didn't end in an infinite loop is that MainAcitvity checked if the night mode is already set correctly and called setDefaultNightMode only if it was necessary to change the setting.
How I solved it:
I moved setDefaultNightMode to InitActivity. This still causes onCreate to be called a second time in InitActivity but this time savedInstanceState is not null and I can use savedInstanceState to prevent MainActivity from being started a second time.
I don't fully understand why savedInstanceState is not null anymore but it works now.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_init);
if(savedInstanceState == null) {
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO);
} else
{
DatabaseInitTask databaseInitTask = new DatabaseInitTask(getApplicationContext(), new DatabaseInitTask.DatabaseInitCallback() {
#Override
public void onInitCompleted() {
showMainActivity();
}
});
}
});
databaseInitTask.execute("");
}
}

Android - Handle global configuration changes

I'm writing a service that tracks system changes, meaning, I'm willing to track whenever a keyboard becomes visible / hidden for any application.
To achieve the following task, i built a small Activity that launches a services
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Intent serviceIntent = new Intent(this, MyService.class);
startService(serviceIntent);
//setContentView(R.layout.activity_main);
}
}
The manifest.xml itself
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="somepackage">
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service
android:name=".MyService"
android:enabled="true"
android:exported="true"
android:configChanges="orientation|screenSize|keyboardHidden"></service>
</application>
</manifest>
and the service itself:
public class MyService extends Service {
public MyService() {
}
private static final String TAG =
"abbeyservice";
#Override
public void onCreate() {
Log.d(TAG, "Service onCreate");
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.i(TAG, "Service onStartCommand");
return Service.START_STICKY;
}
#Override
public IBinder onBind(Intent arg0) {
Log.i(TAG, "Service onBind");
return null;
}
#Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
}
#Override
public void onDestroy() {
Log.i(TAG, "Service onDestroy");
}
}
Problem is I'm notified for changes within, and only for my activity. Which is seen as a white screen for unknown reasons(even though i didn't use SetContentView(..))
When you talk of "keyboard" you are talking about the soft keyboard. This doesn't result in a configuration change, as the configuration has not changed.
There are devices with hardware keyboards that slide out, so they generate a configuration change event when they are slid out or back in again. There is also a possibility to attach an external keyboard to some Android devices and the act of connecting or disconnecting a hardware keyboard also generates a configuration change event.
To detect if the keyboard is shown in your own app, see
How to check visibility of software keyboard in Android?
As far as I know, there is no way to find out if the soft keyboard is shown in another app.

Android app opens after a few seconds after pressing home button during splash screen

I am having an issue I can't seem to figure out the reason for.
When you launch the app, a splash screen is first displayed for 2.5 seconds before finishing and starting a new activity. If you press the home or back button during this time the app will close as normal. However after a few seconds (longer than 2.5) the app will open and start from the activity that comes after the splash screen.
Any help on why this happens is appreciated!
Here is the implementation of the Splash screen (I do however not believe anything here causes this issue as I've tried different implementations)
`public class SplashScreenActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_splash_screen);
Thread myThread = new Thread(){
#Override
public void run() {
try {
sleep(2500);
Intent intent = new Intent(getApplicationContext(),MainActivity.class);
startActivity(intent);
finish();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
myThread.start();`
Here's the manifest
<?xml version="1.0" encoding="utf-8"?>
<uses-permission android:name="android.permission.VIBRATE" />
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<activity
android:name=".activities.MainActivity"
android:label="#string/app_name"
android:theme="#style/AppTheme.NoActionBar"
android:launchMode = "singleInstance">
</activity>
<activity android:name=".activities.SplashScreenActivity"
android:theme="#style/Theme.AppCompat.NoActionBar">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<receiver android:name=".alert.BroadCaster" >
</receiver>
<service android:name=".timer.TimerService"
android:process=":timerservice" />
</application>
It happens because you are creating a new Thread and this thread will be still alive after you put your app in background. You can change your approach using an Handler. If you need that your next Activity won't start if the splash screen is in background, you have to store the current time before the delay starts.
private static final long SPLASH_SCREEN_MS = 2500;
private long mTimeBeforeDelay;
private Handler mSplashHandler;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_splash_screen);
// Create a new Handler.
mSplashHandler = new Handler();
}
#Override
protected void onResume() {
super.onResume();
// The first time mTimeBeforeDelay will be 0.
long gapTime = System.currentTimeMillis() - mTimeBeforeDelay;
if (gapTime > SPLASH_SCREEN_MS) {
gapTime = SPLASH_SCREEN_MS;
}
mSplashHandler.postDelayed(new Runnable() {
#Override
public void run() {
Intent intent = new Intent(SplashScreenActivity.this, MainActivity.class);
startActivity(intent);
SplashScreenActivity.this.finish();
}
}, gapTime);
// Save the time before the delay.
mTimeBeforeDelay = System.currentTimeMillis();
}
#Override
protected void onPause() {
super.onPause();
mSplashHandler.removeCallbacksAndMessages(null);
}
Just use handler instead of thread sleep like this
new Handler().postDelayed(new Runnable(){
#Override
public void run() {
Intent intent = new Intent(SplashScreenActivity.this, MainActivity.class);
startActivity(intent);
SplashScreenActivity.this.finish();
}
}, SPLASH_DURATION);
You need to implement the onStop() method, only if you want to save data and memory.

NavUtils navigateUpFromSameTask() and onSaveInstanceState()

I'm new to android development and I'm facing a problem.
I've got an activity, which contains a ListFragment. After the list item is tapped the new Activity starts. I decided to do a back Navigation in a child Activity with the Home button on the Menu bar.
if (NavUtils.getParentActivityName(getActivity()) != null){
((AppCompatActivity)getActivity()).getSupportActionBar().setDisplayHomeAsUpEnabled(true);
}
....
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
if (NavUtils.getParentActivityName(getActivity()) != null){
NavUtils.navigateUpFromSameTask(getActivity());
}
return true;
default:
return super.onOptionsItemSelected(item);
}
}
And I also need to save the integer value into the parent Activity. So I override the onSaveInstanceState()
#Override
protected void onSaveInstanceState(Bundle savedInstanceState){
super.onSaveInstanceState(savedInstanceState);
Log.d("ACTIVITY_STATE", " onSave");
savedInstanceState.putInt(TAG_INT_VAL_SAVED, intVal);
}
But when I tap on the back arrow at the child Activity and the onCreate method of the parent Activity is called, it appears that the parameter Bundle is null, up to the Log of the following code...
if (savedInstanceState != null){
intVal = savedInstanceState.getInt(TAG_INT_VAL_SAVED);
Log.d("ACTIVITY_STATE", " onSave getting data"); // Never appears at LogCat
} else {
// code to assign intVal as if the Activity was just started
}
I'm a little confused, so I'd like to ask you, guys, for a help. Could you please tell, what's going on, when the navigation happens? And what should I do, to keep the intVal saved? Thank you!
B.t.w. It works fine on the screen rotation - the value is successfully retrieved.
The manifest looks like:
<activity
android:name=".ListItemActivity"
android:label="#string/app_name" >
<meta-data android:name="android.support.PARENT_ACTIVITY"
android:value=".MyListActivity"/>
</activity>
<activity android:name=".MyListActivity"
android:label="#string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>

Can't switch between activities

sorry for asking dumb questions, java and Android are both new to me ;)
My problem: I can't switch between two activities in a very simple app. I tried solutions described in similar topics but it didn't work.
So this is my 1st Activity (I didn't paste the imports):
public class OneActivity extends Activity {
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
public void OnStart(){
Button Btn = (Button)findViewById(R.id.btnNext);
Btn.setOnClickListener(new OnClickListener() {
public void onClick(View Button) {
Intent myIntent = new Intent(OneActivity.this, UserInput.class);
OneActivity.this.startActivity(myIntent);
}
});
}
}
The second Activity is very simple - it is just supposed to load a layout called userinput.xml:
public class UserInput extends Activity {
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.userinput);
}
}
The application part of the Manifest looks like following:
<application
android:icon="#drawable/ic_launcher"
android:label="#string/app_name" >
<activity
android:name=".OneActivity"
android:label="#string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<activity
android:name=".UserInput"
android:label="#string/app_name" />
</activity>
</application>
When I run the app and click the button nothing happens. Where could be the problem?
// Alright, I have put the code into the onCreate() method so it now looks like following:
public class OneActivity extends Activity {
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Button Btn = (Button)findViewById(R.id.btnNext);
Btn.setOnClickListener(new OnClickListener() {
public void onClick(View Button) {
Intent myIntent = new Intent(OneActivity.this, UserInput.class);
OneActivity.this.startActivity(myIntent);
}
});
}
}
Now the app crashes (force close) anytime I click the Next button.
You define your onStart() function with a capital 'O'. That is why the function is never called.
Your onStart():
public void OnStart(){ ... }
How it should be:
// Note the lowercase 'o' in onStart
public void onStart(){ ... }
Also note that having an #Override above the function name when you want to override a method will help prevent making these mistakes, as Eclipse (or whatever IDE you use) will tell you that you are not actually overriding a function.
Write below code in onCreate() method:
Button Btn = (Button)findViewById(R.id.btnNext);
Btn.setOnClickListener(new OnClickListener() {
public void onClick(View Button) {
Intent myIntent = new Intent(OneActivity.this, UserInput.class);
startActivity(myIntent);
}
});
2nd correction for android manifest file:
<application
android:icon="#drawable/ic_launcher"
android:label="#string/app_name" >
<activity
android:name=".OneActivity"
android:label="#string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity> <!-- closed here -->
<activity
android:name=".UserInput"
android:label="#string/app_name" />
</application>
You can move all the code in onCreate() and simplify like this
startActivity(new Intent(this, UserInput.class));
But I don't understand why you start another activity like this
Check it following line
Intent myIntent = new Intent(OneAvtivity.this, SecondActivity.class);
startActivity(myIntent);
Your Class name is UserIpnout and you write SecondActivity.class
Intent myIntent = new Intent(OneAvtivity.this, UserInput .class);
startActivity(myIntent);

Categories