1

I am working on a piece of code to do multipart form data POST request, which in my case is just to upload an image to server with parameters. Here's what I have now:

I have a button to trigger the multipart request, in the button OnClickListener, I have this code to spin a new thread:

new Thread(new Runnable(){

@Override
public void run() {

    String photoUri = getPhotoUri();
    String url = getEndPointUrl();

    try {   

    NewPostRequest.postFile(url, photoUri, <Other Params...>);

    } catch (Exception e) {
        // Exception Handling           
    } 
}).start();

And the NewPostRequest.postFile is just using Apache Http Client to make a request, basically like below:

HttpClient client = new DefaultHttpClient();

HttpPost post = new HttpPost(url);

MultipartEntityBuilder builder = MultipartEntityBuilder.create();    

builder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);

File file = new File(fileUri);

FileBody fb = new FileBody(file);

builder.addPart("file", fb);

builder.addTextBody("param", otherParam);

HttpEntity entity = builder.build();

post.setEntity(entity);

HttpResponse response = client.execute(post);      

I need to spin a new thread everytime because the recent Android releases doesn't let program to make http requests on UI thread. However, I really against to spin a random thread and let it out of control like the code above. I have tried to use Google Volley library, but it is not a handful tool when uploading large data files like image.

I was wondering what I should do to make this call more manageable?

===== UPDATE =====

I switched to use AsyncTask and it works OK for now. I will keep this question open to see if any one has better approach.

Allan Jiang
  • 11,063
  • 27
  • 104
  • 165

3 Answers3

10

HTTP has always been a pain point in Android. Fortunately, we have many great libraries that take care of all the hard parts.

Try out Ion.

It allows you to easily do Multi-Part requests in a background thread and let's you get callbacks on the main thread when the request is complete.

It also does other cool stuff like intelligent caching, automatic request cancellation when the calling Context goes out of scope etc.

P.S: Retrofit is another great library but I prefer Ion myself. Just a matter of preference.

Anup Cowkur
  • 20,443
  • 6
  • 51
  • 84
4

The solution for the above problem related to uploading .db(any extension) file to the server : Below are the steps to upload a file :

1 :- new AsynUpload().execute();

2 :-

