Just looking at this documentation about Activity Lifecycle
https://developer.android.com/reference/android/app/Activity.html
it seems to me the onResume callback is not really a real resume. Because it will run if
a. Activity is just created, even if it was not paused.
b. Activity was paused and then it's resumed.
I am sending a user to another activity to do stuff, and depending on what the user did on those other activities, when they return, I need to decide whether to reload the app manifest. However, I don't even wanna check if the app was not paused at all! (ie. the user just opened the activity)
Is there a better way to track if the user is really resuming other than creating a variable in onPause that I will check when the user returns?
Declare a boolean flag in your activity:
boolean hasBeenPaused = false;
Now in your onPause(), set this to true:
public void onPause(){
hasBeenPaused = true;
}
Since your onResume gets called whether or not the app was previously paused, you can now check the boolean and know if it's a fresh start onResume or post pause onResume
public void onResume(){
if(hasBeenPaused){
//onPause was called
//May be because of home button press, recents opened, another activity opened or a call etc...
}else{
//this is a call just after the activity was created
}
}
If you want to persist, you can even save this variable inside onSaveInstanceState and get the saved state in your onCreate
If you are absolutely against setting the variable in onPause and want to ensure that a change was made before reloading the data then set a variable in your API calls that triggers a reload when the user comes back to the activity. Depending on your application structure you could even do the reload before hitting onResume in the activity.
Also be aware that onResume will be called if you're in a fragment and provide a popup (such as an activity indicator).
Related
When I press the home button on my phone, and when I return to the application, it loses the focus completely, it loses track of where activity was; i.e. the Activity returns to principal state. How to avoid that so that when I press the home key and return to the app; to return to the where the activity was?
I need the solution to work for all devices?
Thanks.
Well when you press the home button, the activity's lifecycle methods will be called (first onPause(), then onStop()), and then when you return, if in the meantime your operating system didn't call onDestroy() (this happens when you force close an app or are running out of memory), your Activity will call onResume() method. If it was destroyed, it will call onCreate and start from the beginning.
So basically what you need to do is override (CTRL+O in Android studio to open the override menu) these methods to save your application state, save the important parameters of your app (since you've not shared any code, I cannot presume what these are) and to then later restore the state your app had previously come to.
I have an application with basically a list of items and a detail screen for each items.
When initially started, we show the list of items. If the user switches to another app when viewing a details screen, when he comes back to the app, the details screen is shown.
All that is the standard, and working well. However, my client needs the user to come back to the list screen instead of the details screen each time the app is resumed.
My first idea would be to remember the time at which the details activity got paused, and when started, if the time is greater than X seconds, finish and launch list activity instead of resuming.
Any more reliable way to do that?
PS: I know we should not do that, I already explained that to my client, decision is not mine.
Use SharedPreference to save the time of your paused detail activity in onPause and when it resume check the saved time with current time whether it has passed your threshold if it is passed then close it otherwise remain it opened.
Implement this solution and it definitely helps.
Basically, the app is not actually restarting completely, but your launch Activity is being started and added to the top of the Activity stack when the app is being resumed by the launcher. You can confirm this is the case by clicking the back button when you resume the app and are shown the launch Activity. You should then be brought to the Activity that you expected to be shown when you resumed the app.
The workaround I chose to implement to resolve this issue is to check for the Intent.CATEGORY_LAUNCHER category and Intent.ACTION_MAIN action in the intent that starts the initial Activity. If those two flags are present and the Activity is not at the root of the task (meaning the app was already running), then I call finish() on the initial Activity. That exact solution may not work for you, but something similar should.
Here is what I do in onCreate() of the initial/launch Activity:
if (!isTaskRoot()
&& getIntent().hasCategory(Intent.CATEGORY_LAUNCHER)
&& getIntent().getAction() != null
&& getIntent().getAction().equals(Intent.ACTION_MAIN)) {
finish();
return;
}
for more details on isTaskRoot()method reference.
You have to provide the following onPause() method to all the activity classes except your list_item activity(Initial Activity).
#Override
protected void onPause() {
super.onPause();
Intent i = new Intent(getApplicationContext(), list_item_activity.class);
startActivity(i);
}
I might understand your problem incorrectly but why you do all the timing stuff? I mean, assuming you've fragments for your list and detail views, just put a a flag to monitor your activity has stopped and listen to catch your activity resume ( via onResume or onWindowFocusChanged ). If it's stopped and resumed then transition to list fragment if it's not already visible.
You can you a broadcast receiver here.
And on activity OnResume method use a call to broadcast receiver and perform whatever you need like this.
#Override
protected void onResume() {
super.onResume();
sendBroadcast(new Intent("YourActionHere"));
}
basically my app has 2 activities.Say "A" and "B"
.
A launches B.
Activity B plays music and also has a notification.
Case 1:when the view is still on activity B` i press home button and then i click on the the notification, activity B is opened with its view intact and with its music playing (because in the manifest i am using android:launchMode= "singleTop" and hence another instance of the activity is not created) this part is as desired......
but
Case 2:when the view is on activity B and i press back button ,activity A appears and then i click on the the notification, activity B is opened with the view lost and music also stops(not desired)......i am making a guess that it happens because when i press the back button the activity is destroyed ,so i have to progamatically restore its view right??so to restore its view i override two methods .....
#Override
public void onSaveInstanceState(Bundle savedInstanceState) {
// Save UI state changes to the savedInstanceState.
// This bundle will be passed to onCreate if the process is
// killed and restarted.
savedInstanceState.putBoolean("boolMusicPlaying", boolMusicPlaying);
savedInstanceState.putInt("swapnumber", swapnumber);
savedInstanceState.putString("seekbarprogress", progress2);
savedInstanceState.putInt("position.seekbar",seekbar.getProgress());
savedInstanceState.putString("seekmaxString", max2);
savedInstanceState.putInt("seekmaxInt",seekMax);
savedInstanceState.putParcelableArrayList("songfetails",songdetails);
super.onSaveInstanceState(savedInstanceState);
}
//make a note ....even if i don't override onDestroy() and don't call on SaveInstanceState explicitly, then too i am not getting any desired effect.......
#Override
public void onDestroy()
{ Bundle savedState = new Bundle();
onSaveInstanceState(savedState);//because of this line....the app is crashing......
super.onDestroy();
}
but it didn't help.....
and in on create i am putting a check if saved instances is null or not....create view accordingly...(i.e from saved instances or from fresh) but it didn't help...
also this line is giving a crash ...onSaveInstanceState(savedState);
even if i don't override ondestroy() and kill the app manually from task killer,and then try to open activity B,then too the saved instances thing should work right,because the method OnSaveInstanceState will be automatically called then,right???please help
Basically if you have pressed a back button,restoration of activity should be done using shared preferences/or a database but if you haven't pressed the back button and then you want to restore the state of the activity (because the activity was destroyed by the system ) then the bundle savedinstances can be used ...
From Android documentation:
When your activity is destroyed because the user presses Back or the activity finishes itself, the system's concept of that Activity instance is gone forever because the behavior indicates the activity is no longer needed. However, if the system destroys the activity due to system constraints (rather than normal app behavior), then although the actual Activity instance is gone, the system remembers that it existed such that if the user navigates back to it, the system creates a new instance of the activity using a set of saved data that describes the state of the activity when it was destroyed. The saved data that the system uses to restore the previous state is called the "instance state" and is a collection of key-value pairs stored in a Bundle object.
To fix second problem you must restore data form some other source (service that plays music, restore info from application context or singleton, etc.)
For more info check this.
I have a quiet big application, and sometimes the user uses the HOME BUTTON to 'exit' the application or he receives a call etc. but when he clicks again on the icon, the application is resumed.
What I want is everytime somthing like this happens, the app restarts on the login activity (security process) before resuming the previous activity running before he exit the app.
When the HOME button is pushed, I believe your activity's onStop() and/or onPause() functions will be called. Override one of these methods and set a member variable to check if your activity was interrupted. Now override onResume() to check that variable to determine if you want to start your login activity.
Hopefully this idea gets you in the right direction.
You might also consider creating a super class that extends Activity and override the onStop()/onPause()/onResume() methods to exhibit this functionality. That way, all of your activities outside of your login activity can extend this class, allowing you to place the functionality that you desire in exactly one location.
Pass a Extra to any activity you call after login: intent.putExtra("isLogin", "Yes");
In every activity you call:
declare a field boolean isLogin;
In onCreate:
Intent sender = getIntent();
isLogin = sender.getStringExtra("isLogin","No") == "Yes";
In the onResume of every activity do this:
if(isLogin){
isLogin = false;
}else{
callActivityLogin();
}
The books I have are abysmal at explaining how to work with the lifecycle, there's a lot I'm missing that I'm hoping somebody can fill in.
My app structure is that when it's first started, it starts an activity full of legalbabble that the user has to accept. When he says 'ok', I start my main activity and then I call finish like this:
public void onClick(View view) { //as a result of "I accept"
Intent mainIntent = new Intent(mParent, EtMain.class);
startActivity(mainIntent); // Start the main program
finish();
}
Then in EtMain in the onCreate method, I've got some tabs and I instantiate some classes:
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mTabHost = (TabHost)findViewById(android.R.id.tabhost);
SetupTabs.setMyTabs(mTabHost, this);
mComData = new ComFields(this); // Create the objects
mDepWx = new WxFields(this, DepArr.Departure);
mArrWx = new WxFields(this, DepArr.Arrival);
mDepVs = new DepFields(this);
mArrVs = new ArrFields(this);
mTabHost.setOnTabChangedListener(new OnTabChangeListener(){
}
Questions:
The 'finish' in the first fragment should terminate the legalbabble activity so it'll never be restarted, right? And the EtMain one will remain forever (until killed externally), even if my app gets pushed to the background, right?
The way it is now, when EtMain gets pushed and later brought to the foreground (by tapping on the icon), it goes through the legalbabble screen as though it's a complete start - that's what I'd like to prevent - going thru the legalbabble screen again.
It would seem that I'd want to override onRestart in the second code fragment and put something in there to restart the app, right? That's the part I'm unclear about.
My question then is what needs to be done in onRestart. Do I have to recreate all the tabs and data in the tabs and all my object instantiations? Or is the memory state of the app saved someplace and then is restored back to the state that it was in before something else was brought to the foreground in which case not much needs to be done because all the objects and listeners will still be there?
Yes after the first activity has ended you shouldn't have to view that activity again. You could also write to the shared preferences that the user has previously seen legal info.
If you're UI object creation is in the onCreate method, this should only be called once. Pausing or resuming will not call the onCreate method again.
Unless you explicitly remove your objects and tabChangedListeners in the onPause method, you should not have to touch them in the onRestart method.
Correct, the state of the app is saved automatically. You shouldn't have to touch the onRestart method.
Hope this helps!
I think the problem is that the launch activity in your manifest is the legalbabble activity, so when you click on the icon, the system launches another one. A better architecture would be to launch the legalbabble activity it from your EtMain activity in the onCreate method of the latter, using startActivityForResult. From the docs:
As a special case, if you call startActivityForResult() with a requestCode >= 0 during the initial onCreate(Bundle savedInstanceState)/onResume() of your activity, then your window will not be displayed until a result is returned back from the started activity.
When you get the result in onActivityResult, you can call finish() if the legal stuff was declined; otherwise everything will proceed normally.
This avoids the problem that the launch activity defined in your manifest finishes when the legal stuff is accepted.
EtMain will not remain forever, if the user backs out (by pressing the BACK key) the Activity will be finished (onPause, then onStop, then onDestroy will be called).
In general you can ignore onRestore until you are doing something complicated.
Once the user has exited your application and re-enters (or presses the icon on the Homescreen), onCreate (followed by onStart and onResume) will be called for your first activity, so you do not need any logic in onRestart, your code in onCreate will do the setting up for you as it did the first time. Because of this your legal babble will appear again when the user starts the app after exiting unless you store a preference (in SharedPreferences or a database or file) to indicate you have already displayed it - in which case finish it straight away and start the main activity.
onRestart is only called when the application goes from the stopped state (onStop has been called but not onDestroy) to the started state (onStart is called but onResume has not yet).
For saving data - some components save their state automatically (e.g. EditTexts remember the text in them, TabHosts remember the currently selected tab etc). Some components will not. If you wish to save extra data then make use of onSaveInstanceState and onRestoreInstanceState. You should only use these methods to restore the state of your application or temporary data, not important things, e.g. the id of the resource what the user was looking at, what zoom level they were at etc. For things like contacts or actual data you should commit these changes to a database, SharedPreferences or other permanent storage (e.g. file) when onPause is called.
I recommend taking a look at the Android Activity lifecycle if you are confused. Or ask more questions!