3

I'm using an ORM for Android called Sugar to persist my models on the database and I'm using it inside my AsyncTask.

Here is its declaration:

public class LoginTask extends AsyncTask<Object, Integer, String> {

    private Context context;
    private ProgressDialog progressDialog;

    public LoginTask(Context context) {
        this.context = context;
    }

    @Override
    protected void onPreExecute() {
        progressDialog = new ProgressDialog(context) {
            {
                setMessage("Authenticating...");
                setTitle("Login");
                setCancelable(false);
                setIndeterminate(true);
                show();
            }
        };
    }

    @Override
    protected String doInBackground(Object... params) {
        String email = (String) params[0];
        String password = (String) params[1];

        try {
            User user = LoginWebService.loginUser(email, password,
                    context);
            user.save();
        } catch (CommunicationException e) {
            e.printStackTrace();
            return e.getMessage();
        }

        return null;
    }

    @Override
    protected void onPostExecute(final String result) {
        progressDialog.dismiss();
    }
}

The line user.save() above, that saves the user model in the db, is the one that causes the exception. The strange thing is that if I declare the task above as an inner class from the activity, it works fine, but if I declare the task on a separate file, it throws this exception:

E/AndroidRuntime(17172):    at com.app.task.LoginTask.doInBackground(LoginTask.java:47)
E/AndroidRuntime(17172):    at com.app.task.LoginTask.doInBackground(LoginTask.java:1)
E/AndroidRuntime(17172):    at android.os.AsyncTask$2.call(AsyncTask.java:264)
E/AndroidRuntime(17172):    at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:305)
E/AndroidRuntime(17172):    ... 5 more
E/AndroidRuntime(17172): Caused by: java.lang.RuntimeException: Cant create handler inside thread that has not called Looper.prepare()

I can't see what makes the difference as I can't see any sense on this.

kaneda
  • 5,981
  • 8
  • 48
  • 73
  • can you post the User.save() method source code? – FoamyGuy Jul 20 '12 at 17:40
  • @Tim, That part of the code is from the ORM, but I can point you to the source code [here](https://github.com/satyan/sugar/blob/master/src/com/orm/SugarRecord.java). You can look after the method save in there. – kaneda Jul 20 '12 at 17:43
  • **"Cant create handler inside thread that has not called Looper.prepare()"** - Agreed with the answer from 10s - this is the sort of error you would see if trying to manipulate an object on the main/UI thread from another thread (such as that of `doInBackground(...)` of an `AsyncTask`). Not sure how this would work as an inner class (as you claim) - it should throw the same exception. Why don't you just return `user` from `doInBackground(...)` and have `onPostExecute(...)` call `user.save()`? – Squonk Jul 20 '12 at 17:53
  • @Squonk That's the strange thing, because It works as an inner class. Actually I'm not manipulating nothing at the UI, I'm just manipulating the db. – kaneda Jul 20 '12 at 17:57
  • @kaneda : Add another `catch` block for `(Exception e)` with a call to `e.printStackTrace()`. I can't see anything in the `Sugar` source you linked to which explains this - not sure if a `catch` for `Exception` will explain it any further but it might be worth a try. – Squonk Jul 20 '12 at 18:08
  • @Squonk did it with no luck. It gives me an ANR before throwing an Exception. – kaneda Jul 20 '12 at 18:25
  • @kaneda : If you're getting an ANR then something is blocking the main thread. – Squonk Jul 20 '12 at 20:40

3 Answers3

3

You are trying to access/update the UI from a background thread. The exception that is thrown in the last sentence of log cat indicates "these" kind of interactions. This would also crash if it was an inner class of an activity.

The proof is that you are passing the context. Another question because that might the problem too. This is the context of the activity or the context of the AsyncTask? What context does it require?

10s
  • 1,699
  • 1
  • 12
  • 14
  • the context that is being passed is the context of the Activity. I'm only passing it because I need it in order to get into the db. I'm not using to touch the UI. – kaneda Jul 20 '12 at 18:00
  • Do you open multiple threads that execute this AsyncTask? And most importantly do you have a `preExecute()` or `onPostExecute()` there? – 10s Jul 20 '12 at 18:06
  • Please look at the updated code I edited above with both methods. – kaneda Jul 20 '12 at 18:16
  • is progress dialog shown? Do you do anything with the orientation? Like changing midways? I would also like to see where is the part that executes the AsyncTask from the Activity. – 10s Jul 20 '12 at 18:41
  • As 10s has stated, you are trying to update the UI from a background thread, possibly due to the db being reference from there. This is due to you passing the context of the activity to the background thread as opposed to the Activity itself, as explained comprehensively [here](http://256design.com/blog/android-login-asynctask/). Having passed the Activity, you are now able to call the Activity methods from the postExecute method on the background thread. – ramizmoh Jun 13 '13 at 13:47
0

I see that this is a very old thread but I would like to put in some efforts to answer this for those who are referring to this in future.

I had a similar problem and the below steps fixed the issue.

You can avoid or workaround this by appropriately setting,

<meta-data android:name="DOMAIN_PACKAGE_NAME" android:value="com.example" />
in your AndroidManifest.xml

It has been mentioned in the original guide that these parameters are all optional but without this parameter set, you may encounter the above exception.

I have also opened an issue on the main repo requesting to update the guide here

Praveen
  • 393
  • 4
  • 10
0

Are you using version 1.3?

I'm using version 1.3 not using DOMAIN_PACKAGE_NAME in my manifest and do the same thing inside an AsyncTask, actually i'm doing a lot of database work inside AsyncTask with a ProgressDialog...

If you want to stress out some things, my application tag in my manifest has the android:persistent="true" tag add.

Also my main activity has the android:launchMode="singleTask", but im also calling some AsyncTask from others Activity's.

rdenadai
  • 433
  • 2
  • 10