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

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("");
}
}

Related

Get the current activity to handle NFC TAG discovered [duplicate]

This question already has an answer here:
Android: How do I temporarily handle an Intent in a different activity of my application?
(1 answer)
Closed 3 years ago.
I've got an android app with several activities. I want the current activity to handle the nfc discovered event, as the state of the app determines what i want to do with the tag
As can be seen in the attached code i've set up the intents on each activity and implemented the onResume, onPause and onNewIntent methods in each activty.
Yet, for some reason the MainActivty is the only one which gets called even though one of the other activities is the active one. Eg. it is the one with the current GUI.
You guys have any idea how to get the active activity to handle the NFC discovered?
Any help greatly appreciated :)
Here is the ApplicationManifest
<uses-permission android:name="android.permission.NFC" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<activity
android:name=".ConfigureStableNamesActivity"
android:label="#string/app_name"
android:theme="#style/AppTheme.NoActionBar">
<intent-filter>
<action android:name="android.nfc.action.NDEF_DISCOVERED " />
<category android:name="android.intent.category.DEFAULT" />
<data
android:host="www.nxp.com"
android:pathPrefix="/products/identification_and_security/smart_label_and_tag_ics/ntag/series/NT3H1101_NT3H1201.html"
android:scheme="http" />
</intent-filter>
</activity>
<activity
android:name=".MainActivity"
android:label="#string/app_name"
android:theme="#style/AppTheme.NoActionBar">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
<!-- <action android:name="android.nfc.action.ACTION_TAG_DISCOVERED"/>-->
<action android:name="android.nfc.action.NDEF_DISCOVERED " />
<category android:name="android.intent.category.DEFAULT" />
<data
android:host="www.nxp.com"
android:pathPrefix="/products/identification_and_security/smart_label_and_tag_ics/ntag/series/NT3H1101_NT3H1201.html"
android:scheme="http" />
</intent-filter>
</activity>
In each of my activities i have this code to handle the NFC discovered intent
#Override
protected void onResume() {
super.onResume();
ntagHandler.start();
}
#Override
protected void onPause() {
super.onPause();
ntagHandler.stop();
}
#Override
protected void onNewIntent(Intent intent) {
try {
Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
nfcHandler = new NearFieldCommunicationHandler(tag);
nfcHandler.connect();
// DO SOMETHING HERE
// dataModel.readStableNames(nfcHandler);
} catch(IOException e) {
Toast.makeText(this, "Caught exception: " + e.toString(), Toast.LENGTH_LONG).show();
}
}
You need to implement "The foreground dispatch system". it allows an activity to intercept an intent and claim priority over other activities. Please refer: https://developer.android.com/guide/topics/connectivity/nfc/advanced-nfc#java
First create pendingIntent globally in your each activities as below:
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, new Intent(this, getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), 0);
then take IntentFilter globally and init with null as below:
IntentFilter[] intentFiltersArray = null;
Write below code in onCreate() method:
IntentFilter ndef = new IntentFilter(NfcAdapter.ACTION_NDEF_DISCOVERED);
try {
ndef.addDataType("*/*"); /* YOU CAN TYPE HERE EITHER android.nfc.action.NDEF_DISCOVERED or
android.nfc.action.ACTION_TAG_DISCOVERED */
}
catch (IntentFilter.MalformedMimeTypeException e) {
throw new RuntimeException("fail", e);
}
IntentFilter[] intentFiltersArray = new IntentFilter[] {ndef, };
then take techListsArray globally as below:
String[][] techListsArray = new String[][] { new String[] { NfcF.class.getName() } };
Finally write below code to enable and disable the foreground dispatch when the activity loses (onPause()) and regains (onResume()) focus. enableForegroundDispatch() must be called from the main thread and only when the activity is in the foreground (calling in onResume() guarantees this)
public void onPause() {
super.onPause();
nfcadapter.disableForegroundDispatch(this);
}
public void onResume() {
super.onResume();
nfcadapter.enableForegroundDispatch(this, pendingIntent, intentFiltersArray, techListsArray);
}
public void onNewIntent(Intent intent) {
Tag tagFromIntent = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
//do something with tagFromIntent
}

Already initialised object is set to null in BroadcastListener Method: onReceive

