Prevent background Activity from being killed? - java

I have an app that has a list of menu items. When you click a menu item it opens a corresponding activity. Now in that new activity when you click the back button and return to the main list, that activity gets killed and it does not return to its past state when you start it again.
My question is, is it possible to not kill the activity when you leave it?
I tried saving values like so:
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putString("TO_REMEMBER", "Remember this");
}
However once the activity gets killed and than re-started, the oncreate method is not reading any data:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (savedInstanceState != null) {
//This is not getting fired
Toast.makeText(this, savedInstanceState.getString("TO_REMEMBER"), Toast.LENGTH_LONG).show();
}
}
Any help on this is appreciated.

Your are saving state using onSaveInstanceState but that is not meant to save state across activity life-cycle when you press back. That is meant to save state across orientation changes etc. That needs to be done if you want to save some state across orientation change, so you are right there.
Now to save something across activity life-cycles, you have two options:
One, save your state to a persistent DB or something.
Second, if it is not to be stored in DB, then use getPreferences and store it using this. This will store it for that specific Activity only. I ll recommend this if you are trying to store the state of activity.
Edit:
Well leaving Activity alive is not a recommended/documented approach. You can have Service running in the background but does not contain UI as Activity does. If you press Home button instead of Back then it will act something like orientation change.
In short, Activity is responsible for saving its state. That said, some UI controls save their state themselves so you dont have to save their state example EditText will save its state.
Ref:
getPreferences
Shared Storage
Saving Activity State

If you are new to android, you should start with the dev guide which is a really usefull Tutorial for starters which is found here.
As for the BackStack, you can check it here.

Related

How to restore previous application after my application is put in background on Android

