2

First of all I already read about all this discussion that it isn't a good idea to manually exit an Android application. But in my case it seems to be needed. I have an AsyncTask which does a lot of operations in background. That means downloading data, saving it to local storage and preparing it for usage in application. It could happen that there is no internet connection or something different happens. For all that cases I have an Exception handling which returns the result. And if there is an exception, the application is unusable so I need to exit it. My question is, do I have to do some unregistration unloading or unbinding tasks or something when I exit the application by code or is System.exit(0) ok? I do all this in an AsyncTask, see my example:

public class InitializationTask extends AsyncTask<Void, Void, InitializationResult> {
    private ProcessController processController = new ProcessController();
    private ProgressDialog progressDialog;
    private Activity mainActivity;

    public InitializationTask(Activity mainActivity) {
        this.mainActivity = mainActivity;
    }

    @Override
    protected void onPreExecute() {
        super.onPreExecute();

        progressDialog = new ProgressDialog(mainActivity);
        progressDialog.setMessage("Die Daten werden aufbereitet.\nBitte warten...");
        progressDialog.setIndeterminate(true); //means that the "loading amount" is not measured.
        progressDialog.setCancelable(false);
        progressDialog.show();
    };

    @Override
    protected InitializationResult doInBackground(Void... params) {
        return processController.initializeData();
    }

    @Override
    protected void onPostExecute(InitializationResult result) {
        super.onPostExecute(result);

        progressDialog.dismiss();

        if (!result.isValid())  {
            AlertDialog.Builder dialog = new AlertDialog.Builder(mainActivity);
            dialog.setTitle("Initialisierungsfehler");
            dialog.setMessage(result.getReason());
            dialog.setPositiveButton("Ok",
                    new DialogInterface.OnClickListener() {

                        @Override
                        public void onClick(DialogInterface dialog, int which) {
                            dialog.cancel();

                            //TODO cancel application
                            System.exit(0);
                        }
                    });

            dialog.show();
        }
    }
}
Bevor
  • 8,396
  • 15
  • 77
  • 141
  • "But in my case it seems to be needed" -- no it isn't. "And if there is an exception, the application is unusable so I need to exit it" -- no, you need to gracefully handle the error, then return the app to its original state. – CommonsWare Nov 11 '12 at 12:39
  • 1
    @CommonsWare Tell me how you would design this: My data initialization of ten thousands of Geolocation coordinates takes about 20 seconds, so when the application starts, meanwhile the Google Maps is shown with a progress bar until the init. is finished. If something happens within this initialization, the only thing the application does is to display Google Maps without data. If I restart it from menu, I would get the empty Map again. I could shift the AsyncTask which does the initialization to onStart or onResume, so I don't need to kill the application. Is this good design then? – Bevor Nov 11 '12 at 12:49
  • "If I restart it from menu, I would get the empty Map again" -- if the user chooses to "restart it from menu", you can determine that the initialization did not occur and try running it again. – CommonsWare Nov 11 '12 at 12:53
  • 1
    @CommonsWare Ok, I understand now why finish works: I didn't know that onCreate will be executed again when executing finish() before. My "ProcessController" can deal with all that behavior stuff (when it's not prefilled, not downloaded, not savable etc), so finish() can work for me. – Bevor Nov 11 '12 at 13:03

2 Answers2

3

Well, you've already mentioned that is not a good idea to close Android application.

You really should not ever use System.exit()! If you need it, then something is seriously wrong with the architecture of your app. For example you can have a special screen dedicated to these "no connectivity" states.

Solution to handling such "no data" states could be to close the activity (or all the activities) by calling finish (this is perfectly fine). Before finishing an activity, you should do the clean up: cancel the tasks, unregister receivers, etc. Now the application is still alive, but you have to leave it up to the system to kill it. Killing it is contrary to how Android work.

Tomik
  • 23,857
  • 8
  • 121
  • 100
  • I need some gelocation data displayed on a MapView. If I would do finish() at error and start the app from and Android menu, I have the same error state as before: An empty Map without data. If that's the Android way, then it is a wrong my in my opinion. – Bevor Nov 11 '12 at 12:00
  • 1
    Yes, the app should handle these problematic states and inform the user in some way that something is necessary (e.g. network connection). And in this case when you restart the app from Android menu, you should requery the data you want to display. The clean-up made upon finishing the activity should ensure that your app keeps only the "good data". The "problematic data" that caused the activity being finished should be renewed. – Tomik Nov 11 '12 at 12:23
  • Yes, I indeed inform the user, that's why I have this InitializationResult. If the connection to my server is down (and not the connection on the phone is not working) to not be able to get the data or something, I have to re-initialize the whole initialization process. And this is only possible when I restart the AsyncTask which is done in onCreate() since it is proposed to do all initialization stuff there. I could shift the AsyncTask invocation to onStart() but this seems to be much falser to me. – Bevor Nov 11 '12 at 12:39
  • 2
    @Bevor: "And this is only possible when I restart the AsyncTask which is done in onCreate() since it is proposed to do all initialization stuff there" -- or, you move your initialization code into a separate method, that you call from `onCreate()` and other places as needed. – CommonsWare Nov 11 '12 at 12:41
  • @CommonsWare if this is good design, I have no problem to do that, but the documentation says to onCreate(): `Called when the activity is first created. This is where you should do all of your normal static set up: create views, bind data to lists, etc.` So what is falser now: To not do initialization stuff in onCreate or to invoke System.exit? – Bevor Nov 11 '12 at 12:53
  • @Bevor: If you finish an activity and start it again later, the `onCreate()` callback is called again. – Tomik Nov 11 '12 at 12:54
  • @Tomik Ok thanks, that explains it, so this solution with finish works. – Bevor Nov 11 '12 at 13:02
1

While technically, using System.exit would work (the OS will take care of cleaning up the process), you shouldn't be using it.

I would re-consider the approach you're taking. The proper way to handle errors in tasks is to propagate the error to the Activity running the task, where it can be handled, and then just finish() the activity if such an error is detected. This allows you to present a message to the user informing them of the error before the app (or top-most activity) closes.

Dia Kharrat
  • 5,948
  • 3
  • 32
  • 43
  • It's indeed internally propagated to the (Main) Activity running the task. And as you can see, I display a dialog in onPostExecute with the error result. – Bevor Nov 11 '12 at 12:08
  • by the way: I can't use finish since it would restore the "error state" if I would relaunch the application. So finish() can not be a solution. – Bevor Nov 11 '12 at 12:10
  • @Dia: Android engineers have said not to use `System.exit()` or the equivalent: http://stackoverflow.com/a/2043302/115145 https://groups.google.com/group/android-developers/msg/0a6b63d6751dc12b https://groups.google.com/group/android-developers/msg/7d28a46ec9105626 – CommonsWare Nov 11 '12 at 12:54