6

Scenario: I'm trying to send some POST data via HttpURLConnection in a service (with progress updates). I am grabbing an image from the gallery and then sending it to a php server with 2 parameters; invnum and password.

Note: If I'm doing it by the HttpClient method, the parameters and the image are sent and received in the server but I can't track the upload progress. I saw some codes related to custom multipart entity, as much as possible I would like to avoid referencing a library

I've looked into a lot of related questions in SO but can't seem to find a solution. Below are the current codes I have in my service.

protected void onHandleIntent(Intent intent) {
    String invnum = intent.getStringExtra("invnum");
    String uploadURL = intent.getStringExtra("uploadURL");
    String imageURI = intent.getStringExtra("imageURI");
    uri = Uri.parse(imageURI);

    String pass = "password";

    //get the actual path of the image residing in the phone
    String[] filePathColumn = { MediaStore.Images.Media.DATA };
    Cursor cursor = getContentResolver().query(uri,filePathColumn, null, null, null);
    cursor.moveToFirst();
    int columnIndex = cursor.getColumnIndex(filePathColumn[0]);
    picturePath = cursor.getString(columnIndex);
    cursor.close();

    ResultReceiver receiver = (ResultReceiver) intent.getParcelableExtra("receiver");

    //check url
    try {
        File file = new File(picturePath);
        FileInputStream fileInputStream = new FileInputStream(file);
        byte[] bytes = new byte[(int) file.length()];
        fileInputStream.read(bytes);
        fileInputStream.close();

        String fileName = file.getName();

        URL url = new URL(uploadURL);
        HttpURLConnection connection = (HttpURLConnection) url.openConnection();
        connection.setDoInput(true);
        connection.setDoOutput(true);
        connection.setUseCaches(false);
        connection.setConnectTimeout(30000);
        connection.setReadTimeout(30000);
        connection.setChunkedStreamingMode(1024);
        connection.setRequestMethod("POST");
        connection.setRequestProperty("Connection", "Keep-Alive");
        connection.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.0.10) Gecko/2009042316 Firefox/3.0.10 (.NET CLR 3.5.30729)");
        connection.setRequestProperty("image", fileName);
        connection.setRequestProperty("Content-Type", "multipart/form-data;boundary=" + boundary);

        DataOutputStream outputStream = new DataOutputStream(connection.getOutputStream());

        //send multipart form data (required) for file
        outputStream.writeBytes("Content-Disposition: form-data; name=\"image\";filename=\"" + fileName + "\"" + lineEnd);
        outputStream.writeBytes("Content-Type: image/jpeg" + lineEnd);
        //outputStream.writeBytes("Content-Type: " + URLConnection.guessContentTypeFromName(fileName) + lineEnd);
        //outputStream.writeBytes("Content-Transfer-Encoding: binary" + lineEnd);
        //outputStream.writeBytes("Content-Type: application/octet-stream" + lineEnd);
        outputStream.writeBytes("Content-Length: " + file.length() + lineEnd);
        outputStream.writeBytes(lineEnd);

        int bufferLength = 1024;
        for (int i = 0; i < bytes.length; i += bufferLength) {
            // publishing the progress....
            Bundle resultData = new Bundle();
            resultData.putInt("progress" ,(int)((i / (float) bytes.length) * 100));
            receiver.send(UPDATE_PROGRESS, resultData);

            if (bytes.length - i >= bufferLength) {
                outputStream.write(bytes, i, bufferLength);
            } else {
                outputStream.write(bytes, i, bytes.length - i);
            }
        }

        //end output
        outputStream.writeBytes(lineEnd);

        //write more parameters other than the file
        outputStream.writeBytes(twoHyphens + boundary + lineEnd);
        //outputStream.writeBytes(twoHyphens + boundary + lineEnd); //less twohyphens
        outputStream.writeBytes("Content-Disposition: form-data; name=\"invnum\"" + lineEnd);
        //outputStream.writeBytes("Content-Type: text/plain; charset=UTF-8" + lineEnd);
        //outputStream.writeBytes("Content-Length: " + invnum.length() + lineEnd);
        outputStream.writeBytes(lineEnd);
        outputStream.writeBytes(invnum + lineEnd);
        outputStream.writeBytes(twoHyphens + boundary + lineEnd);

        outputStream.writeBytes("Content-Disposition: form-data; name=\"pass\"" + lineEnd);
        //outputStream.writeBytes("Content-Type: text/plain; charset=UTF-8" + lineEnd);
        //outputStream.writeBytes("Content-Length: " + pass.length() + lineEnd);
        outputStream.writeBytes(lineEnd);
        outputStream.writeBytes(pass + lineEnd);
        outputStream.writeBytes(twoHyphens + boundary + twoHyphens + lineEnd);

        // publishing the progress....
        Bundle resultData = new Bundle();
        resultData.putInt("progress", 100);
        receiver.send(UPDATE_PROGRESS, resultData);

        outputStream.flush();
        outputStream.close();
        //input ignored for now

    } catch (MalformedURLException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

When running the app, the progress is reflected nicely but when checking on my server, no files are uploaded at all. In fact no data is sent or received by the server. Does anyone have any idea what may be causing this problem? Below is my server code.

$pass = $_POST['pass'];
$invnum = $_POST['invnum'];
$image = $_POST['image'];
if ($pass == 'password') {
    //do something
}

Updates: For a start, I'm getting a 404 error from the HTTPURLConnection. My url looks something like "http://www.xyz.com/upload.php". Update to the former sentence, by removing "setChunkedStreamingMode", I'm able to successfully upload the parameters to the server but not the image! I'm close!

dionkta
  • 181
  • 1
  • 1
  • 10

2 Answers2

7

Finally got it to work...

The line "connection.setChunkedStreamingMode(1024);" is causing the problem. After removing that, the upload of parameters and file succeeded. One minor issue remains, the progress of the upload is not accurate. The progress returned is actually the buffer being filled up which is almost instantaneous even for a 3MB image. The file is still being uploaded in the background after the progress reaches 100. Guess that will be another question for another time.

dionkta
  • 181
  • 1
  • 1
  • 10
  • 1
    Did you ever figure out how to solve this issue? I'm trying to do the same thing, but everyone seems to think they're tracking upload progress when they're actually just tracking the write to the butter (like you said). – Brian Nov 15 '13 at 21:57
  • thanks a lot dude..i was irritated of this problem from a week. finally done with your answer...really thanks a lot... – ELITE Mar 02 '16 at 15:27
0

In android HttpClient method better than HttpUrlConnection. I only show how exceute post method with HttpClient. I used this samly structer;

HttpClient client = new DefaultHttpClient();
HttpPost post = new HttpPost();
List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(<n>);// you have pass, invnum and image
nameValuePairs.add(new BasicNameValuePair("image", "<filName>"));
post.setEntity( new UrlEncodedFormEntity(nameValuePairs));
client.execute(post);
nurisezgin
  • 1,530
  • 12
  • 19
  • 1
    This method works but it is not what I'm looking for, I cannot track the progress of the upload using HttpClient. – dionkta Oct 09 '13 at 08:36
  • Maybe you will check http://stackoverflow.com/questions/7057342/how-to-get-a-progress-bar-for-a-file-upload-with-apache-httpclient-4 – nurisezgin Oct 09 '13 at 08:44
  • 1
    You are wrong about android httpclient methods is better. In general httpurlconnection has been improved more for newer versions of android. Read more here: http://android-developers.blogspot.de/2011/09/androids-http-clients.html – Warpzit Mar 04 '15 at 10:39