9

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

Community
  • 1
  • 1
yorkw
  • 40,926
  • 10
  • 117
  • 130
  • I have no clue if this is right b/c I haven't run into the issue.. did you consider overriding the back button and attempting to finish() when pressed (at least that's the first thing I'd try). – DJPlayer Oct 27 '11 at 00:18
  • Just tried, same behaviour, BTW, I am using galaxy s2, I doubt that is device related. – yorkw Oct 27 '11 at 00:40

5 Answers5

17

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 :)

Joe
  • 14,039
  • 2
  • 39
  • 49
  • Works like a charm, though I haven't fully understood the magic behind the code, I will have a further study once I got time. Thanks:) – yorkw Nov 04 '11 at 11:21
2

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.

user717572
  • 3,626
  • 7
  • 35
  • 60
  • I don't quite understand what you mean. I don't see any points where overriding onResume can help with this issue. Any way, I've tried what you suggested, same behavior. – yorkw Oct 30 '11 at 01:55
1

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
  }
}
Sherif elKhatib
  • 45,786
  • 16
  • 89
  • 106
  • onConfigurationChanged() doesn't get called with the explicitly defined screenOrientation in xml, I need fix this first. Also, from my point of view, the problem is not related to how the activity is destroyed/finished/closed, it is about how to bypass/avoid the activity recreation due to config change. – yorkw Nov 04 '11 at 00:39
  • can you try something please? just add in `onDestroy` `isClosing=true` and add `if(isClosing) finish()` in the top of `onCreate`. I hope you understood. I know this will create some other problems but please check if this resolves the issue. – Sherif elKhatib Nov 04 '11 at 09:55
  • I tried both yours and Joseph's, His anwser works for me, the activity life cycle I described in the question is not quite correct, I am gonna have a further study on this once I got time. – yorkw Nov 04 '11 at 11:18
0

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)

Kibotu
  • 173
  • 8
0

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)

FunkTheMonk
  • 10,908
  • 1
  • 31
  • 37
  • Yes, I can understand the API. You just describe the problem one more time. if you define both android:configChanges and android:screenOrientation, onConfigurationChanged() doesn't get called. search "onConfigurationChanged() not called" on SO, you can find pages of threads discuss this. well the answer is not use android:screenOrientation, however, this is not an option for me. – yorkw Nov 04 '11 at 09:49
  • Sorry, you didn't mention that you're already using configChanges, and I've used it to resolve similar issues when opening a hardware keyboard to awaken a device (causing the device to be woken in landscape when the app was supposed to be portrait). – FunkTheMonk Nov 04 '11 at 10:19