How to send a POST in Android API 22



  • I've been toying around with making a basic Android app to interface with a website, and one of the things I need to do is standard HTTP requests, GETs and POSTs and such. I had been using the AndroidHttpClient APIs, which were a bit verbose, but basically reasonable, and look kinda like this:

    HttpPost loginRequest = new HttpPost(siteAddress);
    List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(3);
    nameValuePairs.add(new BasicNameValuePair("ACCESS_CODE", accessCode));
    nameValuePairs.add(new BasicNameValuePair("Login", "Login"));
    nameValuePairs.add(new BasicNameValuePair("GO", "YES"));
    loginRequest.setEntity(new UrlEncodedFormEntity(nameValuePairs));
    HttpResponse loginResponse = client.execute(loginRequest, clientContext);
    if (loginResponse.getStatusLine().getStatusCode() != 200) return false;
    String responseString = EntityUtils.toString(loginResponse.getEntity());
    

    Then I updated to API22, and apparently, the whole AndroidHttpClient API is deprecated. Seems I'm supposed to be using HttpUrlConnection instead, according to a blog post from 4 years ago. Googling around some, I find that sending a standard HTTP POST with HttpUrlConnection would look something like

    URL url = new URL("http://yoururl.com");
    HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
    conn.setReadTimeout(10000);
    conn.setConnectTimeout(15000);
    conn.setRequestMethod("POST");
    conn.setDoInput(true);
    conn.setDoOutput(true);
    
    List<NameValuePair> params = new ArrayList<NameValuePair>();
    params.add(new BasicNameValuePair("firstParam", paramValue1));
    params.add(new BasicNameValuePair("secondParam", paramValue2));
    params.add(new BasicNameValuePair("thirdParam", paramValue3));
    
    OutputStream os = conn.getOutputStream();
    BufferedWriter writer = new BufferedWriter(
            new OutputStreamWriter(os, "UTF-8"));
    writer.write(getQuery(params));
    writer.flush();
    writer.close();
    os.close();
    
    conn.connect();
    

    Where you define your own getQuery something like:

    private String getQuery(List<NameValuePair> params) throws UnsupportedEncodingException
    {
        StringBuilder result = new StringBuilder();
        boolean first = true;
    
        for (NameValuePair pair : params)
        {
            if (first)
                first = false;
            else
                result.append("&");
    
            result.append(URLEncoder.encode(pair.getName(), "UTF-8"));
            result.append("=");
            result.append(URLEncoder.encode(pair.getValue(), "UTF-8"));
        }
    
        return result.toString();
    }
    

    According to a highly upvoted SO response:

    Apparently, now I need to either write my own form encoder, or pull in a third-party library to do it for me. Because it's not like an average Android app developer would ever need to do something like send a POST request or anything.



  • It's almost as bad as Python's library.

    And HTTP is probably THE most important protocol to implement. How can programming languages get it so wrong? How can anybody in their team look at this and say "this is OK, we don't need to develop a simpler library"?

    (now waiting for a certain someone to show us how it's done in Go)



  • resp, err := http.Get("http://example.com/")

    resp, err := http.PostForm("http://example.com/form", url.Values{"key": {"Value"}, "id": {"123"}})

  • BINNED

    Qt is an interesting beast in this regard.

    Want to send an HTTP request? No problem, just use the standard QNetworkManager API and it's a snap.

    Want to make an HTTP server? No header generation for you, time to concatenate some strings! You'd think that there should be a method that will generate headers for you but nope, none of that in the publicly exposed API.

    To be fair, you could probably hook into the internal mechanisms and maybe make them do your bidding. But I'd rather not do that myself, it's just an invitation to get in trouble between versions sooner or later.



  • @ufmace said:

    ```
    HttpPost loginRequest = new HttpPost(siteAddress);
    List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(3);
    nameValuePairs.add(new BasicNameValuePair("ACCESS_CODE", accessCode));
    nameValuePairs.add(new BasicNameValuePair("Login", "Login"));
    nameValuePairs.add(new BasicNameValuePair("GO", "YES"));
    loginRequest.setEntity(new UrlEncodedFormEntity(nameValuePairs));
    HttpResponse loginResponse = client.execute(loginRequest, clientContext);
    if (loginResponse.getStatusLine().getStatusCode() != 200) return false;
    String responseString = EntityUtils.toString(loginResponse.getEntity());

    
    

    loginResponse, err := http.PostForm(siteAddress, url.Values{
    "ACCESS_CODE": {accessCode},
    "Login": {"Login"},
    "GO": {"YES"},
    })
    if err != nil{
    return nil, err
    }
    defer loginResponse.Body.Close()
    if loginResponse.StatusCode != http.StatusOK {
    return nil, nil
    }
    return ioutil.ReadAll(loginResponse.Body)



  • You know, the other thing is, it's not the end of the world that you need to pull in an external library to do HTTP stuff without reinventing the wheel. A lot of languages/frameworks do that, and it's what I ended up doing, and the resulting code is a lot cleaner and simpler than the original AndroidHttpClient stuff. But it's gotta be an unpleasant surprise to a lot of app developers that the reasonable HTTP API they were using was deprecated on them, and the official recommended replacement seems to have like 10% of the functionality.

    I'm a little surprised that there don't seem to be many rants around the internet about this yet. I'm guessing that either nobody is bothering upgrading to API22 yet, or everybody is already using third-party libraries for their HTTP needs.


Log in to reply