How to get rid of java.lang.IllegalStateException while trying to getAuthToken from Account

5.4k views Asked by At

I am trying to get the authToken for an account but getting this error:

java.lang.IllegalStateException: calling this from your main thread can lead to deadlock

This is how I'm getting the AuthToken:

public class MyAccount {
 private final Account account;
 private final AccountManager manager;
 private final Context context;

 public MyAccount (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 getAuthToken() {
        @SuppressWarnings("deprecation")
        AccountManagerFuture<Bundle> future = manager.getAuthToken(account,"com.myapp", false, null, null);

        try {
            //GETTING EXCEPTION HERE
            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;
        }
    }
}

I'm calling this from my MainActivity like this:

 MyAccount account = new MyAccount(getApplicationContext());
 String authtoken = account.getAuthToken());

Question

How can I call MyAccount to get the authToken and get rid of the exception?

2

There are 2 answers

0
petey On BEST ANSWER

USe an AsyncTask so that this work may be completed in a background thread (doInBackground)

private class FooTask extends AsyncTask<Void, Void, String>{
    /**
     * Override this method to perform a computation on a background thread. The
     * specified parameters are the parameters passed to {@link #execute}
     * by the caller of this task.
     *
     * This method can call {@link #publishProgress} to publish updates
     * on the UI thread.
     *
     * @param params The parameters of the task.
     *
     * @return A result, defined by the subclass of this task.
     *
     * @see #onPreExecute()
     * @see #onPostExecute
     * @see #publishProgress
     */
    @Override
    protected String doInBackground(Void... params) {
        MyAccount account = new MyAccount(getApplicationContext());
        String authtoken = account.getAuthToken());
        return authtoken;
    }

    /**
     * <p>Runs on the UI thread after {@link #doInBackground}. The
     * specified result is the value returned by {@link #doInBackground}.</p>
     *
     * <p>This method won't be invoked if the task was cancelled.</p>
     *
     * @param result The result of the operation computed by {@link #doInBackground}.
     *
     * @see #onPreExecute
     * @see #doInBackground
     * @see #onCancelled(Object)
     */
    @Override
    protected void onPostExecute(String token) {
        if (token != null){
            //use token here
        }
    }
}

Usage : new FooTask().execute();

0
gaurav5430 On

from

"Calling this from your main thread can lead to deadlock and/or ANRs while getting accesToken" from GoogleAuthUtil(Google Plus integration in Android)

Try it with an AsyncTask like this:

        AsyncTask<Void, Void, String> task = new AsyncTask<Void, Void, String>() {
            @Override
            protected String doInBackground(Void... params) {
                String token = null;

                try {
                    token = GoogleAuthUtil.getToken(
                            MainActivity.this,
                            mPlusClient.getAccountName(),
                            "oauth2:" + SCOPES);
                } catch (IOException transientEx) {
                    // Network or server error, try later
                    Log.e(TAG, transientEx.toString());
                } catch (UserRecoverableAuthException e) {
                    // Recover (with e.getIntent())
                    Log.e(TAG, e.toString());
                    Intent recover = e.getIntent();
                    startActivityForResult(recover, REQUEST_CODE_TOKEN_AUTH);
                } catch (GoogleAuthException authEx) {
                    // The call is not ever expected to succeed
                    // assuming you have already verified that 
                    // Google Play services is installed.
                    Log.e(TAG, authEx.toString());
                }

                return token;
            }

            @Override
            protected void onPostExecute(String token) {
                Log.i(TAG, "Access token retrieved:" + token);
            }