如何在HTTP请求(RESTful Web服务)中使用AsyncTask来避免ANR

时间:2017-03-02 08:21:14

标签: android rest android-asynctask httprequest

我是android开发的新手。

现在我有执行HTTP请求(REST Web服务)的公共类

问题在于我不知道如何使用AsyncTask,因此每当请求过程花费很长时间时,它都会使应用程序无响应并冻结。

这是我的代码

public class RESTClient {

private ArrayList<NameValuePair> params;
private ArrayList <NameValuePair> headers;

private String url;

private int responseCode;
private String message;

private String response;

public String getResponse() {
    return response;
}

public String getErrorMessage() {
    return message;
}

public int getResponseCode() {
    return responseCode;
}

public enum RequestMethod
{
    GET,
    POST,
    PUT,
    DELETE
}

public RESTClient(String url)
{
    this.url = url;
    params = new ArrayList<NameValuePair>();
    headers = new ArrayList<NameValuePair>();
}

public void AddParam(String name, String value)
{
    params.add(new BasicNameValuePair(name, value));
}

public void AddHeader(String name, String value)
{
    headers.add(new BasicNameValuePair(name, value));
}

public void Execute(RequestMethod method) throws Exception
{
    switch(method) {
        case GET:
        {
            //add parameters
            String combinedParams = "";
            if(!params.isEmpty()){
                combinedParams += "?";
                for(NameValuePair p : params)
                {
                    String paramString = URLEncoder.encode(p.getValue(), "UTF-8");
                    if(combinedParams.length() > 1)
                    {
                        combinedParams  +=  "|" + paramString;
                    }
                    else
                    {
                        combinedParams += paramString;
                    }
                }
            }

            HttpGet request = new HttpGet(url);
            executeRequest(request, url);
            break;
        }
        case POST:
        {
            HttpPost request = new HttpPost(url);

            //add headers
            for(NameValuePair h : headers)
            {
                request.addHeader(h.getName(), h.getValue());
            }

            if(!params.isEmpty()){
                NameValuePair param = params.get(0);
                String val = param.getValue();

                StringEntity data = new StringEntity("{\"Value\": \"" + val + "\"}");
                data.setContentType("application/json");
                request.setEntity(data);
            }

            executeRequest(request, url);
            break;
        }
        case PUT:
        {
            HttpPut request = new HttpPut(url);

            //add headers
            for(NameValuePair h : headers)
            {
                request.addHeader(h.getName(), h.getValue());
            }

            if(!params.isEmpty()){
                NameValuePair param = params.get(0);
                String val = param.getValue();

                StringEntity data = new StringEntity("{\"Value\": \"" + val + "\"}");
                data.setContentType("application/json");
                request.setEntity(data);
            }

            executeRequest(request, url);
            break;
        }
        case DELETE:
        {
            HttpDelete request = new HttpDelete(url);

            //add parameters
            String combinedParams = "";
            if(!params.isEmpty()){
                combinedParams += "?";
                for(NameValuePair p : params)
                {
                    String paramString = URLEncoder.encode(p.getValue(), "UTF-8");
                    if(combinedParams.length() > 1)
                    {
                        combinedParams  +=  "|" + paramString;
                    }
                    else
                    {
                        combinedParams += paramString;
                    }
                }
            }

            executeRequest(request, url);
            break;
        }
    }
}

private void executeRequest(HttpUriRequest request, String url)
{

   HttpClient client = new DefaultHttpClient();

    HttpResponse httpResponse;
    try {

        StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
        StrictMode.setThreadPolicy(policy);
        httpResponse = client.execute(request);
        responseCode = httpResponse.getStatusLine().getStatusCode();
        message = httpResponse.getStatusLine().getReasonPhrase();

        HttpEntity entity = httpResponse.getEntity();

        if (entity != null) {

            InputStream instream = entity.getContent();
            response = convertStreamToString(instream);

            // Closing the input stream will trigger connection release
            instream.close();
        }

    } catch (ClientProtocolException e)  {
        client.getConnectionManager().shutdown();
        e.printStackTrace();
    } catch (IOException e) {
        client.getConnectionManager().shutdown();
        e.printStackTrace();

    }
}


private static String convertStreamToString(InputStream is) {

    BufferedReader reader = new BufferedReader(new InputStreamReader(is));
    StringBuilder sb = new StringBuilder();

    String line = null;
    try {
        while ((line = reader.readLine()) != null) {
            sb.append(line);
        }
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        try {
            is.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    return sb.toString();
}
}

有没有办法将asyncTask进程包含到我的类中?

- EDITED - 使用疯狂的sciendtist后

public class RESTClient  {

private ArrayList<NameValuePair> params;
private ArrayList <NameValuePair> headers;
private String url;
private int responseCode;
private String message;

ProgressDialog progressBar;
private String response;
private Context mContext;

public String getResponse() {
    return response;
}

public String getErrorMessage() {
    return message;
}

public int getResponseCode() {
    return responseCode;
}

public enum RequestMethod
{
    GET,
    POST,
    PUT,
    DELETE
}

public RESTClient(String url)
{
    this.url = url;
    params = new ArrayList<NameValuePair>();
    headers = new ArrayList<NameValuePair>();
}

public void AddParam(String name, String value)
{
    params.add(new BasicNameValuePair(name, value));
}

public void AddHeader(String name, String value)
{
    headers.add(new BasicNameValuePair(name, value));
}

   public String Execute(RequestMethod method) throws Exception
    {
        switch(method) {
            case GET:
            {
                //add parameters
                String combinedParams = "";
                if(!params.isEmpty()){
                    combinedParams += "?";
                    for(NameValuePair p : params)
                    {
                        String paramString = URLEncoder.encode(p.getValue(), "UTF-8");
                        if(combinedParams.length() > 1)
                        {
                            combinedParams  +=  "|" + paramString;
                        }
                        else
                        {
                            combinedParams += paramString;
                        }
                    }
                }

                HttpGet request = new HttpGet(url);
                // IM CALLING THE ASYNCTASK HERE
              return new HttpRequest(request, url).get();

                break;
            }
            default:
                return "";
            break;

        }
    }
private void executeRequest(HttpUriRequest request, String url)
{
   HttpClient client = new DefaultHttpClient();

    HttpResponse httpResponse;
    try {

        StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
        StrictMode.setThreadPolicy(policy);
        httpResponse = client.execute(request);
        responseCode = httpResponse.getStatusLine().getStatusCode();
        message = httpResponse.getStatusLine().getReasonPhrase();

        HttpEntity entity = httpResponse.getEntity();

        if (entity != null) {

            InputStream instream = entity.getContent();
            response = convertStreamToString(instream);

            // Closing the input stream will trigger connection release
            instream.close();
        }

    } catch (ClientProtocolException e)  {
        client.getConnectionManager().shutdown();
        e.printStackTrace();
    } catch (IOException e) {
        client.getConnectionManager().shutdown();
        e.printStackTrace();

    }
}


private static String convertStreamToString(InputStream is) {

    BufferedReader reader = new BufferedReader(new InputStreamReader(is));
    StringBuilder sb = new StringBuilder();

    String line = null;
    try {
        while ((line = reader.readLine()) != null) {
            sb.append(line);
        }
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        try {
            is.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    return sb.toString();
}

private class HttpRequest extends AsyncTask<HttpUriRequest,Void, String> {

    private HttpUriRequest httpUriRequest;
    private String url;
    public HttpRequest(HttpUriRequest httpUriRequest , String url) {
        this.httpUriRequest = httpUriRequest;
        this.url = url;
    }

    @Override
    protected String doInBackground(HttpUriRequest... params) {

        // perform all network task on a different thread (i.e not on the main thread)
        HttpClient client = new DefaultHttpClient();
        String response=null;
        HttpResponse httpResponse;
        try {

            StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
            StrictMode.setThreadPolicy(policy);
            httpResponse = client.execute(httpUriRequest);
            responseCode = httpResponse.getStatusLine().getStatusCode();
            message = httpResponse.getStatusLine().getReasonPhrase();

            HttpEntity entity = httpResponse.getEntity();

            if (entity != null) {

                InputStream instream = entity.getContent();
                response = convertStreamToString(instream);

                // Closing the input stream will trigger connection release
                instream.close();
            }

        } catch (ClientProtocolException e)  {
            client.getConnectionManager().shutdown();
            e.printStackTrace();
        } catch (IOException e) {
            client.getConnectionManager().shutdown();
            e.printStackTrace();

        }
        // return the response;
        return response;
    }

    @Override
    protected void onPreExecute() {
        super.onPreExecute();
        // do not forget to add a progress dialog here or a progressbar

    }

    @Override
    protected void onPostExecute(String s) {
        super.onPostExecute(s);
        if (!TextUtils.isEmpty(s)){
            // on succesfull callback. hide the progres bar or dialog

        }
    }


}

}

这是我调用异步restclient时的活动,我需要得到json的响应

Login.Java

public class Login extends AppCompatActivity  {

private static String URLService;
// UI references.
private EditText USERID;
private EditText PASSWORD;
private View mProgressView;
private View mLoginFormView;
public static String UserID;
private static String Version="3.0";
private String VersionID;
private String VersionStatus;
private String hashed="";
private String Enc_Pass="";
private int responseCode;
Context context;
ProgressDialog mProgressDialog;
private String message;
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_login);
    // Set up the login form.
    USERID = (EditText)findViewById(R.id.userID);
    //populateAutoComplete();
    URLService = getString(R.string.URLService);
    Enc_Pass = getString(R.string.password_encryption);
    PASSWORD = (EditText) findViewById(R.id.password);
    Button LOGINBUTTON = (Button) findViewById(R.id.email_sign_in_button);
    LOGINBUTTON.setOnClickListener(new OnClickListener() {
        @Override
        public void onClick(View view) {
            attemptLogin();
        }
    });

    mProgressView = findViewById(R.id.login_progress); 
    SharedPreferences pref = getApplicationContext().getSharedPreferences("MyPref", MODE_PRIVATE);
    UserID = pref.getString("userId", "");
    if (!UserID.toString().equals(""))
    {
        Intent i = new Intent(Login.this, Index.class);
        startActivity(i);
    }
    else
    {
    }
}
private void attemptLogin() {

    // Reset errors.
    USERID.setError(null);
    PASSWORD.setError(null);
    // Store values at the time of the login attempt.

        try {
            String valueEncrypt = strUserId + "|" + strPassword;
            String encc  = "";
             try {
                  encc = AndroidCrypt.encrypt(Enc_Pass,valueEncrypt);
                  encc = encc.replace("+", "%2B");
            }catch (GeneralSecurityException e){
                //handle error
            }

       //     new BigProccess(Login.this, ProgressDialog.STYLE_SPINNER).execute();
          //  new HttpRequestMet(URLService+"do?method=dologin&value=" +encc,"GET").execute();
            RESTClient client = new RESTClient(URLService+"do?method=dologin&value=" +encc);

            client.Execute(RESTClient.RequestMethod.GET);

            String response = client.getResponse();

            response = response.replace("\\\"", "\"");
            response = response.substring(1, response.length() - 1);

            JSONParser jsonParser = new JSONParser();
            JSONObject jsonObject = (JSONObject) jsonParser.parse(response);
            Status = jsonObject.get("Status").toString();

            if (Status == "true") {

                String dataku = jsonObject.get("Data").toString();

                 try {
                 dataku = AndroidCrypt.decrypt(Enc_Pass, dataku);
                 }catch (GeneralSecurityException e){
                     //handle error - could be due to incorrect password or tampered encryptedMsg
                 }

                JSONParser parser = new JSONParser();
                JSONObject structure = (JSONObject) parser.parse(dataku);


                Toast.makeText(getApplicationContext(), "Welcome Back Mr./Mrs. " + FullName,
                        Toast.LENGTH_SHORT).show();

                Intent i = new Intent(Login.this, Index.class);
                startActivity(i);
                //  finish();



            } else {
                Toast.makeText(getApplicationContext(), "Login Failed",
                        Toast.LENGTH_SHORT).show();
            }
        } catch (Exception e) {
            e.printStackTrace();
            Toast.makeText(getApplicationContext(),"Cant Connect to server, please try again later",
                    Toast.LENGTH_SHORT).show();
        }
    }


}

}

2 个答案:

答案 0 :(得分:0)

只需将您的网络操作放在AsyncTask中,

class HTTPAsyncTask extends AsyncTask<String, Void, Boolean> {

@Override
protected void onPreExecute() {
    super.onPreExecute();

}

@Override
protected Boolean doInBackground(String... urls) {
     HttpGet request = new HttpGet(url);
     executeRequest(request, url);
     return false;
}

protected void onPostExecute(Boolean result) {

}

在类编写的任何地方执行AsyncTask,

new HTTPAsyncTask().execute("");

答案 1 :(得分:0)

欢迎使用Android Dev,Android(UI线程)中有一个主线程,可以进行所有视图操作。建议不要对这些线程执行繁重的计算或FileSystem操作或NetworkTasks,因为视图依赖于此线程。

作为这个问题的解决方案,android支持Worker threads,它可以处理这些繁重的操作。

AsyncTask是实现此结构的好方法。 Read the doc here

就您的代码而言,您可以在同一个文件中创建一个新类

private class HttpRequest extends AsyncTask<Void,Void, String>{

private HttpUriRequest httpUriRequest;
private String url;
public HttpRequest(HttpUriRequest httpUriRequest , String url) {
    this.httpUriRequest = httpUriRequest;
    this.url = url;
}

@Override
protected void onPreExecute() {
    super.onPreExecute();
    // do not forget to add a progress dialog here or a progressbar
    progressBar.show();
}

@Override
protected void onPostExecute(String s) {
    super.onPostExecute(s);
    if (!TextUtils.isEmpty(s)){
        // on succesfull callback. hide the progres bar or dialog
        progressBar.gone();
    }
}

@Override
protected String doInBackground(Void... voids) {

    // perform all network task on a different thread (i.e not on the main thread)
    HttpClient client = new DefaultHttpClient();
    String response=null;
    HttpResponse httpResponse;
    try {

        StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
        StrictMode.setThreadPolicy(policy);
        httpResponse = client.execute(request);
        responseCode = httpResponse.getStatusLine().getStatusCode();
        message = httpResponse.getStatusLine().getReasonPhrase();

        HttpEntity entity = httpResponse.getEntity();

        if (entity != null) {

            InputStream instream = entity.getContent();
            response = convertStreamToString(instream);

            // Closing the input stream will trigger connection release
            instream.close();
        }

    } catch (ClientProtocolException e)  {
        client.getConnectionManager().shutdown();
        e.printStackTrace();
    } catch (IOException e) {
        client.getConnectionManager().shutdown();
        e.printStackTrace();

    }
    // return the response;
    return response;
}
}

您需要做的就是使用自定义Contructor

调用此类

离。 new HttpRequest(httpUriRequest, url).execute();并使用onPostExecute()方法处理了响应。

此外,由于您是一个小推荐,尝试使用第一个字母作为小写命名方法名称,这样您就可以将类与其方法区分开来。

尝试Retrofit比HttpRequests的原生方式更酷,