androidandroid-asynctaskoauth-2.0tokenthread-exceptions

Method to AsyncTask Android OAuth2Client


I am trying to use this code:

public static Token getAccessToken(OAuth2Config oauthDetails) {
    HttpPost post = new HttpPost(oauthDetails.getTokenEndPointUrl());
    String clientId = oauthDetails.getClientId();
    String clientSecret = oauthDetails.getClientSecret();
    String scope = oauthDetails.getScope();
    List<BasicNameValuePair> parametersBody = new ArrayList<BasicNameValuePair>();
    parametersBody.add(new BasicNameValuePair(OAuthConstants.GRANT_TYPE,
            oauthDetails.getGrantType()));
    parametersBody.add(new BasicNameValuePair(OAuthConstants.USERNAME,
            oauthDetails.getUsername()));
    parametersBody.add(new BasicNameValuePair(OAuthConstants.PASSWORD,
            oauthDetails.getPassword()));
    if (isValid(clientId)) {
        parametersBody.add(new BasicNameValuePair(OAuthConstants.CLIENT_ID,
                clientId));
    }
    if (isValid(clientSecret)) {
        parametersBody.add(new BasicNameValuePair(
                OAuthConstants.CLIENT_SECRET, clientSecret));
    }
    if (isValid(scope)) {
        parametersBody.add(new BasicNameValuePair(OAuthConstants.SCOPE,
                scope));
    }
    DefaultHttpClient client = new DefaultHttpClient();
    HttpResponse response = null;
    Token accessToken = null;
    try {
        post.setEntity(new UrlEncodedFormEntity(parametersBody, HTTP.UTF_8));
        response = client.execute(post);
        int code = response.getStatusLine().getStatusCode();
        if (code >= 400) {
            Log.d(TAG, "Authorization server expects Basic authentication");
                // Add Basic Authorization header
            post.addHeader(
                    OAuthConstants.AUTHORIZATION,
                    getBasicAuthorizationHeader(oauthDetails.getUsername(),
                            oauthDetails.getPassword()));
            Log.d(TAG, "Retry with login credentials");
            try {
                response.getEntity().consumeContent();
            } catch (IOException e) {
                    // TODO Auto-generated catch block
                e.printStackTrace();
            }
            response = client.execute(post);
            code = response.getStatusLine().getStatusCode();
            if (code >= 400) {
                Log.d(TAG, "Retry with client credentials");
                post.removeHeaders(OAuthConstants.AUTHORIZATION);
                post.addHeader(
                        OAuthConstants.AUTHORIZATION,
                        getBasicAuthorizationHeader(
                                oauthDetails.getClientId(),
                                oauthDetails.getClientSecret()));
                try {
                    response.getEntity().consumeContent();
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                response = client.execute(post);
                code = response.getStatusLine().getStatusCode();
                if (code >= 400) {
                    throw new RuntimeException(
                            "Could not retrieve access token for user: "
                                    + oauthDetails.getUsername());
                }
            }
        }
        Map map = handleResponse(response);
        accessToken = new Token(Long.valueOf((Integer) map.get(OAuthConstants.EXPIRES_IN)), (String) map.get(OAuthConstants.TOKEN_TYPE), (String) map.get(OAuthConstants.REFRESH_TOKEN), (String) map.get(OAuthConstants.ACCESS_TOKEN));
    } catch (ClientProtocolException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (IOException e) {
           // TODO Auto-generated catch block
        e.printStackTrace();
    }
    return accessToken;
}

Is part of an OAuth2Client that i am using in my Android app. I am getting this error:

android.os.NetworkOnMainThreadException

and i was reading that i should use AsyncTask, but i have no idea how to convert this method to a AsyncTask.

I will apreciate some help.

Thanks


Solution

  • First of All you need a Fragment to wrap your asynctask so if the device rotates you do not create multiple requests and leak that. And also you need listener (GetAccessTokenCallbacks) to inform your activity that you have done and returning the result.

    public class GetAccessTokenFragment extends Fragment {
    
    
    OAuth2Config mOauthDetails;
    
    static interface GetAccessTokenCallbacks {
      void onPostExecute(Token token);
    }
    
    private GetAccessTokenCallbacks mCallbacks;
    private AccessTokenTask mTask;
    
    
    @Override
    public void onAttach(Activity activity) {
      super.onAttach(activity);
      mCallbacks = (GetAccessTokenCallbacks) activity;
    }
    
    
    @Override
    public void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setRetainInstance(true);
      // you must do it as follow
      // first create new instance
      // mOauthDetails = new OAuth2Config(....)
      // then use the values of MainActivity.this.mOauthDetails to initialize it
    
    
      mTask = new AccessTokenTask();
      mTask.execute();
    
    }
    
    @Override
    public void onDetach() {
      super.onDetach();
      mCallbacks = null;
    }
    
    
    
    private class AccessTokenTask extends AsyncTask<Void, Void, Token> {
    
      @Override
      protected Token doInBackground(Void... param) {
    
        Token token = TheClassOfThisFunction.getAccessToken(mOauthDetails);
        return token;
      }
    
      @Override
      protected void onPostExecute(Token token) {
        if (mCallbacks != null) {
          mCallbacks.onPostExecute(token[0]);
        }
      }
     }
    }
    

    and in your MainActivity you must implement GetAccessTokenFragment.GetAccessTokenCallbacks and creating the GetAccessTokenFragment.

    public class MainActivity extends FragmentActivity implements GetAccessTokenFragment.GetAccessTokenCallbacks {
    
          public OAuth2Config mOauthDetails;
    
          private static final String TAG_GetAccessTokenFragment = "GetAccessToken";
    
          private GetAccessTokenFragment mGetAccessTokenFragment;
    
          @Override
          protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
    
            // Initialize mOauthDetails here
    
    
            FragmentManager fm = getSupportFragmentManager();
            mGetAccessTokenFragment = (GetAccessTokenFragment) fm.findFragmentByTag(TAG_GetAccessTokenFragment);
    
            if (mGetAccessTokenFragment == null) {
              mGetAccessTokenFragment = new GetAccessTokenFragment();
              fm.beginTransaction().add(mGetAccessTokenFragment, TAG_GetAccessTokenFragment).commit();
            }
    
          }
    
          @Override
          public void onPostExecute(Token token) {
              //you got your token here
          }
        }
    

    Seems that OAuthConfig is called in the following:

    public class OAuth2Client {
    private final String username;
    private final String password;
    private final String clientId;
    private final String clientSecret;
    private final String site;
    public OAuth2Client(String username, String password, String clientId, String clientSecret, String site) {
        this.username = username;
        this.password = password;
        this.clientId = clientId;
        this.clientSecret = clientSecret;
        this.site = site;
    }
    public String getUsername() {
        return username;
    }
    public String getPassword() {
        return password;
    }
    public String getClientId() {
        return clientId;
    }
    public String getClientSecret() {
        return clientSecret;
    }
    public String getSite() {
        return site;
    }
    public Token getAccessToken() {
        OAuth2Config oauthConfig = new OAuth2Config.OAuth2ConfigBuilder(username, password, clientId, clientSecret, site)
                .grantType("password").build();
        return OAuthUtils.getAccessToken(oauthConfig);
    }
    

    }