【问题标题】:Method to AsyncTask Android OAuth2ClientAsyncTask Android OAuth2Client 的方法
【发布时间】:2014-10-01 12:15:43
【问题描述】:

我正在尝试使用此代码:

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;
}

是我在我的 Android 应用程序中使用的 OAuth2Client 的一部分。 我收到此错误:

android.os.NetworkOnMainThreadException

我正在阅读我应该使用 AsyncTask,但我不知道如何将此方法转换为 AsyncTask。

我会感谢一些帮助。

谢谢

【问题讨论】:

    标签: android android-asynctask oauth-2.0 token thread-exceptions


    【解决方案1】:

    首先,您需要一个片段来包装您的asynctask,因此如果设备旋转,您不会创建多个请求并泄漏它。您还需要监听器 (GetAccessTokenCallbacks) 来通知您的活动您已完成并返回结果。

    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]);
        }
      }
     }
    }
    

    在您的MainActivity 中,您必须实现GetAccessTokenFragment.GetAccessTokenCallbacks 并创建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
          }
        }
    

    好像在下面调用了OAuthConfig:

    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);
    }
    

    }

    【讨论】:

    • 我的应用程序只有 2 个带有片段容器的活动,基本上我的应用程序一直在处理片段。当用户按下登录按钮时,会出现一个名为 LogInFragment 的片段,用户将在其中输入用户名和密码。当用户确认用户名和密码时,它会调用一个对话框片段,该片段只显示登录...并且所有正在进行的登录都在此处完成。
    • 我想我明白了,我现在就测试一下。基本上,我必须获取 accessToken 的方法不需要是 asyncTask,但我应该在 AsyncTask 中执行该方法。我没听错吗?
    • 没错,我的代码只是为您执行此操作,我将您的 getAccessToken 放在 doInBackground 中,因为 doInBackground 在其他线程(工作线程)上运行,您将摆脱该异常。因为用户可以旋转您的设备,这会导致再次调用getAccessToken,我认为没有必要我将 AsyncTask 放入保留的片段中只请求一次。
    • 这一行抱怨:mCallbacks.onPostExecute(token[0]);预期键入的数组,发现:com.xxxxx.xxxxx.xxxxx.Token
    • 第一个 protected void onPostExecute(Token token) 将结果传递给片段,我认为您可以用 DialogFragment 替换该片段,但我不确定 DialogFragment 在配置更改期间是否保持其状态,因此请阅读此@987654321 @所以删除setRetainInstance(true);
    猜你喜欢
    • 2016-11-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-01-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多