Android: NullPointerException from UP Button - java

I have a problem with a nullpointer exception when I return to a previous activity by using the UP button in the action bar.
I'll try to explain my flow:
ActivityA.java:
Intent intent = new Intent(this, ActivityB.class);
intent.putExtra(KEY, value);
startActivity(intent);
ActivityB.java:
Obj o = getIntent().getSerializableExtra(ActivityA.KEY);
o.doStuff();
Intent intent = new Intent(this, ActivityC.class);
startActivity(intent);
ActivityC.java:
// Do some stuff, then finish
finish();
Now all this works fine when I press a button on Activity C that triggers the finish()part.
The problem occurs when instead of pressing that button I press the UP button on the action bar to go back to Activity B. Then I get a nullpointer because he tries to recreate Activity B, and fails on the line o.doStuff();
FATAL EXCEPTION: main
java.lang.RuntimeException: Unable to start activity ComponentInfo{ActivityB}:
java.lang.NullPointerException
How can I solve this? How can I prevent the Activity B from needlessly recreating? Please keep in mind that I'm doing this Android stuff since Tuesday ..

I know that this might not be what you want but this scenario is not uncommon and what I find myself doing at times is if (o == null) in ActivityB I do finish(). This leads the user back to ActivityA. If ActivityA is not in the backstack, then the app finishes. This is what happens with Instagram at times. It's not perfect but it's not that annoying, I think.
If it's a must to go back to B, you could actually just transfer your Object in your intent to C. And before finish() in C, you could fire a new StartActivity(B.class) with Object as extras to B.

You should look at the Android Activity lifecycle. The problem is that starting a new Activity can destroy an old one in memory, and if you don't return to an Activity for a while its memory will be reclaimed. You need to take a look at onPause() and onResume() to see what you can do to save state.
https://developer.android.com/training/basics/activity-lifecycle/starting.html
It's not that Android "needlessly" recreates the Activity, it does it all the time. If you change orientation, your Activity is destroyed and recreated. If you start a bunch of apps and Android needs the memory currently held by an inactive app, it'll be destroyed and will be recreated when you next launch it.
As an aside, if you're not going to use the lifecycle callbacks onPause() and onResume(), you should at least check to see if your object is null and recreate it in onCreate().

Related

On Back Button shows errror

I have four activity for my application, Main Activity -> second Activity-> Third Activity -> Fourth Activity. Each Activity contains the onBackPressed method implemented. Every time when the onBackPressed method called, it sends an intent to the previous activity. For Example, in Fourth Activity onBackPressed method, it contains an intent to go to the previous Activity, which is the Third Activity. This works fine upto the MainActivity. When I press on the back button on the MainActivity it must exit the application. However, it just starts the next activity, which is the second Activity. What causes this bug???
Here is some relevant code.
From the fourth activity:
#Override
public void onBackPressed() {
Intent intent = new Intent(this,third.class);
intent.putExtra("id",FinalID);
intent.putExtra("Image Item", categoryItem);
startActivity(intent);
}
From the third activity:
#Override
public void onBackPressed() {
Intent intent2 = new Intent(this, second.class);
intent2.putExtra("Image Item", categoryItem);
Toast.makeText(this, "theFinalActivity=" + categoryItem.getId(), Toast.LENGTH_SHORT).show();
startActivity(intent2);
}
The second activity looks like the following.
#Override
public void onBackPressed() {
next = false;
Intent intent = new Intent(this, MainActivity.class);
startActivity(intent);
}
And finally the code in the MainActivity:
#Override
public void onBackPressed() {
System.exit(0);
}
Android System internally handles the backstack for the activities. You don't need to explicitly handle going back if you're not supposed to override the default behavior. In your case, On pressing back, you're not popping the current activity, instead you're pushing a new one into the backstack. This will result in ambiguous behavior of your back button.
First, the onBackPressed function is not required to be implemented only if you are caring about taking care of the activity stack (i.e. finishing up your third activity will bring back the second and finishing the second activity will bring up the first one and so on). The activity stack is already taking care of it.
Secondly, if you want to pass the data to a caller activity from the activity that you have opened from the caller, this is not the ideal way to do so. I would like to recommend you to read this documentation where it explains how to pass such intents in a graceful manner using the life-cycle functions provided by Android.
Just to give you a heads up, here are three steps for you to pass the data between activities in a backward direction.
You need to start the second activity from the first activity using startActivityForResult instead of startActivity with a request code passed along with it (so that you can differentiate between different request codes from other activity if there is any).
Then in your second activity, if you need to pass something to your caller activity (i.e. the first activity), you need to use setResult to pass the desired data back to the caller and finish() the second activity.
In the first activity, you need to implement onActivityResult function to get the data back from the second activity.
Here is a nice example of the overall implementation where you can take a look too.
I know that you are expecting that the system.exit(0) should kill the application whatever the situation is. However, in Android, it does not work in the way that you have expected I think. I am quoting from this answer on StackOverflow to explain how the system.exit(0) works.
System.exit(0) - Restarts the app with one fewer activity on the
stack. So, if you called ActivityB from ActivityA, and System.exit(0)
is called in ActivityB, then the application will be killed and
started immediately with only one activity ActivityA.
I hope that helps!

Switching between activities automatically

