How to close Landscape VideoView Activity properly? - android

In my application, I have an activity play http live streaming video in landscape mode.
My AndroidManifest.xml:
<activity android:name=".MediaPlayerActivity"
android:label="#string/menu_player"
android:launchMode="singleInstance"
android:screenOrientation="landscape">
</activity>
My activity layout:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#color/black">
<VideoView android:id="#+id/myVideoView"
android:layout_height="fill_parent"
android:layout_width="fill_parent"
android:layout_gravity="center_horizontal"
android:layout_alignParentTop="true"
android:layout_alignParentRight="true"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"/>
</LinearLayout>
The problem is everytime I close this activity (By clicking back button), it always rotate to portrait mode (time is very soon but you can actually see the effect on real device before back to the previous activity) before closing. How can I fix this annoying issue?
Update with more info
This annoying behaviour only happened If the previous activity is in portrait mode, if the previous one is landscape, it is just fine. To me it looks like something to do with Android framework when fade in/out activities with different screenOrientation settings.
Update with the cause
After some deep reading through Google's API, I think I found the reason that cause this annoying behaviour, check out here:
Unless you specify otherwise, a configuration change (such as a change in screen orientation, language, input devices, etc) will cause your current activity to be destroyed, going through the normal activity lifecycle process of onPause(), onStop(), and onDestroy() as appropriate. If the activity had been in the foreground or visible to the user, once onDestroy() is called in that instance then a new instance of the activity will be created, with whatever savedInstanceState the previous instance had generated from onSaveInstanceState(Bundle).
So what happened behind the scenes when back button is clicked: currnet VideoView Activity (landscape) is destroyed, a new VideoView Activity (portrait) is created due screenOrientation configuration has been changed, and destoryed immidiately (where you can see the effects on screen), last activity in stack is shown. this also explain why this annoying behaviour disappered if last activity has the same screenOrientation settngs.
I am still trying to figure out how to bypass this activity recreation due to configuration change. As it stated in API, overriding
onConfigurationChanged(Configuration), however, since I explicitly define screenOrientation in xml, onConfigurationChanged() is not called, lots of similiar SO has been discussed before, like this one.
Please provide answer on the right direction.
Thanks,
Y

Try adding calls to VideoView's suspend(), resume() and stopPlayback() in your activity's onPause(), onResume() and onDestroy() methods:
#Override
protected void onResume() {
mVideoView.resume();
super.onResume();
}
#Override
protected void onPause() {
mVideoView.suspend();
super.onPause();
}
#Override
protected void onDestroy() {
mVideoView.stopPlayback();
super.onDestroy();
}
The VideoView class implementation varies from one device to another (and the class itself is very sparsely documented), but the Gallery3D code from AOSP does call the above methods in its MovieView activity lifecycle methods, so hopefully most devices should at least make itself looks good in that scenario.
If it still looks bad, you might want to override onBackPressed() in your activity to maybe hide the VideoView or some similar hacks to conceal the annoying behavior :)

Since your activity isn't always recreated if you close one, It may not execute your manifest code always, tough i'm not sure of this.
But something you could try is setting the orientation manually in onResume:
#Override
protected void onResume()
{
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
super.onResume();
}
this has more on it.

I beleive that a simple solution would to add a field inside your video activity:
boolean isClosing = false;
Set isClosing to true in the onDestroy or, much better, in the onBackPressed (before calling finish())
Now, I supposed you have set onConfigurationChanged to catch orientation changes.
So, in your onConfigurationChanged Encapsulate it with if(!isClosing)
#Override
public void onConfigurationChanged(Configuration newConfig)
{
if(!isClosing){
//YOUR OLD CODE
}
}

You might use a completely different layout for landscape and portrait mode which I recommend, since you use can both differently.
I would recommend the API documentation to this too: http://developer.android.com/guide/topics/manifest/activity-element.html#screen (especially the part about handling savedBundle)

onConfigurationChanged will only be called if you add android:configChanges="orientation" to the activity in the manifest file.
This tells the system that you want to manually handle orientation changes, if you also have android:screenOrientation="landscape", you're also telling the system that the activity should be displayed in landscape mode (they should work together to give you what you want)

Related

Check if application is going to background and close my dialog(if any)

