34

I was going through various practices to handle orientation change with threads and AsyncTask. I came across following solutions:

  1. Attach-detach model : Attaching and detaching activity to threads and AsyncTask while preserving their instance. (Source: 1, 2)

  2. Headless fragment way : Using a non-UI/headless fragment to do all the thread related operations and retaining its instance on configuration change. (Source: 1, 2)

Are there any other approaches to handle this scenario? What is the recommended practice? I'm asking this because I couldn't find a generic solution anywhere in the Android docs.

Community
  • 1
  • 1
Gaurav Arora
  • 17,124
  • 5
  • 33
  • 44
  • you wont find anything better than whatever proposed by @vogella or CommonsWare. What they say is almost the generic android solution. – Carlos Robles Dec 17 '13 at 23:41

6 Answers6

43

Some summaries

There are several methods mentioned above that are good practices but I thought I might sum them up with short explanations. Below are some of the most popular libraries being used currently for http networking, asynchronous work / threading, and caching.

My current project (just preferences)

I personally am currently using Otto, Loaders, Volley, Ormlite, and a network stack based on Apache and Services. I do hope to replace, the network stack at some point with either Volley, Retrofit, and maybe eventually Robospice.

I personally very much like Otto and Volley


RoboSpice (Modular)

  • https://github.com/octo-online/robospice
  • http://www.youtube.com/watch?v=ONaD1mB8r-A
  • a plugin / modular approach to long-running tasks
  • this is like the "swiss-army-knife" of libraries, but you need to know what each tool does.
  • Handles REST calls
  • persists data through orientation and other changes
  • can handle disk and memory caching )
  • works with various HTTP libraries and persistence libraries (Gson, Jackson, Spring, OkHttp, and many of the below libraries)
  • beta for Ormlite support, I think

Retrofit (REST)

Volley (Networking data & Images)

Picasso (images)

Loaders (Android)

  • well supported
  • persist through orientation change and save/load of fragment state
  • can be difficult to get right
  • no caching

AsyncTask (Android)

  • simple way for background work from the UI thread
  • must be canceled and be careful about tasks that return after an activity or fragment is torn down.

Otto (event bus)

  • https://github.com/square/otto
  • Event bus that makes a-sync work between components and fragments easy
  • Very powerful @Produce ability retains the last event and can produce it on demand for any new interested subscribers to the bus

Headless Fragments (?)

  • I personally have never seen this used other than Vogella's tutorials, so I'm not sure on this one.

Service (Android)

  • The old school way
  • ultimate control, you must do everything yourself
  • usually used with Appache or HURL client and
  • pass Parcels around via Intents
pjco
  • 3,826
  • 25
  • 25
7

Why don't you try Loaders, in particular AsyncTaskLoader? They are available for pre-Honeycomb through Support Library and perfectly match Activity/Fragment lifecycle. Here is the official summary:

  • They are available to every Activity and Fragment.
  • They provide asynchronous loading of data.
  • They monitor the source of their data and deliver new results when the content changes.
  • They automatically reconnect to the last loader's cursor when being recreated after a configuration change. Thus, they don't need to re-query their data.
a.ch.
  • 8,285
  • 5
  • 40
  • 53
4

We are actually using RoboSpice library. It runs on a Service with only providing RequestListeners objects.

The problem with your first approach (Keeping references between the AsyncTask) is that you can probably generate memory leaks because when your AsyncTasks holds your Activities references, they will be not garbage collected. Keep an eye on this just profiling your application checking Heap Size rotating the same Activity over and over again. Your heap should grow in the normal parameters (There is a moment when your objects that must be garbage collected lives at the same time with new objects) but when GC runs your RAM allocation should fall to the same size that you've allocated at the beginning.

So if I have to recommend something will be the next thing:

Activity managing API Calls and Flows (With RoboSpice, letting de UI rotate) Simple screens inside Fragments using retainInstance in true. This let to you pass your DTOs directly to your fragments, and you have to only manage the state at the top level Activity.

noni
  • 2,927
  • 19
  • 18
3

If handling asyncTask is your main concern i.e not willing to download data each time orientation is changed then you may try like this --

(1) Initialize any value before on create like this ..

Boolean android_hacker = false;

(2) Now when you are done with downloading data on AsyncTask class then set that value to true

android_hacker = true;

Here maintain all data utilizing model and Array adapter class

(3) Now each time orientation is changed then check like this

