Hick
Hick

Reputation: 36404

How to save state while using AsyncTask in a service?

I've been using AsyncTask for sometime and the biggest problem I face is that the app crashes a lot and the rendering happens way too many times. For example, If I set the data on a particular layout and render it, and then turn the screen, the entire layout is rendered again with another GET request to the server for data. Didn't care much about it yet, thinking even twitter had the same problem. Seems like they have fixed it.

Thus, how does one use AsyncTask in a service and also have the instancestate which I can refer to, to check when screen is turned or even when the app crashes.

Upvotes: 2

Views: 1429

Answers (1)

Gomoku7
Gomoku7

Reputation: 1372

I did have similar problems with asynctask in an activity : the activity is destroyed on screen rotation and recreated thus recreating the asynctask.

To solve this :

  • easy but not elegant : prevent activity from being destroyed with android:configChanges="orientation" in your manifest for your activity.

  • a bit complex : create a class that stores the current activity controls, save it in onRetainNonConfigurationInstance and restore it in onCreate. When the asynctask is started, instead of talking to the activity directly, it talks to this class that persists through rotation. I can provide some code if you want (it's a bit long).

Edit : Here's some code.

        package com.ybi;

        import android.app.Activity;
        import android.os.AsyncTask;
        import android.os.Bundle;
        import android.widget.TextView;

        public class EmptyShellActivity extends Activity {

            private ActivityControl activityControl;
            private EmptyShellTask emptyShellTask;

            private TextView textView;


            @Override
            protected void onCreate(Bundle savedInstanceState) {
                super.onCreate(savedInstanceState);
                setContentView(R.layout.main);
                textView = (TextView)findViewById(R.id.textView1);
                restoreFromObject();
            }

            @Override
            public Object onRetainNonConfigurationInstance() {
                activityControl.textView = null;
                return activityControl;
            }

            private void restoreFromObject() {
                activityControl = (ActivityControl) getLastNonConfigurationInstance();
                if (activityControl == null) {
                    activityControl = new ActivityControl();
                    activityControl.textView = textView;
                    activityControl.textView.setText("Doing");
                    emptyShellTask = new EmptyShellTask();
                    emptyShellTask.execute((Void[])null);
                } else {
                    activityControl.textView = textView;
                    if (activityControl.isInProgress)
                        activityControl.textView.setText("Doing");
                    else
                        activityControl.textView.setText("Done");
                }
            }

            protected class ActivityControl {
                protected boolean isInProgress;
                protected TextView textView;
            }

            private class EmptyShellTask extends
            AsyncTask<Void, Void, Void> {

                @Override
                protected Void doInBackground(Void... params) {
                    activityControl.isInProgress = true;
                    try {
                            Thread.sleep(3000);
                    } catch (InterruptedException e) {
                        // say something
                    }
                    return null;
                }

                @Override
                protected void onPostExecute(Void result) {
                    super.onPostExecute(result);
                    activityControl.isInProgress = false;
                    activityControl.textView.setText("Done");
                }
            }
        }

I just removed some things from one of my class. I usually use an interface instead of writing code in postExecute. It helps to prevent having pieces of code that do UI things everywhere (like repeating the Done Doing display).

If you want to go further (like progress control, cancel tasks, error management), I ve got interesting piece of code. The only problem is that it becomes rapidly very very complex.

Upvotes: 3

Related Questions