class AsynUpload extends AsyncTask<Void,Integer,String>
        {
        String result="";
        ProgressDialog dialog=null;
        String iFileName = CONST.USER_NAME+".db";
        String lineEnd = "\r\n";
        String twoHyphens = "--";
        String boundary = "*****";
        String Tag="fSnd";

        @Override
        protected void onPreExecute()
        {
        Log.i("AsynUpload is callinmg...", "calling");
        dialog=new ProgressDialog(Upload_Database.this);
        dialog.setMessage("File uploading...");
        dialog.setCancelable(false);
        dialog.show();
        }

        @Override
        protected String doInBackground(Void... params) {
        try 
        {
        UTILITIES.copyDBToSDCard();
        String selectedFilePath = "/data/data/com.DxS.androidSunTec.visioapp/databases/"+CONST.USER_NAME+".db";
        FileInputStream fstrm = new FileInputStream(selectedFilePath);
        URL connectURL = new URL(CUSTOM_URL.UPLOAD_URL+"Default.aspx");
        HttpURLConnection conn = (HttpURLConnection)connectURL.openConnection();
        // Allow Inputs
        conn.setDoInput(true);
        // Allow Outputs
        conn.setDoOutput(true);
        // Don't use a cached copy.
        conn.setUseCaches(false);
        // Use a post method.
        conn.setRequestMethod("POST");
        conn.setRequestProperty("Connection", "Keep-Alive");
        conn.setRequestProperty("Content-Type", "multipart/form-data;boundary="+boundary);
        conn.setRequestProperty("FILE_NAME", ""+CONST.USER_NAME+".db");
        DataOutputStream dos = new DataOutputStream(conn.getOutputStream());
        dos.writeBytes(twoHyphens + boundary + lineEnd);
        dos.writeBytes("Content-Disposition: form-data; name=\"title\""+ lineEnd);
        dos.writeBytes(lineEnd);
        dos.writeBytes(""+CONST.USER_NAME);
        dos.writeBytes(lineEnd);
        dos.writeBytes(twoHyphens + boundary + lineEnd);                    
        dos.writeBytes("Content-Disposition: form-data; name=\"description\""+ lineEnd);
        dos.writeBytes(lineEnd);
        dos.writeBytes(loc_code+"~"+user_code+"~"+fyid);
        dos.writeBytes(lineEnd);
        dos.writeBytes(twoHyphens + boundary + lineEnd);
        dos.writeBytes("Content-Disposition: form-data; name=\"uploadedfile\";filename=\"" + iFileName +"\"" + lineEnd);
        dos.writeBytes(lineEnd);

        // create a buffer of maximum size
        int bytesAvailable = fstrm.available();

        int maxBufferSize = 1024;
        int bufferSize = Math.min(bytesAvailable, maxBufferSize);
        byte[ ] buffer = new byte[bufferSize];

        // read file and write it into form...
        int bytesRead = fstrm.read(buffer, 0, bufferSize);

            while (bytesRead > 0)
            {
            dos.write(buffer, 0, bufferSize);
            bytesAvailable = fstrm.available();
            bufferSize = Math.min(bytesAvailable,maxBufferSize);
            bytesRead = fstrm.read(buffer, 0,bufferSize);
            }
            dos.writeBytes(lineEnd);
            dos.writeBytes(twoHyphens + boundary + twoHyphens + lineEnd);

            // close streams
            fstrm.close();
            // 103424
            dos.flush();
            InputStream is = conn.getInputStream();

            // retrieve the response from server
            int ch;

            StringBuffer b =new StringBuffer();
            while( ( ch = is.read() ) != -1 ){ b.append( (char)ch ); }
            String s=b.toString();
            Log.i("Response",s);
            dos.close();

            result="OK";
            }

            catch (MalformedURLException ex)
            {
            result = "MalformedURLException";
            Log.i(Tag, "URL error: " + ex.getMessage(), ex);
            }
            catch (IOException ioe)
            {
            result = "IOException";
            Log.i(Tag, "IO error: " + ioe.getMessage(), ioe);
            }
            catch(Exception e)
            {
            Log.e("Exception","Exception"+e.getMessage());
            result="FAILURE";
            }
            finally
            {
            if (result.equalsIgnoreCase("OK"))
            {
            File file = new File("/data/data/com.test.app/databases/"+CONST.USER_NAME+".db");
                if(file.exists())
                {
                file.delete();
                Log.i("uploading database file Deleted from sd card :", "deleted");
                }
            file = new File("/data/data/com.test.app/databases/"+DatabaseHelper.DB_NAME);
                if(file.exists())
                {
                file.delete();
                Log.i("Original database file Deleted from sd card :", "deleted");
                }

                MyActivity.this.runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                    // TODO Auto-generated method stub
                    AlertDialog.Builder builder = new AlertDialog.Builder(MyActivity.this);
                    LayoutInflater inflater = getLayoutInflater();
                    View vw = inflater.inflate(R.layout.custom_title, null);
                    builder.setCustomTitle(vw);
                    builder.setMessage("File uploaded successfully!")
                    .setCancelable(false)
                    .setPositiveButton("OK", new DialogInterface.OnClickListener() {
                        public void onClick(DialogInterface dialog, int id) {
                            dialog.cancel();
                            finish();
                            }
                        });
                            builder.create();
                            builder.show();
                            }
                        });
                        }
                    else
                    {
                    MyActivity.this.runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                        AlertDialog.Builder builder = new AlertDialog.Builder(MyActivity.this);
                        LayoutInflater inflater = getLayoutInflater();
                        View vw = inflater.inflate(R.layout.custom_title, null);
                    builder.setCustomTitle(vw);
                    builder.setMessage("File uploading failed, please try again!")
                    .setCancelable(false)
                    .setPositiveButton("OK", new DialogInterface.OnClickListener() {
                        public void onClick(DialogInterface dialog, int id) {
                                dialog.cancel();
                                }
                            });
                                builder.create();
                                builder.show();
                                }
                            });
                            }
                              }
                            return result;
                        }   

                         @Override
                         protected void onProgressUpdate(Integer... values)
                         {
                             super.onProgressUpdate(values);
                         // dialog.incrementProgressBy(5);   
                        }
                        @Override
                        protected void onPostExecute(String result)
                        {
                            dialog.dismiss();

                            if (result.equalsIgnoreCase("OK"))
                            {
                            }
                            else
                            {
                            }
                        }
                      }

3.) UTILITIES class:

public static void copyDBToSDCard() {
        try {
            InputStream myInput = new FileInputStream("/data/data/com.DxS.androidSunTec.visioapp/databases/"+DatabaseHelper.DB_NAME);

            Log.i("sd card path: ", ""+Environment.getExternalStorageDirectory().getPath().toString());

        //    File file = new File(Environment.getExternalStorageDirectory().getPath()+"/"+CONST.USER_NAME+".db");
            File file = new File("/data/data/com.DxS.androidSunTec.visioapp/databases/"+CONST.USER_NAME+".db");
            if (!file.exists()){
                try {
                    file.createNewFile();
                } catch (IOException e) {
                    Log.i("FO","File creation failed for " + file);
                }
            }

       //     OutputStream myOutput = new FileOutputStream(Environment.getExternalStorageDirectory().getPath()+"/"+CONST.USER_NAME+".db");
            OutputStream myOutput = new FileOutputStream("/data/data/com.DxS.androidSunTec.visioapp/databases/"+CONST.USER_NAME+".db");

            byte[] buffer = new byte[1024];
            int length;
            while ((length = myInput.read(buffer))>0){
                myOutput.write(buffer, 0, length);
            }

            //Close the streams
            myOutput.flush();
            myOutput.close();
            myInput.close();
            Log.i("FO","copied");

        } catch (Exception e) {
            Log.i("FO","exception="+e);
        }
}
Gopal Singh Sirvi
  • 4,539
  • 5
  • 33
  • 55