I'm new to Android programming, so I'm probably missing something trivial here.
The goal is to create a prototype of a digital signage app. Right now I've created three activities; MainActivity has a method which switches to the second activity after a certain period of time. The same method is then called from the second activity to third, and from third back to main.
There are two problems though: first, is it ok to create new Intent every time the app switches between the activities? As I mentioned, I started learning Android recently, so please don't be mad if this is a super dumb question.
Second: the app launches itself after I've hit home button in my emulator even though I'm calling finish(); after the startActivity(intent);
Here is the method in the MainActivity:
public void switchActivities(final Class<?> classObject) {
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
Intent intent = new Intent(getApplicationContext(), classObject);
startActivity(intent);
finish();
}
}, 1000);
}
The activities Second and Third extend MainActivity and call the switchActivities method:
switchActivities(Third.class); (from Second to Third).
Thanks in advance!
UPDATED:
I added public boolean isRunning = true; to my MainActivity and
if(isRunning) startActivity(intent); to the switchActivities method;
I also added a method
#Override
protected void onPause(){
super.onPause();
isRunning = false;
}
as advised here.
Although finish(); should have cleared the method stack, the app didn't close after pressing Home button but went to previous activity instead, so I added this line to every activity in the AndroidManifest file:
android:noHistory="true"
as advised here.
Sorry for not upvoting helpful answers, I don't have enough reputation yet.
Yeah, it is the proper way of switching activities by creating new intents. I am little confused about your second questions. if you are saying that as you are using postDelayed method which gets triggered after some interval, is being called even you have finished your activity or pressed home button, you can handle this by creating a boolean variable isRunning in your activity which gets false when onPause or onDestroy gets called. Then you in your postdelayed method, you can check the flag and then proceed as required.
The Intent used in navigation between the Activities , so it's cool to using it , no problem
The second problem because the Activity object still in your memory after you hit Home button , then the Handler will continue its work and start the activity after the certain period you determined in your code
For your first question: it's not a problem that you're creating a new Intent every time
The second one is a bit trickier. When you press the home button the current activity stays in memory, so it can start the new one even though you think it's not running. The easiest way to handle this to check weather the activity is finishing, and if so, you don't show the next one.
if (!isFinishing()) startActivity(intent);
This if statement prevents your activity to start a new one when it's in the background.

How do I close a previously opened layout?

Im needing to know how to destroy previous class, when I open a new class so I dont have a ton of open classes to have to hit the 'back' button through to get back to 1st main class.
I know the layout code within the onCreate is typically this:
setContentView(R.layout.page);
i was thinking like super.destroy();
So when I use an intent to launch another class, I want the inital class to not leave behind open window/ContentView
By class, you mean another activity?
You can call finish(); after you have started the intent;
Intent intent = new Intent(activity1.this, activity2.class);
startActivity(intent);
finish();
Android also takes care of these things himself. If memory is needed, the Dalvik virtual machine will close low priority activities that are running.
onDestroy is called automatically when the Activity is shut down. To remove your previos layout you can just call the method finish() or System.exit(0);

Android: launchMode=SingleTask problem

I have an app that circles around the main activity (a main menu). In each other app there is an option menu item that directs to this activity.
At first, I always started a new main activity when this item was selected. Using the intent bundle, I did tell the main activity that some initializations I do on a fresh start were not necessary.
However, I didn't quite like the overall behavior. I stumbled upon android:launchMode="SingleTask" and this seemed to help: now I don't recreate my main menu activity all the time; also, if I press the "back" button I come back straight to the home screen. This feels quite nicely like a proper "main" menu.
My problem now is this: if I run another activity of my app, press home button and then reopen my app (e.g. using "last apps"), then I don't go back to the last activity, but to the main one. The other activity is destroyed.
Any ideas how I can implement the behavior of SingleTask without only being able to return to one activity?
If your other activities are declared normally with activity defaults in Android, then going back to your app should take you to the same activity where you left off (using the hardware home button)
However remember that the Android system kills applications when it requires system resources. So your app may have been killed when you went to the other application. Then when you get back to your app, the default launcher activity will be restarted, which is your Menu activity.
To get back to the main activity from any activity, do this:
public static void goHome(Context context) {
final Intent intent = new Intent(context, HomeActivity.class); //give name of your main activity class here
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
context.startActivity(intent);
}
That will clear the activity stack and get you back to your main activity. As you declared singleTop, it will bring the existing main activity to the foreground. The flag Intent.FLAG_ACTIVITY_CLEAR_TOP will remove all activities in the stack on top of the main activity. (I am assuming you are within the same application).
Now, all your other activities only need to include a button whose click listener invokes the method goHome();
From your main activity, if you press the hardware back button, it should exit your app.
Why not call finish() on the activities that were created by the main activity? This way you return to the main activity, without creating a new one...
I think you should save the state of you activity before starting another activity, and then resume your activity whenever you come back on last activity.
see Activity Life cycle from Android
http://developer.android.com/guide/topics/fundamentals/activities.html

Prevent an Activity from being killed by the OS while starting a child activity

I have a main activity which calls a child one via
Intent I = new Intent(this, Child.class);
startActivityForResult(I, 0);
But as soon as Child becomes visible the main activity gets its onStop and immediately after that onDestroy method triggered. And as soon as I call finish() within the Child activity or press the back button, the Child activity closes and the home screen shows (instead of the main activity).
How can I prevent the main activity from being destroyed? :\
If you launch a child Activity from which you expect return data, you'll probably want to use startActivityforResult instead.
You may want to check this question: Child Activity in Android as it seems to be the same problem.
Edit:
As for what's happening here, you could place code in the onStop() and/or onDestroy() methods to investigate - at least a call to isFinishing() to check why the Activity is being destroyed.
You should also use adb logcat from your host machine to check the logcat in case it holds more information - and maybe use Log.d() (the result goes into logcat as well) instead of toasts to make sure you don't miss them.
I used Dialog instead of an Activity and everything worked well so I'm leaving it like that.
check androidmanifest nohistory=true and that made the OS destroy the activity before the result. that might be one of the reason for your problem.

Categories