if( android_hacker = true ){

// Use your saved instance ..

}else{

// Download data as it is yet not downloaded ..

}

Hope it helps ..

AndroidHacker
  • 3,596
  • 1
  • 25
  • 45
  • 1
    I was looking for a framework or a good practice. I don't see it as any of them. Thanks for replying though ! – Gaurav Arora Dec 18 '13 at 06:43
  • I faced problem in fragments where each time data was downloaded. Same thing exits while changing orientation. I solved that issue using this logic only. – AndroidHacker Dec 18 '13 at 07:19
2

There are many ways you can try beside the AsyncTask. And if you try to find a best practice, AsyncTask isn't a good option. This answer explains why you should not use AsyncTask. And they recommend you using a better way which can deal with long running task, RoboSpice.
I have already used this library and I think it is worthy to try: respect activities lifecycles (orientation change), no memory leaks, supports multi-threading, caches results... It can plug and unplug long request task by using cache (but it can't work well for a non-cache request).

But I recommend a good way comes from Google: IntentService and BroadcastReceiver. You will registered and unregistered broadcast during orientation change to receive the data result. All background task will work in IntentService and notify whatever you want to activity by BroadcastReceiver. There are a lots of example that you can try. Something like this: http://mobile.tutsplus.com/tutorials/android/android-fundamentals-intentservice-basics/

Update:

Hi R4j, the point is my application is quiet complex. And I've to make number of parallel network calls. Your approach with IntentService is good but isn't suitable for complex scenarios

I don't think this is a problem. You can do anything with the IntentService, even the complicated tasks. If you want parallel tasks, you may consider a Service with multithreading in it and communicate with activity by Intent. Sending intent between Service and activity is safe and flexible, that is Android way.
And if you want to cache (by file download, stream, by database..) RoboSpice is a best choice for you

Community
  • 1
  • 1
ductran
  • 10,043
  • 19
  • 82
  • 165
  • Hi R4j, the point is my application is quiet complex. And I've to make number of parallel network calls. Your approach with IntentService is good but isn't suitable for complex scenarios. – Gaurav Arora Dec 18 '13 at 06:46
  • You can use a regular `Service` for multiple threads, `IntentService` is just s specialized `Service` with a single background worker thread already created for you. – pjco Dec 19 '13 at 05:03
  • @pjco Yeah, I know it. But you can use the `IntentService` with multithreading too, (like create new thread in `onHandleIntent`) to receive and execute many tasks sending from activity. – ductran Dec 19 '13 at 05:52
  • No, you can't (or shouldn't). Creating threads in an `IntentService` is NOT a good idea. `onHandleIntent` is already called from the worker thread created by the IntentService. `onHandleIntent` creates a sequential blocking work queue. If you need 2 background worker threads, using an IntentService would create 3 threads and put you in shaky ground about when those threads are alive. `IntentService` is very nice, but using it to start threads is pushing it beyond what it was intended for. If you need that kind of concurrency you should use a regular service with a `ThreadPoolExecutor` – pjco Dec 20 '13 at 00:38
  • 1
    Thanks, I got it, and I updated my answer. Actually, I prefer Service to IntentService because its flexibility. I don't like the worker thread queue inside IntentService because I can't control how many tasks can execute at the same time. – ductran Dec 20 '13 at 03:55
-3

You can try with the following approaches:

1) If your application does not explicitly require any orientation changes, just disable orientation changes at the beginning of app execution, thereby you would be avoiding any crashes or related problems with respect to orientation changes.

This you can do using the following line in the outermost layout of your layout xml file:

  android:orientation="vertical"

(for setting vertical orientation)

2) You can set or preserve previous orientation values at the beginning of your thread execution using Asynctask, as follows (syntax example only):

  setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);

and

  getResources().getConfiguration().orientation
SoulRayder
  • 5,072
  • 6
  • 47
  • 93
  • Reason for downvote? These two approaches have helped me get over my problems when I was coding. Please tell me if there is a better way. – SoulRayder Dec 11 '13 at 10:06
  • 3
    By locking the orientation, you stop the normal behavior in android. Users may want to change orientation to get the comfortable UI for them (even during execute task). And your answer isn't really deal with the orientation change as `gauravsapiens` wants. P/s: the down vote isn't mine. – ductran Dec 14 '13 at 16:49
  • 4
    You're also overlooking the fact that tablets are often used in landscape view. – radley Jul 18 '14 at 17:46