I'm using MonoDroid but an equivalent Java answer can still help.
I'm using a portrait layout and a landscape layout so, if possible, I want to use the Android screen orientation to automatically destory/create activities.
My app is using TextToSpeech so in the activity's OnPause() I am stopping it, which works well when the Home key is pressed or an incoming call is happening. However I don't want to stop the TextToSpeech on a screen orientation change from the user.
Is there a simple way of detecting this change so that TextToSpeech isn't interrupted?
My activity's OnStop() code:
protected override void OnPause()
{
// I need this for Home key, intercepting phone calls, etc.
// But how can I prevent this for a screen orientation change?
// Need to enable screen orientation to get my portrait/landscape views
if(Text2Speech.IsTextToSpeechInitialised && Text2Speech.TextToSpeech != null)
Text2Speech.TextToSpeech.Stop();
base.OnPause();
}
As others have said in the comments on the question, I think you'll want to handle configuration changes yourself here. There are other configuration changes that can cause your activity to be restarted as well, such as revealing the device's hardware keyboard.
In Mono for Android you can specify which of these you want to handle yourself in the ActivityAttribute:
[Activity(ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.KeyboardHidden)]
public class MainActivity : Activity
Related
Firstly, I believe this is not a duplicate question, although the solution for the error has been asked a lot of times. I have tried atleast 5 different solutions but they either don't change anything or make things worse. I want to pause the activity when the screen is locked/focus changed and allow the user to unpause the activity when the app is opened again.
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
if (!hasFocus && pauseFragment == null) {
exercisePlayPause(isPaused, workoutExerciseNum);
isPaused = !isPaused;
}
}
exercisePlayPause calls the following method
public void PassExerciseNum(int exerciseNum, Boolean isPaused) {
if (!isPaused) {
pauseFragment = new PauseFragment();
pauseFragment.getExNum(exerciseNum);
getFragmentManager().beginTransaction().add(R.id.aworkout_layout, pauseFragment, "pause").commit();
} else {
getFragmentManager().beginTransaction().remove(pauseFragment).commit();
pauseFragment = null;
exercisePlayPause(true, exerciseNum);
}
}
This works fine when the home button is pressed or some other app is activated or the notification bar is clicked. But when the screen is locked then I get the following error
java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState
at android.app.FragmentManagerImpl.checkStateLoss(FragmentManager.java:1411)
at android.app.FragmentManagerImpl.enqueueAction(FragmentManager.java:1429)
at android.app.BackStackRecord.commitInternal(BackStackRecord.java:687)
at android.app.BackStackRecord.commit(BackStackRecord.java:663)
The offending line is getFragmentManager().beginTransaction().add(R.id.aworkout_layout. I am pausing few processes when any event that makes the user move away from the app. And when the user comes back to the app, he/she can resume from there. Hence, I am not destroying the activity. I have tried using commitAllowingStateLoss() but that makes me lose data for the paused processes and becomes a bit messy.
So in short the question is how to make a fragmenttransaction happen before onSaveInstanceState is triggered when the screen lock button is pressed?
The activity's orientation was sensorLandscape. When a screen locks it converts the screen to portrait and when the screen is unlocked it starts from a portrait mode and then becomes landscape. Hence, onDestroy was called when screen is locked. And when the screen is unlocked, onCreate gets called. This orientation change overrides the activity's orientation set in manifest. What happens when this forceful orientation happens can be controlled by adding android:configChanges="orientation|screenSize|keyboardHidden"/> to the manifest. This prevents onDestroy being called and the "illegalStateException" can be avaoided.
I have developed an application and it contains web view.
My issue
When my phone's orientation changes from portrait to landscape the whole application loads again and the web view reloads showing the first page of website.
So I am getting confused about the screen orientation or saving the data during that phase, so how do I fix it...
Yes, in Android the Activity is destroyed and recreated when your change the screen orientation. Thus you need to restore your applications state on recreation. On way is to use the callback method onSaveInstanceState() which you can use to save the state in a Bundle.
The Activities are explained here: http://developer.android.com/guide/components/activities.html and I suggest you take a look on that page for examples and more detailed instructions.
The default behaviour is to restart the activity when a configuration change happens (such as orientation change).
To override this you need to tell the system you'll handle orientation change yourself by adding this to your manifest file in your <activity> element:
android:configChanges="keyboardHidden|orientation|screenSize"
You may also want to override onConfigurationChanged which will be called when such a change happens.
See http://developer.android.com/guide/topics/manifest/activity-element.html#config
The Android Activity lifecycle clearly indicates this behaviour .
What happens
Whenever you start an Activty is gets created(after onStart() method) the
onCreate(Bundle onSavedInstance)
The variable onSavedInstance mentioned above initially recieves null as nothing is saved.
But during the orientation the whole layout hierarchy has to adjust according to the new mode from an existing mode(from portrait->landscape or vice-versa).This change may remove the previous data that you had in your activity.So to avoid such a problem(loosing data), there is a method
onConfigurationChange(Bundle saveSomething)
This method will be called for you to handle some configuration changes into this,
The default implementation will save you some data like some text in an editText.
Note This method as far the specs goes should be used to save some trivial data.
Example
Suppose you had applied a background colour to the activty layout and now you rotated it default implementation won't save it but onConfigurationChange if you want you can save it like this
saveSomething.putInt("color",1);
Inside onCreate
protected void onCreate(Bundle onSavedInstance){
if(onSavedInstance!=null){
int color=onSavedInstance.getInt("color");
if(color==1){
setBackgroundColor(Color.BLACK);
}
}
}
Add the following line inside the activity element of your manifest file you will be handling the changes in configuration
android:configChanges="keyboardHidden|orientation|screenSize"
I have run into a problem with handling screen orientation changes (For example: portrait to landscape). I'm developing a flashlight app which has a toggle button that turns the LED light on or off on the person's phone. I set up my onPause() method to kill the app like so:
#Override
protected void onPause() {
super.onPause();
finish();
}
This is because if I was to open the app and then go something else (like open youtube) and then come back and press the button again it crashes. But because of this "finish();" thing I can't handle screen orientation changes because apparently when it switches orientation it calls the onPause() method which finishes!
SO my question is...how do I do both? I want to be able to fix the crash problem but also not have it crash when the screen orientation changes. I'm not asking for code (although it would be helpful) just some insight from a new set of eyes.
I thought about using an "if" statement...would this work?
Thanks in advance,
Andrew
When the screen orientation changes, the activity will do onPause(), onStop() and onCreate() again. If you don't want your activity do onPause when the orientation changes, try this:
In your manifest.xml, add android:configChanges="orientation|keyboardHidden" for your activity like:
<activity android:name=".yourname"
android:configChanges="orientation|keyboardHidden">
</activity>
In your activity, override this method:
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
}
But my advice is not to use finish() in onPause(), the system can handle the lifecycle just fine. If you want to finish your activity when the home or back button pressed, try to override onBackPress() and onUserLeaveHint(), these two method can catch back and home button pressed, and add finish() in these two method.
Hope it helps.
Related questions:
https://stackoverflow.com/questions/15648713/strange-behaviour-while-screen-lock-in-landscape
This is a strange behaviour i got in my Activities.
Portrait mode (It's normal)
Press screen lock, Activity: onPause();
Unlock the screen, Activity: onResume().
Landscape mode (It's strange)
Press screen lock, Activity: onPause() -> onStop() -> onDestroy() -> onCreate() -> onStart() -> onResume() which loads the Portrait layout;
Unlock the screen, Activity: onPause() -> onStop() -> onDestroy() -> onCreate() -> onStart() -> onResume() and loads the Landscape layout.
What I expect is:
Portrait mode: (same)
Landscape mode: (should act like Portrait mode)
Press screen lock, Activity: onPause();
Unlock the screen, Activity: onResume().
So my questions:
Why does my Activities behave like this?
How does your Activities behave?
Original text description of my question:
While i press the Lock Screen button of my phone, when my Activity is at its Landscape mode, i noticed (in the debug messages i output to Eclipse) the Activity is re-created to its Portrait mode (while the screen is all black, of course). Then when i press the Lock Screen button again to unlock the screen, the Activity was destroyed and re-created to its Portrait again.
As i remember (not 100% sure though), and what i expect is, my Activity should only undergo onSaveInstanceState() and onPause(), while Lock Screen in Landscape mode, like what it does in Portrait mode. Rather than re-creating the Activity to Portrait and going back to Landscape again.
Is it that i have messed up something with my phone? How can i fix it back to normal?
Thanks!
Thanks everyone for contributing into this issue. Especially thanks #HoanNguyen for his effort of testing for me in his devices. And Especially thanks #Raghunandan for having an in-depth discussion with me concerning this issue.
Summarising everyone's contributions so far, i have the following conclusions:
1. This is a normal phenomenon.
It seems that, on mobile phones, the running Activities, that are in Landscape mode, are switched into Portrait mode upon screen lock is a normal behaviour. At least it is true on the tested phones so far. So we have to make sure our lifecycle functions can take care this change elegantly always.
2. Guess this is because of the "default orientation" in the locked screen.
We do not have documentation or many resource talking about this issue. But the assumption that the running Activities switching back to the device's "default orientation" upon screen lock, as in most devices the locked screen is in Portrait, is quite logical.
Further study:
I just wonder how the Activities behave if we are having a landscape locked screen?
You can stop the activity from restarting on orientation change but this is generally a pretty bad idea.
The Android documentation has a section on handling runtime changes with this note:
Note: Handling the configuration change yourself can make it much more difficult to use alternative resources, because the system does not automatically apply them for you. This technique should be considered a last resort when you must avoid restarts due to a configuration change and is not recommended for most applications.
Android generally only recommends you supress recreating on rotation if you don't need alternate resources and, more importantly, have a performance requirement. A well-designed app shouldn't need to do this in most cases.
If you insist on going down the path of supressing default Android behavior, I'd modify Raghunandan's code and include a screen size attribute as well. As of API level 13, the screen size changes upon orientation change. So you must include screenSize unless you are only targeting API 12 and below.
<activity android:name=".MyActivity"
android:configChanges="orientation|screenSize"
android:label="#string/app_name">
To avoid activity from restarting
<activity android:name=".MyActivity"
android:configChanges="orientation|keyboardHidden"//add tthis in manifest
android:label="#string/app_name">
http://developer.android.com/guide/topics/resources/runtime-changes.html.
In normal circumstances when your screen is locked your activity is paused and when screen is unlocked activity resumes.
An issue when screen locked is: Current Activity may be stopped forcefully by the system if it finds shortage of memory, instead of moving Activity to background. In such a case, we should have to save (all the necessary data) the current state of the Activity.
Save you data in onSaveInstanceState() and restore data onRestoreInstanceState().
#Override
public void onSaveInstanceState(Bundle outState)
{
Log.v("$````$", "In Method: onSaveInstanceState()");
//if necessary,set a flag to check whether we have to restore or not
//handle necessary savings…
}
#Override
public void onRestoreInstanceState(Bundle inState)
{
Log.v("$````$", "In Method: onRestoreInstanceState()");
//if any saved state, restore from it…
}
In your onCreate()
IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_ON);
filter.addAction(Intent.ACTION_SCREEN_OFF);
filter.addAction(Intent.ACTION_USER_PRESENT);
mReceiver = new ScreenReceiver();
registerReceiver(mReceiver, filter); //register
public class ScreenReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent)
{
if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF))
{
Log.v("$$$$$$", "In Method: ACTION_SCREEN_OFF");
// onPause() will be called.
}
else if (intent.getAction().equals(Intent.ACTION_SCREEN_ON))
{
Log.v("$$$$$$", "In Method: ACTION_SCREEN_ON");
//onResume() will be called.
//Better check for whether the screen was already locked
// if locked, do not take any resuming action in onResume()
//Suggest you, not to take any resuming action here.
}
else if(intent.getAction().equals(Intent.ACTION_USER_PRESENT))
{
Log.v("$$$$$$", "In Method: ACTION_USER_PRESENT");
//Handle resuming events
}
}
In your onDestroy
#Override
public void onDestroy()
{
super.onDestroy();
Log.v("$$$$$$", "In Method: onDestroy()");
if (mReceiver != null)
{
unregisterReceiver(mReceiver); //unregister
mReceiver = null;
}
}
I'm developing an app that only some pages can be displayed on landscape orientation, I do not want to lock the screen on display, I wish to deny Android do a orientation change.
There's something that I can use for it? Like, at runtime on orientation change, Android asks if it's possible to go to that orientation?
If there's not, how can I lock the current screen orientation? I know that setRequestedOrientation can do that, but it implies in discover the current orientation (and even discover the correct orientation like 'normal' or 'inverse' portraits/landscapes) and lock to it.
EDIT:
There's only ONE activity on this app, and based on it's state (that changes trough time and user input) it can be rotated or not, that is my problem.
As seen at http://developer.android.com/guide/topics/resources/runtime-changes.html about configuration changes:
"Handle the configuration change yourself
Prevent the system from restarting your activity during certain configuration changes, but receive a callback when the configurations do change, so that you can manually update your activity as necessary."
Even with that the configuration changes, I wish to block this behavior before that.
Add one othese to each activity.
public void checkActivityPos() {
if(somthing == "this") {
myActivity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
}else {
myActivity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
}
}