My Class NetworkListener should check, if Internet Connection is available or not. Then, It should show a Snackbar with the InternetState. For this, I'm using an interface.
My whole code:
[MainActivity.java]:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
setTitle(R.string.Inbox);
Initialize_NavigationDrawer();
Initialize_Objects();
//1. Here, I initialise my NetworkListener and register my Receiver
NetworkListener mNetworkListener = new NetworkListener();
mNetworkListener.registerReceiver(this);
}
#Override
public void ToggleSnackbar(boolean ShowHide) {
if (ShowHide) snbNoInternet.show();
else snbNoInternet.dismiss();
}
[NetworkListener.java]:
public class NetworkListener extends BroadcastReceiver {
private SnackbarInterface snbInterface;
public NetworkListener() {}
#Override
public void onReceive(Context context, Intent intent) {
//4. After toggling the Network-Connection, a NullReferenceException occurs
//5. System.out.println(snbInterface) shows: null
ConnectivityManager cm = (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo ni = cm.getActiveNetworkInfo();
if (ni == null || !ni.isConnected()) {
snbInterface.ToggleSnackbar(true);
}
else if (ni != null && ni.isConnected()) {
snbInterface.ToggleSnackbar(false);
}
}
public void registerReceiver(SnackbarInterface receiver) {
snbInterface = receiver; //2. Is called from onCreate
//3. System.out.println(snbInterface) shows: at.guger.email.activities.MainActivity#27472a5e
}
public interface SnackbarInterface {
public void ToggleSnackbar(boolean ShowHide);
}
}
[AndroidManifest.xml]:
<activity
android:name=".activities.MainActivity" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".activities.WriteActivity" />
<activity
android:name=".activities.ReadActivity" />
<receiver
android:name=".NetworkListener">
<intent-filter>
<action
android:name="android.net.conn.CONNECTIVITY_CHANGE" />
</intent-filter>
</receiver>
And the permissions:
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
The code is called like the numbers are ordered!
I really can't explain, why snbInterface is set to null!
I hope you can help me!
You registered the BroadcastReceiver using the receiver element in the AndroidManifest. Android system creates the BroadcastReceiver instance and calls the onReceive method with the appropriate parameters.
If you want to use a BroadcastReceiver to manipulate UI of your application (like show/hide Snackbar ), you will have to register the receiver within your activity using the registerReceiver(BroadcastReceiver receiver,IntentFilter intentFilter) in the onCreate method and unRegister in the onDestroy method of your activity.
Remove the receiver element from the AndroidManifest.xml file and create the BroadcastReceiver through code.
This question here has a clear explanation on how BroadcastReceivers can be created and registered :
Broadcast Receiver class and registerReceiver method
In the onReceive method of the BroadcastReceiver, call the toggleSnackbar method in your Activity to toggle the Snackbar.
There is an other method for achieving what you want. It is discussed here:
Inform Activity from a BroadcastReceiver ONLY if it is in the foreground
Read more on BroadcastReceivers here
You can write the Receiver as a separate class. Instantiate the Receiver and make a call to registerReceiver with the first parameter as the Receiver and the second parameter as the IntentFilter.

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>

Force closing app and ActivityNotFoundException while using ListActivity

I am following an youtube tutorial to create android apps.
In one of the tutorials they told how to create a Menu class using List activity.
public class Menu extends ListActivity {
String classes[] = {"Start","example1","example2","example3","example4","example5","example6"};
#Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setListAdapter(new ArrayAdapter<String>(Menu.this, android.R.layout.simple_list_item_1, classes));
}
#Override
protected void onListItemClick(ListView l, View v, int position, long id) {
// TODO Auto-generated method stub
super.onListItemClick(l, v, position, id);
String cheese = classes[position];
try{
Class ourClass = Class.forName("com.example.add." + cheese);
Intent ourIntent = new Intent(Menu.this,ourClass);
startActivity(ourIntent);
}catch(ClassNotFoundException e){
e.printStackTrace();
}
}
And add activity in the manifest.
<activity
android:name=".Splash"
android:label="#string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:exported="false"
android:name=".Menu"
android:label="#string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MENU" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
<activity
android:exported="false"
android:name="com.example.add.Start"
android:label="#string/app_name" >
<intent-filter>
<action android:name="com.example.add.START" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
My project has a Start class which adds one to a counter and display it,
a Splash class which defines background image, music and it is the main class.
Before adding Menu class my app worked fine,but after i added it my app began to force close and logcat showed an ActivityNotFoundException and error in Splash class at line 28
public class Splash extends Activity{
MediaPlayer ourSong;
#Override
protected void onCreate(Bundle Dab) {
// TODO Auto-generated method stub
super.onCreate(Dab);
setContentView(R.layout.splash);
ourSong = MediaPlayer.create(Splash.this, R.raw.nodebeat);
ourSong.start();
Thread timer = new Thread(){
public void run(){ //framework to start a new thread
try{
sleep(5000);
}catch(InterruptedException e){
e.printStackTrace();
}finally{
Intent openStart = new Intent("com.example.add.MENU");
startActivity(openStart);
}
}
};
timer.start();
}
#Override
protected void onPause() {
// TODO Auto-generated method stub
super.onPause();
ourSong.release();
finish();
}
So please help i am new to android app development and im struck here.
Links to the Logcat logs:-
https://docs.google.com/file/d/0BxLaXhL-q50-MHlhUW93SmxNT0U/edit Debug Log
https://docs.google.com/file/d/0BxLaXhL-q50-b1pzbVpIcVNQR2s/edit Error Log
Thanks.
You are using the wrong intent filter for what you're trying to launch. So either change
<action android:name="android.intent.action.MENU" />
to
<action android:name="com.example.add.MENU" />
So that everything matches.
Or change your call in your code so it is:
Intent openStart = new Intent("android.intent.action.MENU");
You should read about Intent Filters.
You could also use the explict intent, since you're not exporting this Activity and you know its name, I don't see a need for an intent filter.
Intent openStart = new Intent(Splash.this, Menu.class);
startActivity(openStart);
Intent action in below both(1 and 2) places should be same , which are not. make them identical.
<intent-filter>
<action android:name="android.intent.action.MENU" />// (1)
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
and
Intent openStart = new Intent("com.example.add.MENU"); (2)

Game doesn't Quit properly

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();
}

Categories