I need a way to restore previous Android task when the current task (my application) is put in background using either back or overview button. For example, a video is played by youtube app when a SIP call is received. The softphone task is brought to foreground, then the call is answered. Once the call finishes, by pressing back or overview button youtube app is shown and the video continues playing. An example of such Android application is Linphone. I would like to know how this can be achieved programmatically.
As stated by others and here, Android handles it automatically for you. But if you need to add anything explicitly when going/coming to/from the background state then you can also override onSaveInstanceState() and onRestoreInstanceState() methods which will be called accordingly.
As your activity begins to stop, the system calls the onSaveInstanceState() method so your activity can save state
information to an instance state bundle. The default implementation of
this method saves transient information about the state of the
activity's view hierarchy, such as the text in an EditText widget or
the scroll position of a ListView widget.
To save additional instance state information for your activity, you must override onSaveInstanceState() and add key-value pairs to the
Bundle object that is saved in the event that your activity is
destroyed unexpectedly. If you override onSaveInstanceState(), you
must call the superclass implementation if you want the default
implementation to save the state of the view hierarchy.
#Override
protected void onRestoreInstanceState(Bundle outState) {
if (outState != null) {
Crashlytics.log(1, "FormActivity", "Method:onRestoreInstanceState, Msg: saved instance is not null");
if (outState.containsKey("record")
&& Session.getCurrentRecord() == null) {
Session.setCurrentRecord(
gson.fromJson(
outState.getString("record"),
Record.class
)
);
}
if (outState.containsKey("user")
&& Session.getCurrentUser() == null) {
Session.setCurrentUser(
gson.fromJson(
outState.getString("user"),
User.class
)
);
}
}
super.onRestoreInstanceState(outState);
}
#Override
protected void onSaveInstanceState(Bundle outState) {
Session.setCurrentRecord(record);
outState.putString("record", gson.toJson(Session.getCurrentRecord()));
outState.putString("user", gson.toJson(Session.getCurrentUser()));
super.onSaveInstanceState(outState);
}
Source 1 Source 2
This is done automatically by the android system.
Now why you may not be able to notice this behavior for your app.
You may be launching your app from the app launcher. Which means that you already put all other apps (except the launcher) in background. Now depending on the launcher settings you may go on page from where you launched the app or home when you press back button.
When can you observe this behavior
If your activity is launched from background service, e.g. broadcast receiver
If your activity is launched by clicking on a notification button
basically when your activity is created without killing or putting other apps in background, you will get back to the same app when your app is closed.
Exception - If you use home button all apps go to background and home screen appears.
hope this helps.
here is the official documentation on how to preserve the UI state:
https://developer.android.com/topic/libraries/architecture/saving-states
if the user configured the phone to always kill activities in background or they have limited resources then you have to handle that, but in some cases (your activity wasn't killed and remained in memory) as Mayank answered the system will do it for you.
getting a call from phone app will interrupt your app (System-initiated UI state dismissal)
what you should do as suggested by the documentation above:
In the section: Managing UI state: divide and conquer
Local persistence: Stores all data you don’t want to lose if you open and close the activity. Example: A collection of song
objects, which could include audio files and metadata.
ViewModel: Stores in memory all the data needed to display the associated UI Controller. Example: The song objects of the most
recent search and the most recent search query.
onSaveInstanceState(): Stores a small amount of data needed to easily reload activity state if the system stops and then recreates
the UI Controller. Instead of storing complex objects here, persist
the complex objects in local storage and store a unique ID for
these objects in onSaveInstanceState(). Example: Storing the most
recent search query.
so In your case have a view model that stores the Url and the video time when the call got received
and I would also store the same info in the instanceState using the proper life cycle hooks
here is a good SO thread with example on how to use the savedInstanceState :
Saving Android Activity state using Save Instance State
it has old and new answers, you may want to read through it to get a sense of how things changed overtime
basically the three bullet points above are the recommended strategy by official documentation

Up Navigation: From Activity to Fragment: Android Studio

The basic navigation of my app is a tab bar within one activity in which each tab is its own fragment. I am trying to get the back button to work to go back to the last tab it was on. I can get the back button to work/appear if the activities are going to the first tab by using this in the java class of the activity:
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
and this in the AndroidManifest.xml:
<activity android:name=".CreateNewPost" android:parentActivityName=".MainActivity"></activity>
This works fine, however when I go to a new activity from a button within the other tabs, if I use this same method it goes to tab1. How do I tell it to go to a specific tab or the last active fragment?
Any suggestions would help!
When you launch a new activity the old one either paused or stopped , as in either OnPause() or OnStop() method has been called. Then when you navigate back to a previous activity it is either started (OnStart()) or resuemd (OnResume()). And sometime the activity is destroyed and created again when navigating back to it using OnDestroy() and OnCreate() respectively.
The most guaranteed way that I can think of is to store the state of the first activity somewhere persistently and when the user navigates back to it check what has been stored and show that fragment.
You can use SharedPreferences to store this kind of data, see the google developer documentation on that here. Or onSaveInstanceState(Bundle savedInstanceState) check out this SO question on saving activity state. Although from the answers it is clear that onSaveInstanceState should not work in your specific case, but you should look at it any way because it is useful in other cases like changing screen orientation for example.

Confusion between onPause() onStop() onResume()

I am developing an Android app in which I want to check if the user has minimized the application or just come from another activity.
In detail, if the user have started another app, went to the home screen or locked the screen, I want to show the activity where the user will enter the password to access the app. But where or how to check this exactly?
https://developer.android.com/guide/components/activities/activity-lifecycle.html
I was trying onResume() but according to documentation onResume() can be fired if the user’s navigating to another activity and coming back.
I'm not very clear on what you are trying to achieve.
The life cycle diagram is quite clear if you are wondering which lifecycle method it would hit when something happens.
Basically, it's the same to minimise the app and go to another activity. But if you are referring to coming from another activity in your own app, you can distinguish your own activity by adding extra information to the intent you use.
Basically, it's like this:
Intent intent = new Intent(FirstActivity.this,SecondActivity.class);
intent.putExtra(key,value);
startActivity(intent);
And in your SecondActivity, you can always retrieve that data like this:
Bundle bundle = getIntent().getExtras();
if ( bundle != null && bundle.containsKey(key) ) {
value = bundle.getInt(key); // not nessecarily getInt(), you should use according to your value type
// use the value to tell if it is from your own app
} else {
// it is not from your own app
}
You can use this mechanism combined with the lifecycle methods. For example, if you use the latter code in your onCreate() method, then whenever the Activity is created, if will check who creates it, which sounds like your what you might want.
As soon as your activity becomes visible it will call OnStart() and as soon as it is ready for the interaction(such as touch ,click etc event). it calls onResume, at this stage your app is running and it is completely in foreground. When your activity start another activity or a dialog box then it calls onPause it means activity is visible but user can not interact with the Activity UI. in case we start another Activity which completely hides the previous activity then its onStop method is called
onPause: Called when another activity comes into the foreground.
onStop: Called when that other activity is completely visible.
onResume: Called when your activity is navigated back to from the onPause state.
Maybe your app was already in the onStop state, so then it would call onRestart.

Advice on onPause and onResume

If i use the code below will this restore text that has been input into EditTextfields and selected spinner items?
#Override
protected void onPause(){
super.onPause();
}
#Override
protected void onResume(){
super.onResume();
}
or do I have to tell it to save the current values and then restore then when activity is resumed? when I am using the emulator if I don't have these methods in and I go to say home then run my app again it always loads back to the previous state, so my questions is does this actually do antyhing?
Nope, this actually only called the super class onPause() and onResume() without doing anything else. The value in your editbox stay there because even if the app is paused, is still there on the activity stack waiting.
However Android can kill your paused activity and your data will be lost. So you have to save them onPause and restore them on the onResume to avoid this.
No, this code does not do anything. You're overriding these methods, but giving them an implementation of just calling the parent implementation. This is the same as not overriding them in the first place.
It's not absolutely necessary to save/restore state for when you pause/resume. The only reason why you would need to manually do some state saving is if you want to restore state even after your application is killed.
You values still the same in your spinner because the app hasn't been kill yet. It's only put a pause state still in memory. If the app were destroyed the values of your spinner will be back to the onCreate method and whatever value they had at the start.
Look here for what each method does --> https://developer.android.com/reference/android/app/Activity.html
You only need to save state when onDestroy() is called. That only happens when you use the back button or the OS kills the Activity when it is in a stopped state.
If you Activity becomes partially obscured it will be paused but if it is completely obscured it will be stopped.
When it is top of the stack again it will resume or start.
To experiment use Log to write messages to the LogCat when each of events occurs and then you will be able to see when and why they are called.

Android : Text Fields are displaying empty when returning to previous activity

I have a problem with back button functionality in an Activity of Android. The first Activity having the Spinner to select one item from the Spinner's list and second one is the text field. I implemented search functionality using the Spinner and text field. The results are displaying fine as a ListView.
Here my Problem is:
While returning to the first Activity, the Spinner and text field are showing empty in the Activity. It should show the previous searched results.
Help me with the sample code/ links.
Dont create a new intent. You just need to call finish() from your second Activity to handle back event and move back to your first activity.
Its normal. When your first Activity goes to back ground its finished by System itself. So make sure to save your data in some place and in Activitie's onCreate() and onRestart() method reload the data to TextView and spinner..
Edits:
Create a Data class and Store your search results in String[] array or a String or how ever you like it. and make the class a singlton class. and when you come back to this screen fetch those data's and set Text of TextView and adapter for Spinner..
Shafi yes, i am calling the back function using Intent as Intent i=new
Intent (presentClass.this, previousClass.class);
Don't do this. Because the Activity stack will become like loop with same Activities started again n again. Instead just finish presentClass.. it will come back to previousClass
Just an addition to #ntc post look to onSaveInstanceState(Bundle outState) and onRestoreInstanceState(Bundle state) methods in Activity.

Categories

Resources