2015-12-22 2 views
5

У меня есть несколько деятельностей, каждый из которых получают различные данные из различных URL-адресов и различных методов HTTP, как POST, GET, PUT, DELETE и т.д. Некоторые запросов имеют данные заголовка, а некоторые имеют тело, некоторые из них могут иметь и другие. Я использую один класс AsyncTask с несколькими конструкторами для передачи данных из Деяний, чтобы я мог добавить их в экземпляр HttpUrlConnection.Как я могу разделить логику HttpUrlConnection на несколько методов?

Я пробовал этот учебник: http://cyriltata.blogspot.in/2013/10/android-re-using-asynctask-class-across.html.

Но приведенный выше учебник использует HttpClient и NameValuePair. Я заменил NameValuePair на Pair. Но мне трудно реализовать ту же логику, используя HttpUrlConnection, поскольку мне нужно добавить несколько данных и заголовков POST к моему запросу.

Но возвращенная строка пуста. Как правильно реализовать этот сценарий?

Полный код:

public class APIAccessTask extends AsyncTask<String,Void,String> { 
URL requestUrl; 
Context context; 
HttpURLConnection urlConnection; 
List<Pair<String,String>> postData, headerData; 
String method; 
int responseCode = HttpURLConnection.HTTP_NOT_FOUND; 


APIAccessTask(Context context, String requestUrl, String method){ 
    this.context = context; 
    this.method = method; 
    try { 
     this.requestUrl = new URL(requestUrl); 
    } 
    catch(Exception ex){ 
     ex.printStackTrace(); 
    } 
} 


APIAccessTask(Context context, String requestUrl, String method, List<Pair<String,String>> postData,){ 
    this(context, requestUrl, method); 
    this.postData = postData; 
} 

APIAccessTask(Context context, String requestUrl, String method, List<Pair<String,String>> postData, 
       List<Pair<String,String>> headerData){ 
    this(context, requestUrl,method,postData); 
    this.headerData = headerData; 
} 

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

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

    setupConnection(); 

    if(method.equals("POST")) 
    { 
     return httpPost(); 
    } 

    if(method.equals("GET")) 
    { 
     return httpGet(); 
    } 

    if(method.equals("PUT")) 
    { 
     return httpPut(); 
    } 

    if(method.equals("DELETE")) 
    { 
     return httpDelete(); 
    } 
    if(method.equals("PATCH")) 
    { 
     return httpPatch(); 
    } 

    return null; 
} 

@Override 
protected void onPostExecute(String result) { 
    Toast.makeText(context,result,Toast.LENGTH_LONG).show(); 
    super.onPostExecute(result); 
} 

void setupConnection(){ 
    try { 
     urlConnection = (HttpURLConnection) requestUrl.openConnection(); 
     urlConnection.setDoOutput(true); 
     urlConnection.setDoInput(true); 
     urlConnection.setChunkedStreamingMode(0); 
     if(headerData != null){ 
      for (Pair pair: headerData) 
      { 
       urlConnection.setRequestProperty(pair.first.toString(), Base64.encodeToString(pair.second.toString().getBytes(),Base64.DEFAULT)); 
      } 
     } 
    } 
    catch(Exception ex) { 
     ex.printStackTrace(); 
    } 

} 

