androidperformanceandroid-account

"lead to deadlock" error when doing a certain activity multiple times


I'm testing my app on a device and after doing a certain activity 5 or 6 times, the app crashes with error: java.lang.IllegalStateException: calling this from your main thread can lead to deadlock

The activity is simple: User puts in a task and clicks save. At this time, I get their username and authtoken and make a POST request to my server. I wonder if my app is crashing because each time I am getting the username and authtoken.

The crash is happening in the below code at line new CreateTask.

public boolean onOptionsItemSelected(MenuItem menuItem) {
    if (menuItem.getTitle().toString().equalsIgnoreCase("save")) {
        new CreateTask(this,taskName.getText().toString(), getMyAccount().getUsername(), getMyAccount().getAuthToken()).execute();
        return true;
    }
return true
}

The code for getMyAccount() looks like this:

private MyAccount getMyAccount() {
    MyAccount myAccount = new MyAccount(getApplicationContext());
    return myAccount;
}

And finally the class MyAccount looks like below:

public class MyAccount {
    private static final String TAG = "MyAccount";
    private final Account account;
    private final AccountManager manager;
    private final Context context;
    public MyAccount(final Context context) {
        this.context = context;
        final Account[] accounts = AccountManager.get(context).getAccountsByType("com.myapp");
        account = accounts.length > 0 ? accounts[0] : null;
        manager = AccountManager.get(context);
    }

    public String getPassword() {
        return account!=null? manager.getPassword(account): null;
    }

    public String getUsername() {
        return account!=null? account.name: null;
    }

    public String getAuthToken() {
        if (account != null) {
            AccountManagerFuture<Bundle> future = manager.getAuthToken(account,"com.myapp", false, null, null);
            try {
                Bundle result = future.getResult();
                return result != null ? result.getString(KEY_AUTHTOKEN) : null;
            } catch (AccountsException e) {
                Log.e(TAG, "Auth token lookup failed", e);
                return null;
            } catch (IOException e) {
                Log.e(TAG, "Auth token lookup failed", e);
                return null;
            }
        }
        else
            return null;
    }
}

Question

Is this not a best practice? Is my app crashing because I keep getting the account and authtoken repeatedly? What is a way to avoid this?


Solution

  • Please note this statement in the description for getAuthToken method you are using:

    This method may be called from any thread, but the returned AccountManagerFuture must not be used on the main thread.

    You obviously violate this, as your MyAccount#getAuthToken() is accessing the Future on the main thread : Bundle result = future.getResult();

    I assume that is why you get the exception.

    Hope that helps.