Maddy Sharma
  • 4,870
  • 2
  • 34
  • 40
-2

1) Create Native Android Plugin for uploading Multiple files along with JSON Object. 2) Concept is Multipart file upload. 3) Create for offline mode sync. 4) Phonegap and Android Native Code.

Javascript Call for Native Andorid Code

alert(window.FilesUpload.sendFiles(JSON.stringify(jsonObj)));

Below is the Android Plugin (FilesUpload.java)

package com.yourpackagename.core;
import java.io.*;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.ResponseHandler;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.BasicResponseHandler;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.entity.mime.HttpMultipartMode;
import org.apache.http.entity.mime.MultipartEntity;
import org.apache.http.entity.mime.content.FileBody;
import org.apache.http.entity.mime.content.StringBody;
import org.json.JSONArray;
import org.json.JSONObject;


public class FilesUpload
{
   public FilesUpload() {

   }

   public String sendFiles(String s) {       


       String responseBody = "";

       try
       {

          JSONObject jsonObject = new JSONObject(s);   

          int len_outer = jsonObject.getJSONArray("electricityExpenseManagement").getJSONObject(0).length();

          HttpClient httpclient = new DefaultHttpClient();

          HttpPost httppost = new HttpPost("http://yourservername.com/php_file_upload/file_upload2.php");

          MultipartEntity reqEntity = new MultipartEntity(HttpMultipartMode.BROWSER_COMPATIBLE);          

          StringBody elecExpObj = new StringBody(s);

          reqEntity.addPart("elecExpObj", elecExpObj);



           for(int i=0;i<len_outer;i++)
           {
               int bill_count = jsonObject.getJSONArray("electricityExpenseManagement").getJSONObject(i).getJSONArray("electricityExpenseBillInfoData").length();

               for(int j=0;j<bill_count;j++)
               {
                   String sourceFileUri = jsonObject.getJSONArray("electricityExpenseManagement").getJSONObject(0).getJSONArray("electricityExpenseBillInfoData").getJSONObject(j).getString("image_path");

                   String partName = jsonObject.getJSONArray("electricityExpenseManagement").getJSONObject(i).getJSONArray("electricityExpenseBillInfoData").getJSONObject(j).getString("image_base64_encode");                

                   FileBody bin = new FileBody(new File(sourceFileUri));

                   reqEntity.addPart(partName, bin);                   
               }
           }

           httppost.setEntity(reqEntity);          
           System.out.println("Requesting : " + httppost.getRequestLine());
           ResponseHandler<String> responseHandler = new BasicResponseHandler();
           responseBody = httpclient.execute(httppost, responseHandler);
           System.out.println("responseBody : " + responseBody);

           return responseBody;

      }
      catch (UnsupportedEncodingException e) {
         e.printStackTrace();
         return e.getMessage(); 
      }
      catch (ClientProtocolException e) {
         e.printStackTrace();
         return e.getMessage(); 
      }
      catch (IOException e) {
         e.printStackTrace();
         return e.getMessage(); 
      }
      catch(Exception e){
         e.printStackTrace();
         System.out.println("error");
         return e.getMessage();     
      }

   }
}

Main Android Java File (Define plugin class)

package com.yourpackagename.core;

import android.os.Bundle;
import org.apache.cordova.*;

public class Waterhealth extends DroidGap
{

    private FilesUpload f;

    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        // Set by <content src="index.html" /> in config.xml

        super.init();

        f = new FilesUpload();
        appView.addJavascriptInterface(f, "FilesUpload");


        super.loadUrl(Config.getStartUrl());
        super.loadUrl("file:///android_asset/elect_exp_FS/index.html");
    }
}

PHP Script for uploading files (Webservice)

<?php

if(isset($_REQUEST['elecExpObj']))
{        
        $obj= json_decode(stripslashes($_REQUEST['elecExpObj']));
        $len = count($obj->electricityExpenseManagement);
        $str = "";
        for($i=0;$i<$len;$i++)
        {
           $bill_count = count($obj->electricityExpenseManagement[$i]->electricityExpenseBillInfoData);
           for($j=0;$j<$bill_count;$j++)
           {
            $filePath = $obj->electricityExpenseManagement[$i]->electricityExpenseBillInfoData[$j]->image_base64_encode;


            if($_FILES[$filePath]['name'])
            {
              if(!$_FILES[$filePath]['error'])
          {
                 $new_file_name = $filePath . rand() . ".jpg"; //rename file    
                 move_uploaded_file($_FILES[$filePath]['tmp_name'], 'uploads/'.$new_file_name);
         $str .= 'Congratulations!  Your file was accepted.';                 
              }
            }
           }
        }
    echo $str;
}
else{
    echo "fail";
}
?>
Flexo
  • 87,323
  • 22
  • 191
  • 272
Husain A.
  • 47
  • 2
  • 9
  • 1
    This does not seem to really be an answer to the question specifically (just a code dump that's only tangentially related) and there's spam links that are not relevant at all. – laalto Feb 11 '14 at 10:29