private String httpPost(){ 
    try{ 
     urlConnection.setRequestMethod("POST"); 
    } 
    catch (Exception ex){ 
     ex.printStackTrace(); 

    return stringifyResponse(); 
} 

String httpGet(){ 

    try{ 
     urlConnection.setRequestMethod("GET"); 
    } 
    catch (Exception ex){ 
     ex.printStackTrace(); 
    } 
    return stringifyResponse(); 
} 

String httpPut(){ 

    try{ 
     urlConnection.setRequestMethod("PUT"); 
    } 
    catch (Exception ex){ 
     ex.printStackTrace(); 
    } 
    return stringifyResponse(); 
} 

String httpDelete(){ 
    try{ 
     urlConnection.setRequestMethod("DELETE"); 
    } 
    catch (Exception ex){ 
     ex.printStackTrace(); 
    } 
    return stringifyResponse(); 

} 

String httpPatch(){ 
    try{ 
     urlConnection.setRequestMethod("PATCH"); 
    } 
    catch (Exception ex){ 
     ex.printStackTrace(); 
    } 
    return stringifyResponse(); 

} 

String stringifyResponse() { 

    StringBuilder sb = new StringBuilder(); 
    try { 
     OutputStream out = new BufferedOutputStream(urlConnection.getOutputStream()); 
     BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(out, "UTF-8")); 
     writer.write(getQuery(postData)); 
     writer.flush(); 
     writer.close(); 
     out.close(); 

     urlConnection.connect(); 
     responseCode = urlConnection.getResponseCode(); 
     if (responseCode == 200) { 
      InputStream in = new BufferedInputStream(urlConnection.getInputStream()); 
      BufferedReader reader = new BufferedReader(new InputStreamReader(in, "UTF-8")); 
      String line = null; 

      while ((line = reader.readLine()) != null) { 
       sb.append(line); 
      } 
     } 

    } catch (Exception ex) { 
     ex.printStackTrace(); 
    } 
    return sb.toString(); 
} 


private String getQuery(List<Pair<String,String>> params) throws UnsupportedEncodingException{ 
    Uri.Builder builder = null; 
    for (Pair pair : params) 
    { 
     builder = new Uri.Builder() 
       .appendQueryParameter(pair.first.toString(), pair.second.toString()); 
       } 
    return builder.build().getEncodedQuery(); 
} 
} 
+1

Можете добавить код, в котором вы хотите добавить несколько данных POST к вашему запросу. –

+2

Непонятно, что вы просите. Вам не нужно несколько методов для добавления нескольких пар-имен POST-имен или заголовков. – EJP

+0

IMO, для вашего требования вы можете обратиться к исходному коду Google Volley, начиная с 'setConnectionParametersForRequest' по адресу [HurlStack.java] (https://android.googlesource.com/platform/frameworks/volley/+/master/src/ main/java/com/android/volley/toolbox/HurlStack.java) – BNK

ответ

1

ИМО, вы можете сослаться на мой следующем примере кода:

/**   
    * HTTP request using HttpURLConnection 
    * 
    * @param method 
    * @param address 
    * @param header 
    * @param mimeType 
    * @param requestBody 
    * @return 
    * @throws Exception 
    */ 
    public static URLConnection makeURLConnection(String method, String address, String header, String mimeType, String requestBody) throws Exception { 
     URL url = new URL(address); 

     HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection(); 

     urlConnection.setDoInput(true); 
     urlConnection.setDoOutput(!method.equals(HTTP_METHOD_GET)); 
     urlConnection.setRequestMethod(method); 

     if (isValid(header)) { // let's assume only one header here    
      urlConnection.setRequestProperty(KEYWORD_HEADER_1, header); 
     } 

     if (isValid(requestBody) && isValid(mimeType) && !method.equals(HTTP_METHOD_GET)) { 
      urlConnection.setRequestProperty(KEYWORD_CONTENT_TYPE, mimeType); 
      OutputStream outputStream = new BufferedOutputStream(urlConnection.getOutputStream()); 
      BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(outputStream, "utf-8"); 
      writer.write(requestBody); 
      writer.flush(); 
      writer.close(); 
      outputStream.close(); 
     } 

     urlConnection.connect(); 

     return urlConnection; 
    } 

requestBody производится с помощью следующего метода:

public static String buildRequestBody(Object content) { 
     String output = null; 
     if ((content instanceof String) || 
       (content instanceof JSONObject) || 
       (content instanceof JSONArray)) { 
      output = content.toString(); 
     } else if (content instanceof Map) { 
      Uri.Builder builder = new Uri.Builder(); 
      HashMap hashMap = (HashMap) content; 
      if (isValid(hashMap)) { 
       Iterator entries = hashMap.entrySet().iterator(); 
       while (entries.hasNext()) { 
        Map.Entry entry = (Map.Entry) entries.next(); 
        builder.appendQueryParameter(entry.getKey().toString(), entry.getValue().toString()); 
        entries.remove(); // avoids a ConcurrentModificationException 
       } 
       output = builder.build().getEncodedQuery(); 
      } 
     } else if (content instanceof byte[]) { 
      try { 
       output = new String((byte[]) content, "UTF-8"); 
      } catch (UnsupportedEncodingException e) { 
       e.printStackTrace(); 
      } 
     } 

     return output; 
    } 
} 