I need to check if my application is going to background due to Home,power or any other event causing the application to go into background. Based on this event I have to close all the dialogs(if shown). My app also support orientation change and I have to retain dialog(if shown) in case of orientation change.
Things I tried: I have tried methods mentioned on the below blogs but it's fails in orientation change.
http://vardhan-justlikethat.blogspot.in/2013/05/android-solution-to-detect-when-android.html
Most of the Stackoverflow suggestion fails on orientation change.
EDIT
More information about my app so that could help.
My activity has Tabs and a container, which get replace with Fragment on tab click. Every fragment has different layout for landscape and portrait. Even the activity layout is different for landscape and portrait.
override your onPause method to insure that any open dialog is closed before it goes to background
#Override
protected void onPause() {
super.onPause();
if (alertDialog != null) {
alertDialog.dismiss();
}
}
On onPause dismiss all your dialogs:
#Override
protected void onPause() {
super.onPause();
if (dialog!= null) {
dialog.dismiss();
}
}
also if you want to handle orientation change then add this line in your activity tag in manifest:
android:configChanges="keyboardHidden|orientation|screenSize"
this will override the default behavior of android's orientation change.

Android WebView re-rendering UI after changing orientation.

In My application i am setting orientation of the application on button click, using setRequestedOrientation(), My application has one webview which displays local web page.
I am using solution as mentioned in below link, to stop reloading of page when orientation changes.
http://www.devahead.com/blog/2012/01/preserving-the-state-of-an-android-webview-on-screen-orientation-change/
Only difference is that i am not having onSaveInstanceState and onRestoreInstanceState in my activity.
What happens in my case is that, my web view does not reload when i change the orientation but it just re-renders the UI upon changing the orientation.
It happens like it first displays the UI and then it displays the white blank screen for few seconds and then again it displays UI.
How can i workaround it?
Once upon a time I used their implementation however I after reading up on the Android documentation I realized that much of their code was pointless since registering for config changes (in the manifest) means that your activity won't be destroyed as it normally is.
Long story short, you don't need to use a FrameLayout as a container for your webView, you may not need onConfigurationChanged, etc. If I get some time I will post some code as an example.
For now, make sure you have the following in your manifest file
android:configChanges="keyboard|keyboardHidden|orientation|screenSize"
instead of
android:configChanges="keyboard|keyboardHidden|orientation"
since on orientation change devices may get get a screenSize change
EDIT This is what I have done (skimmed from one of my projects so I may have missed minor details)
in AndroidManifest.xml
<activity android:name=".Activities.WebWrapperActivity"
android:theme="#android:style/Theme.NoTitleBar"
android:configChanges="keyboard|keyboardHidden|orientation|screenSize"/>
web_wrapper_activity_layout.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<WebView android:id="#+id/web_wrapper_activity_web_view"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:scrollbarStyle="outsideOverlay"/>
</LinearLayout>
The Activity (or a portion of it)
public class WebWrapperActivity extends Activity {
private WebView _webView;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.web_wrapper_activity_layout);
init();
}
private void init() {
_webView = (WebView) findViewById(R.id.web_wrapper_activity_web_view);
_webView.setScrollbarFadingEnabled(true);
_webView.getSettings().setLoadsImagesAutomatically(true);
_webView.getSettings().setJavaScriptEnabled(true);
_webView.getSettings().setAllowFileAccess(true);
_webView.getSettings().setSavePassword(false);
_webView.getSettings().setPluginState(WebSettings.PluginState.ON);
_webView.loadUrl(“http://www.google.com”);
}
#Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
_webView.saveState(outState);
}
}
As i mentioned previously, you may not need onConfigurationChanged if your webView is the only view in the Activity.
If you have any issues let me know

App resets values when I turn device to side

