0

I am trying to develop a simple chat application, only for study purpose. My problem is that when the screen orientation is changing the TCP/IP connection is closed and recreated after orientation changes.

I know that Android destroys the activity and recreates it when changing orientation.

So my question: It is posible to change only view but everything else to remain intact?

Thanks

Catalin
  • 752
  • 1
  • 16
  • 32
  • Possibility: http://stackoverflow.com/questions/4584015/handle-screen-orientation-changes-when-there-are-asynctasks-running – EGHDK Jul 13 '12 at 20:15

5 Answers5

3

You should implement your TCP/IP communications as Service and then it will not depend on any orientation change/other recreating of your activity.

Prizoff
  • 4,486
  • 4
  • 41
  • 69
2

You want to read the section called Handling the Configuration Change Yourself in the Handling Runtime Changes document. In short, you tell it you will handle them manually by adding android:configChanges="orientation|keyboardHidden" to your Activity decleration in your AndroidManifest. Here is an example:

<activity android:name=".MyActivity"
          android:configChanges="orientation|keyboardHidden"
          android:label="@string/app_name">

And then in your Activity you override onConfigurationChanged like this:

@Override
public void onConfigurationChanged(Configuration newConfig) {
    super.onConfigurationChanged(newConfig);

    // Checks the orientation of the screen
    if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
        Toast.makeText(this, "landscape", Toast.LENGTH_SHORT).show();
    } else if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT){
        Toast.makeText(this, "portrait", Toast.LENGTH_SHORT).show();
    }
}
Alex Lockwood
  • 83,063
  • 39
  • 206
  • 250
Salil Pandit
  • 1,498
  • 10
  • 13
  • OK... but what if the user puts the phone in a dock? Or what if the user changes the locale? This will cause the `Activity` to be destroyed/recreated just the same. Now what? – Alex Lockwood Jul 13 '12 at 20:20
1

You can either make your connection static and not recreate it when it is != null, or even better you wrap it into a separate class that uses the singleton pattern

Alex Lockwood
  • 83,063
  • 39
  • 206
  • 250
SimonSays
  • 10,867
  • 7
  • 44
  • 59
  • why would it do that? just the tcp connection has to be static and is therefore created just once. – SimonSays Jul 13 '12 at 20:21
  • that is why you use the application context and not the activity itself whenever possible... – SimonSays Jul 13 '12 at 20:27
  • this was a general comment. it is clear to me to use the application context for database connections for example so no activities can leak. but i anyways do not see why a activity would leak in this case, because no context is required to open a socket connection: sSocket = new Socket(hostAddr, servPort); – SimonSays Jul 13 '12 at 20:42
  • I like the application context as a holder for objects but keep in mind that you might not be using the TCP connection instance during the whole life of your application. Service would definitely be a better choice. – Igor Čordaš Jun 19 '14 at 15:19
1

Just don't create the connection from the activity. You can use Application instead:

in your manifest:

<application
        android:name=".MyApplication" ...>

It will be created once, and live throughout the whole life of your application, even when activities are destroyed.

Other alternative is a Service. For a chat application I would use that, since it seperates the background network work from the UI completely.

Amir Uval
  • 14,425
  • 4
  • 50
  • 74
  • 1
    Just a little caution: In some testing I'm doing on a current application, I'm finding that the `Application` instance is often killed (and soon after created again) even when the `Activity` stack remains. This is of course when the phone is left for a long period with the `Activity` stack in the background. Therefore the point I'd make from my experiences is that `Activity` classes should always check that "global" references you've stored in `Application` are still actually there, and be prepared to create them again if not. – Trevor Jul 13 '12 at 20:43
  • What you describe should never happen. When an Application is killed (which often happens), the activities belonging to it *must* be killed too by the system. Did you look for memory leaks in your app, keeping zombie activities around? – Amir Uval Jul 14 '12 at 08:31
  • Agreed - it was unexpected. This occurs on my HTC One X, which on XDADevs is known for running low on memory, sometimes even killing the launcher. My app's `Application` is typically recreated when the phone is left for an hour or overnight with activity stack in background. On resuming, the topmost `Activity` resumes, but `Application` is new instance. I have a `Toast` that tells me when `Application` has been re-initialised, and I occasionally see the system kill and then recreate the `Application` for my app in the background, while I'm doing something else (e.g. web browsing). [TBC] – Trevor Jul 14 '12 at 09:01
  • In terms of memory leaks, I *think* it's okay. I have extensively tested by rotating orientation, and discovered and eliminated leaks this way. The `Application` class holds a lot of "singleton" data. Now, on resuming, all my `Activity` classes *must* check `Application` "global" structures exist, and trigger their recreation if not. In fact I notice a few apps (not my own) that appear to lose state when their stack is resumed on my HTC One X, if some time passed since their last use (DI FM Radio app being an example). I ought to create a separate Stackoverflow question for this I think. – Trevor Jul 14 '12 at 09:11
  • Wow, that looks like a major flaw in HTC One X, I wonder how they've passed CTS (if there are tests covering this scenario). Google should have been more strict about approving ports. – Amir Uval Jul 14 '12 at 10:07
1

Well, the real issue here is that you are performing the TCP/IP connection on the main UI thread, which is a terrible idea because you risk blocking touch events and the layouts from being generated. A NetworkOnMainThreadException is thrown on most new devices these days to prevent this behavior too.

What I would do is wrap the TCP/IP connection in a Thread, and then have the Thread execute in a worker (non-UI, invisible) Fragment with setRetainInstance(true). This protect your Thread on configuration changes, as the Fragment will remain in memory even when the Activity is destroyed. You can read more about this approach here.

If the TCP/IP connection needs to exist across multiple Activity instances, you should use a Service instead.

Alex Lockwood
  • 83,063
  • 39
  • 206
  • 250
  • I would advise not using a AsyncTask for the TCP Connection, what if the user wishes to use the AsyncTask for other purposes? – basickarl Dec 01 '13 at 16:12
  • @KarlMorrison AsyncTasks should be used for short tasks (3-4 seconds). If the TCP connection needs to persist over a long period of time, then it would be better to use a service. I'm not sure what you mean by "what if the user wishes to use `AsyncTask` for other purposes. – Alex Lockwood Dec 01 '13 at 16:59
  • I think what @Karl Morrison is referring to is the pool limit for async tasks. In newer android versions they are essentially serially executed unless you specify parallel execution. On older versions you never know, usually you can run two in parallel. As you mentioned it's ok to run a short task like this even if using TCP connection in them but if you want to create something like a chat or sending game moves you should really create a service with a worker thread. – Igor Čordaš Jun 19 '14 at 15:13
  • @PSIXO I've edited my answer assuming the TCP connection will last longer than a few seconds. `AsyncTask`s are good for short-lived async computations, but if you need to persist a TCP connection for longer than that, it is better to use a retained `Fragment` or a `Service`. – Alex Lockwood Aug 17 '14 at 20:51