Тогда , в вашем классе AsyncTask вы можете позвонить:

 String url = "http://......."; 
     HttpURLConnection urlConnection; 
     Map<String, String> stringMap = new HashMap<>();   
     stringMap.put(KEYWORD_USERNAME, "bnk"); 
     stringMap.put(KEYWORD_PASSWORD, "bnk123"); 
     String requestBody = buildRequestBody(stringMap); 
     try { 
      urlConnection = (HttpURLConnection) Utils.makeURLConnection(HTTP_METHOD_POST, url, null, MIME_FORM_URLENCODED, requestBody);    
      if (urlConnection.getResponseCode() == HttpURLConnection.HTTP_OK) { 
       // do something... 
      } else { 
       // do something... 
      } 
      ... 
     } catch (Exception e) { 
      e.printStackTrace(); 
     } 

или

 String url = "http://......."; 
     HttpURLConnection urlConnection; 
     JSONObject jsonBody;      
     String requestBody; 
     try { 
      jsonBody = new JSONObject(); 
      jsonBody.put("Title", "Android Demo"); 
      jsonBody.put("Author", "BNK"); 
      requestBody = Utils.buildRequestBody(jsonBody); 
      urlConnection = (HttpURLConnection) Utils.makeURLConnection(HTTP_METHOD_POST, url, null, MIME_JSON, requestBody);    
      if (urlConnection.getResponseCode() == HttpURLConnection.HTTP_OK) { 
       // do something... 
      } else { 
       // do something... 
      } 
      ... 
     } catch (Exception e) { 
      e.printStackTrace(); 
     } 
+0

Слишком поздно вызывать 'connect()' * после * вы отправили запрос. На самом деле вам вообще не нужно называть 'connect()' вообще. Трудно понять, как это отвечает на запрос, независимо от того, что это означает, «разбивая несколько методов». – EJP

+0

@EJP: Я согласен с вами в отношении connect(). О «взломе», если я правильно понимаю требование OP, когда он передал «GET», например, в параметр «method», это запрос GET ... Если «POST» передан, это запрос POST. – BNK

1

Позволяет применить некоторые OOPS понятия здесь
Иметь класс HttpCommunication с будет чисто заботиться о направлении запроса и получения ответа от сервера. Пример кода, который выглядит следующим образом

package com.example.sample; 

import java.io.BufferedReader; 
import java.io.InputStream; 
import java.io.InputStreamReader; 
import java.util.ArrayList; 

import org.apache.http.HttpEntity; 
import org.apache.http.HttpResponse; 
import org.apache.http.NameValuePair; 
import org.apache.http.client.entity.UrlEncodedFormEntity; 
import org.apache.http.client.methods.HttpGet; 
import org.apache.http.client.methods.HttpPost; 
import org.apache.http.client.utils.URLEncodedUtils; 
import org.apache.http.impl.client.DefaultHttpClient; 
import org.apache.http.params.BasicHttpParams; 
import org.apache.http.params.HttpConnectionParams; 
import org.apache.http.params.HttpParams; 