I have an app that adds to a total variable when a button is clicked.
However if I turn my phone so the layout gets turned into the horizontal layout the values all get reset, and idea why this is and how to stop it?
Thanks!
When you move your device, your device's Orientation State changes from Portrait to Landscape of from Lanscape to Portrait.
In this Orientation change, your Activity's onCreate Method is called every time.
Therefore the values in your Activity are being reset.
There are 2 ways of solving this problem:
1) Let You Activity manage it for you.
2) Managing the changes yourself by saving and restoring states.
Using 1st way of solving this problem:
Just add this line in your Activity Node in your Manifest.xml file.
android:configChanges="orientation|keyboardHidden|screenSize"
For example:
<activity
android:name=".MyMainActivity"
android:configChanges="orientation|keyboardHidden|screenSize"
android:label="#string/app_name" >
Using the second Way:
You can override these two Methods:
public void onSaveInstanceState(Bundle bundle) {
super.onSaveInstanceState(bundle);
//Manage your Data Explicitly here.
}
public void onRestoreInstanceState(Bundle bundle) {
super.onRestoreInstanceState(bundle);
//Manage your Data Explicitly here.
}
EDITAccording to Android Dev Guide:
Using android:configChanges="orientation|keyboardHidden|screenSize" is not a good practice.
Quote from this page
Note: Using this attribute should be avoided and used only as a last resort. Please read Handling Runtime Changes for more information about how to properly handle a restart due to a configuration change.
I recommend you to follow the Android Dev Guide for Handling Run-time Changes and follow the good Practices.
you need to save the variable in OnSaveInstanceState and restore it in onRestoreInstnace state
For example;
#Override
public void onSaveInstanceState(Bundle bundle) {
bundle.putParcelableArrayList(PEOPLE, people);
super.onSaveInstanceState(bundle);
}
#Override
public void onRestoreInstanceState(Bundle bundle) {
super.onRestoreInstanceState(bundle);
people = bundle.getParcelableArrayList(PEOPLE);
}
This happens because the normal way Android handles an activity during any configuration change (including screen reorientations) is to destroy the activity and recreate it. As described in the guide topic Handling Runtime Changes, you can handle it a couple of ways. The "Android way" is to save your activity's state information by overriding onSaveInstanceState and onRestoreInstanceState methods. The details about how to use these methods can be found in the guide topic Recreating an Activity.
The other way to prevent this problem is to tell Android that your activity will handle configuration changes internally. You do this by adding android:configChanges="orientation" to the <activity> tag in the manifest for the activity and overriding the onConfigurationChanged method of the activity to actually handle the changes.

Kill an activity when orientation changes

I would like to know if it is possible to ask Android not to reload one Activity when orientation changes (I want to reload others but to kill this one !!).
I have checked the activity properties that I can set in the manifest but no one seems to allow that.
Thanks !
Try this:
public boolean onRetainNonConfigurationInstance() {
return true;
}
public onCreate() {
if(getLastNonConfigurationInstance() != null) {
finish();
}
}
It is simple, in your activity override onConfigurationChanged(Configuration config) and kill the activity inside of that.
Ex:
#Override
public void onConfigurationChanged (Configuration newConfig)
{
super.onConfigurationChanged(newConfig);
finish();
}
This will cause the activity to be killed when a configuration change takes place. In the manifest under config changes select orientation for your activity. You can check which type of orientation it is changing to by looking at newConfig.orientation and compare it to the constants for portrait and landscape in the Configuration class.
I would like to know if it is possible to ask Android not to reload one Activity when orientation changes (I want to reload others but to kill this one !!).
Possible? Sure. A good idea? No. Users will get very confused if a simple twist of their wrist causes the current activity to go away. They might think that your app is broken.
Ideally, you allow users to use your activities in any orientation they desire. It is their device, not yours.
If, for some reason, some activity only makes sense in one orientation (e.g., landscape), use the android:orientation attribute in the <activity> element in the manifest to keep it in that orientation.

Activity lifecycle - onCreate called on every re-orientation