public class HttpCommunication { 
    public String makeHttpRequest(String url, HttpMethods method, ArrayList<NameValuePair> requestParams, ArrayList<NameValuePair> postData) throws Exception { 

     InputStream inputStream = null; 
     String response = ""; 
     HttpParams httpParameters = new BasicHttpParams(); 

     /** 
     * Set the timeout in milliseconds until a connection is established. The default value is 
     * zero, that means the timeout is not used. 
     */ 
     int timeoutConnection = 15000; 
     HttpConnectionParams.setConnectionTimeout(httpParameters, timeoutConnection); 

     /** 
     * Set the default socket timeout (SO_TIMEOUT) in milliseconds which is the timeout for 
     * waiting for data. 
     */ 
     int timeoutSocket = 15000; 
     HttpConnectionParams.setSoTimeout(httpParameters, timeoutSocket); 

     DefaultHttpClient httpClient = new DefaultHttpClient(httpParameters); 

     /** 
     * Check for request method 
     */ 
     if (method == HttpMethods.POST) { 
      HttpPost httpPost = new HttpPost(url); 

      if (requestParams != null && requestParams.size() > 0) { 
       httpPost.setEntity(new UrlEncodedFormEntity(requestParams)); 
      } 

      HttpResponse httpResponse = httpClient.execute(httpPost); 
      HttpEntity httpEntity = httpResponse.getEntity(); 
      inputStream = httpEntity.getContent(); 

     } else if (method == HttpMethods.GET) { 
      if (requestParams != null && requestParams.size() > 0) { 
       String paramString = URLEncodedUtils.format(requestParams, "utf-8"); 
       url += "?" + paramString; 
      } 

      HttpGet httpGet = new HttpGet(url); 

      HttpResponse httpResponse = httpClient.execute(httpGet); 
      HttpEntity httpEntity = httpResponse.getEntity(); 
      inputStream = httpEntity.getContent(); 
     } 

     BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, "UTF-8")); 
     StringBuilder sb = new StringBuilder(); 
     String line = null; 
     while ((line = reader.readLine()) != null) { 
      sb.append(line + "\n"); 
     } 
     inputStream.close(); 
     response = sb.toString(); 

     return response; 
    } 
} 

Есть абстрактный базовый класс, который будет выступать в качестве шаблона для всех лежащих в основе веб-сервисов в вашем приложении. Этот класс будет использовать выше класс HttpCommunication для отправки запроса. Запросы будут отправляться из AsyncTask, следовательно, они полностью асинхронны. Класс предоставит абстрактные методы, которые производные классы должны переопределить и предоставить определения;
1. GetURL() - Хорошо отформатированный URL запроса
2. getHttpMethod() - один из метода HTTP GET с, POST, PUT, DELETE, PATCH
3. getRequestParams() - запрос PARAMS (заголовки) если таковые имеются.
4. getPostParams() - Параметры сообщения, если они есть.
5. parseResponse (String) - производные классы должны дать определение этого метода для анализа полученного ответа.
6. notifyError (int) - производные классы должны дать определение этого метода для обработки ошибки, которая может быть получена при общении.

package com.example.sample; 
import java.util.ArrayList; 
import org.apache.http.NameValuePair; 
import android.os.AsyncTask; 
/** 
* This class is an abstract base class for all web services. 
*/ 
public abstract class BaseService { 
    protected abstract String getUrl(); 
    protected abstract HttpMethods getHttpMethod(); 
    protected abstract ArrayList<NameValuePair> getRequestParams(); 
    protected abstract ArrayList<NameValuePair> getPostParams(); 
    protected abstract void parseResponse(String response); 
    protected abstract void notifyError(int errorCode); 

    public void send() { 
     SendRequestTask sendRequestTask = new SendRequestTask(); 
     sendRequestTask.execute(); 
    } 

    private class SendRequestTask extends AsyncTask< Void, Void, Integer > { 
     @Override 
     protected Integer doInBackground(Void... params) { 
      try { 
       String url = getUrl(); 
       HttpMethods method = getHttpMethod(); 
       ArrayList<NameValuePair> httpParams = getRequestParams(); 
       ArrayList<NameValuePair> postParams = getPostParams(); 

       HttpCommunication httpCommunication = new HttpCommunication(); 
       String response = httpCommunication.makeHttpRequest(url, method, httpParams, postParams); 

       parseResponse(response); 
      } catch (Exception ex) { 
       ex.printStackTrace(); 
       notifyError(CommunicationError.ERROR_COMMUNICATION); 
      } 
      return 0; 
     } 
    } 
} 

Вот код для образца Webservice класса, который является производным от класса выше;