I have a simple activity that loads a bitmap in onCreate. I find that if I rotate the device I can see from the logs that onCreate called again. In fact, because all instance variables are set to default values again I know that the entire Activity has been re-instantiated.
After rotating 2 times I get an FC because not enough memory can be allocated for the bitmap. (Are all instances of the activty still alive somewhere? Or does the GC not clean up fast enough?)
#Override
public void onCreate(Bundle savedInstanceState) {
File externalStorageDir = Environment.getExternalStorageDirectory();
File picturesDir = new File(externalStorageDir, "DCIM/Camera");
File[] files = picturesDir.listFiles(new FilenameFilter(){
public boolean accept(File dir, String name) {
return name.toLowerCase().endsWith(".jpg");
}});
if (files.length > 0) {
Bitmap bm = BitmapFactory.decodeStream(new FileInputStream(files[0]));
ImageView view = (ImageView) findViewById(R.id.photo);
view.setImageBitmap(bm);
}
}
From all that I read, onCreate should be called once during the lifetime of an application. Am I wrong about this? How can re-orienting the device cause the activity to be recreated?
android:configChanges="keyboardHidden|orientation|screenSize"
Caution: Beginning with Android 3.2 (API level 13), the "screen size"
also changes when the device switches between portrait and landscape
orientation. Thus, if you want to prevent runtime restarts due to
orientation change when developing for API level 13 or higher (as
declared by the minSdkVersion and targetSdkVersion attributes), you
must include the "screenSize" value in addition to the "orientation"
value. That is, you must decalare
android:configChanges="orientation|screenSize". However, if your
application targets API level 12 or lower, then your activity always
handles this configuration change itself (this configuration change
does not restart your activity, even when running on an Android 3.2 or
higher device).
From docs: http://developer.android.com/guide/topics/resources/runtime-changes.html
What happen when orientation changed
Life Cycle of orientation
onPause();
onSaveInstanceState();
onStop();
onDestroy();
onCreate();
onStart();
onResume();
---- app recreated and now is running ---
If you do long operation in onCreate() and want prevent re-create your activity add configChanges attribute in your mainfest
<activity android:name=".MyActivity"
android:configChanges="orientation|keyboardHidden|screenSize"
android:label="#string/app_name">
screenSize if you targeting api >= 13
Activity is recreated after each rotation by default. You can override this behaviour with configChanges attribute of the activity tag in AndroidManifest. For further details and different options, see http://developer.android.com/guide/topics/resources/runtime-changes.html
Actvity Lifecycle when you rotate screen
onPause
onSaveInstanceState
onStop
onDestroy
onCreate
onStart
onRestoreInstanceState
onResume
If you want to prevent FC from not enough memory, you need to deallocate resources in onStop() or onPause(). this allows you to use fresh memory in onCreate().
This is an alternate solution to preventing the recreation of the activity by using
android:configChanges="keyboardHidden|orientation"
As sometimes your activity's layout is different in portrait and landscape (layout, layout-land).
preventing recreate on orientation change will prevent your activity from using the other orientation's layout.
Yes, activity's onCreate() is called everytime when the orientation changes but you can avoid the re-creation of Activity by adding configChanges attribute of Activity in your AndroidManifest file in the activity tag.
android:configChanges="keyboardHidden|orientation"
On Create method will call everytime when you do orientation, to avoid this you have to use
//Define Below in you Manifest file.
<activity
android:name="com.ecordia.activities.evidence.MediaAttachmentView"
android:configChanges="keyboardHidden|orientation|screenSize"
</activity>
//Define Below in your activity.
#Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT) {
//your code
} else if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
//your code
}
}
It will works like a charm!!
Manifest XML activity Tag:
android:configChanges="keyboardHidden|orientation"‍‍‍
#Override
public void onConfigurationChanged(Configuration newConfig) {
// TODO Auto-generated method stub
super.onConfigurationChanged(newConfig);
}
Use the above code to perform changes related to orientation in your Activity Java Code
Cheers!!!
One of the most common and suggested “solutions” to dealing with orientation changes is to not deal with them. You can do this by setting the android:configChanges flag on your Activity in AndroidManifest.xml as shown below:
<activity
android:name=".MyActivity"
android:label="#string/title_my_activity"
android:configChanges="orientation|screenSize|keyboardHidden" />
This is NOT the correct way to deal with orientation changes.
CORRECT way is to implement the onSaveInstanceState method (this could be in your Activity, Fragment or both) and place the values you need to save in the Bundle argument that gets passed to the method.
It is nicely described here: http://code.hootsuite.com/orientation-changes-on-android/
While it may seem a bit tedious to implement, handling orientation changes properly provides you with several benefits: you will be able to easily use alternate layouts in portrait and landscape orientations, and you will be able to handle many exceptional states such as low memory situations and interruptions from incoming phone calls without any extra code.
While the Manifest way may work, there is a better and proper solution for these types of problems. The ViewModel class. You should have a look here: https://developer.android.com/topic/libraries/architecture/viewmodel
Basically, you extend the ViewModel class and define all the data members in it which we want to be unchanged over re creation of the activity (in this case orientation change). And provide relevant methods to access those from the Activity class. So when the Activity is re created, the ViewModel object is still there, and so are our data!
Kindly see my way of doing it:-
http://animeshrivastava.blogspot.in/2017/08/activity-lifecycle-oncreate-beating_3.html
snippet is:-
#Override
protected void onSaveInstanceState(Bundle b) {
super.onSaveInstanceState(b);
String str="Screen Change="+String.valueOf(screenChange)+"....";
Toast.makeText(ctx,str+"You are changing orientation...",Toast.LENGTH_SHORT).show();
screenChange=true;
}
#Override
public void onCreate(Bundle b) {
super.onCreate(b);
ctx=getApplicationContext();
if(!screenChange) {
String str="Screen Change="+String.valueOf(screenChange);
// ...
}
}
I had the same problem, in which my onCreate is called multiple times when the screen orientation is changed. My problem got solved when i add android:configChanges="orientation|keyboardHidden|screenSize" in the activity tag in manifest
I had the same problem and I did some workaround
Define didLoad boolean variable with false value
private boolean didLoad = false;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity);
if (!this.didLoad){
// Your code...
this.didLoad = true;
}

Categories

Resources