package com.example.sample; 
import java.util.ArrayList; 
import org.apache.http.NameValuePair; 
import org.apache.http.message.BasicNameValuePair; 
/** 
* This is a web service class to login. 
*/ 
public class SignIn extends BaseService { 
    private final String _emailId; 
    private final String _password; 
    private final String _signinUrl = "http://www.example.com/login.php"; 

    public SignIn(String userName, String password) { 
     _emailId = userName; 
     _password = null; 
    } 

    @Override 
    protected String getUrl() { 
     return _signinUrl; 
    } 

    @Override 
    protected ArrayList<NameValuePair> getRequestParams() { 
     ArrayList<NameValuePair> params = new ArrayList<NameValuePair>(); 
     params.add(new BasicNameValuePair("header1", "header1")); 
     params.add(new BasicNameValuePair("header2", "header2")); 
     return params; 
    } 

    @Override 
    protected ArrayList<NameValuePair> getPostParams() { 
     ArrayList<NameValuePair> params = new ArrayList<NameValuePair>(); 
     params.add(new BasicNameValuePair("email", _emailId)); 
     params.add(new BasicNameValuePair("password", _password)); 
     return params; 
    } 

    @Override 
    protected HttpMethods getHttpMethod() { 
     return HttpMethods.POST; 
    } 

    @Override 
    protected void parseResponse(String response) { 
     // Parse the response here 
    } 

    @Override 
    protected void notifyError(int errorCode) { 
     // Notify error to application 
    } 
} 

Вот как вы можете использовать веб-сервис SignIn;

SignIn signIn = new SignIn("[email protected]", "abc123"); 
signIn.send(); 

Измените свой класс HttpCommunication следующим образом.

package com.example.sample; 

import java.io.BufferedReader; 
import java.io.InputStream; 
import java.io.InputStreamReader; 
import java.io.OutputStream; 
import java.net.HttpURLConnection; 
import java.net.URL; 
import java.util.ArrayList; 

import org.apache.http.NameValuePair; 

public class HttpCommunication { 
    private final int CONNECTION_TIMEOUT = 10 * 1000; 

    /** 
    * Default Constructor 
    */ 
    public HttpCommunication() { 

    } 

    public String makeHttpRequest(String strUrl, HttpMethods method, ArrayList<NameValuePair> requestParams, ArrayList<NameValuePair> postData) throws Exception { 

     HttpURLConnection connection = null; 
     InputStream inputStream = null; 
     URL url = null; 
     String response = null; 
     try { 
      url = new URL(strUrl); 
      connection = (HttpURLConnection) url.openConnection(); 
      connection.setConnectTimeout(CONNECTION_TIMEOUT); 
      connection.setReadTimeout(CONNECTION_TIMEOUT); 

      if (requestParams != null && requestParams.size() > 0) { 
       for (NameValuePair pair : requestParams) { 
        connection.setRequestProperty(pair.getName(), pair.getValue()); 
       } 
      } 

      connection.setDoInput(true); 
      connection.connect(); 
      if (method == HttpMethods.POST) { 
       OutputStream os = connection.getOutputStream(); 
       // Convert post data to string and then write it to outputstream. 
       String postDataStr = "test"; 
       os.write(postDataStr.getBytes()); 
       os.close(); 
      } 

      inputStream = connection.getInputStream(); 

      if (inputStream != null) { 
       BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, "UTF-8")); 
       StringBuilder sb = new StringBuilder(); 
       String line = null; 
       while ((line = reader.readLine()) != null) { 
        sb.append(line + "\n"); 
       } 
       response = sb.toString(); 
       inputStream.close(); 
      } 
      connection.disconnect(); 
     } catch (Exception e) { 
      if (connection != null) { 
       connection.disconnect(); 
      } 
     } 

     return response; 
    } 
} 
+0

Я знаю, как это можно сделать с помощью Apache 'HttpClient'. который устарел с API22. Если вы можете отправить код с помощью 'HttpUrlConnection', это было бы полезно. –

+0

Обратитесь к модифицированному классу HttpCommunication. Вам не нужно менять какой-либо другой класс. – abidfs

Смежные вопросы