简体   繁体   中英

Android: Show real uploading progress percentage

I need to upload a large generated pdf file to the server and show uploading progress to the user. But the problem is the percentage I got from OutputStream is not the real progress because after 100% progress of OutputStream, still cannot get response code from the server (need to wait for more)

Please help me with this problem. Thank you.

** For more information: the total uploading time is 15 minutes but the progress percentage finish in a second.

class UploadPdf extends AsyncTask<String, Integer, String> {

    private Activity activity;
    private String orderId = "";
    private String filenamepdf = "";
    private String filenamezip = "";
    private int dpi = 640;
    public ImageCreator mImageCreator;

    public UploadPdf(Activity activity) {
        this.activity = activity;
    }

    @Override
    protected String doInBackground(String... strings) {
        orderId = strings[0];
        filenamepdf = orderId + ".pdf";

        String uploadStatus = uploadFileToServer();
        return uploadStatus;
    }

    @Override
    protected void onProgressUpdate(Integer... progress) {
        //Update progress
        updateProgress(progress[0]);
    }

    @Override
    protected void onPostExecute(String result) {
        //Show result
        try {
            JSONObject obj = new JSONObject(result);
            if(obj.getString("status").equals("success")) {
                uploadSuccess();
            } else {
                errorContainer.setVisibility(View.VISIBLE);
            }

        } catch (Exception ex) {
            errorContainer.setVisibility(View.VISIBLE);
        }
    }

    private String uploadFileToServer() {
        Log.d(LOGTAG, "uploadFileToServer");
        String urlString = Constants.API_BASE_URL + Constants.API_CREATE_UPLOAD_FILE;

        String response = null;
        String attachmentName = "attachment";
        String attachmentFileName = "attachment";
        String crlf = "\r\n";
        String twoHyphens = "--";
        String boundary = "*****";

        try {
            File file = new File(filenamepdf);
            MultipartUtility multipart = new MultipartUtility(urlString, "UTF-8", getApplicationContext());

            multipart.addFormField("order_id", orderId);
            multipart.addFilePart("album_image_path", file);

            List<String> responseReturn = multipart.finish();
            Log.e(LOGTAG, "SERVER REPLIED:");
            response = "";
            for (String line : responseReturn) {
                Log.e(LOGTAG, "Upload Files Response:::" + line);
                response += line;
            }
        } catch (Exception ex) {
            Log.e(LOGTAG, "Failed:" + ex.getMessage());
        }

        Log.e(LOGTAG, "Response:" + response);
        return response;
    }

    public class MultipartUtility {
        private final String LOGTAG = "MultipartUtility";
        private final String boundary;
        private static final String LINE_FEED = "\r\n";
        private HttpURLConnection httpConn;
        private String charset;
        private OutputStream outputStream;
        private PrintWriter writer;
        Context context;

        /**
         * This constructor initializes a new HTTP POST request with content type
         * is set to multipart/form-data
         *
         * @param requestURL
         * @param charset
         * @throws IOException
         */
        public MultipartUtility(String requestURL, String charset, Context context)
                throws IOException {
            this.charset = charset;
            this.context = context;

            // creates a unique boundary based on time stamp
            boundary = "===" + System.currentTimeMillis() + "===";
            URL url = new URL(requestURL);
            httpConn = (HttpURLConnection) url.openConnection();
            httpConn.setUseCaches(false);
            httpConn.setDoOutput(true);    // indicates POST method
            httpConn.setDoInput(true);
            httpConn.setRequestProperty("Content-Type",
                    "multipart/form-data; boundary=" + boundary);
            outputStream = httpConn.getOutputStream();
            writer = new PrintWriter(new OutputStreamWriter(outputStream, charset),
                    true);
        }

        /**
         * Adds a form field to the request
         *
         * @param name  field name
         * @param value field value
         */
        public void addFormField(String name, String value) {
            Log.d(LOGTAG, "name: " + name + ", value: " + value);
            writer.append("--" + boundary).append(LINE_FEED);
            writer.append("Content-Disposition: form-data; name=\"" + name + "\"")
                    .append(LINE_FEED);
            writer.append("Content-Type: text/plain; charset=" + charset).append(
                    LINE_FEED);
            writer.append(LINE_FEED);
            writer.append(value).append(LINE_FEED);
            writer.flush();
        }


        /**
         * Adds a upload file section to the request
         *
         * @param fieldName  name attribute in <input type="file" name="..." />
         * @param uploadFile a File to be uploaded
         * @throws IOException
         */
        public void addFilePart(String fieldName, File uploadFile) throws IOException {
            String fileName = uploadFile.getName();
            Log.d(LOGTAG, fieldName);
            writer.append("--" + boundary).append(LINE_FEED);
            writer.append(
                    "Content-Disposition: form-data; name=\"" + fieldName
                            + "\"; filename=\"" + fileName + "\"")
                    .append(LINE_FEED);
            writer.append(
                    "Content-Type: "
                            + URLConnection.guessContentTypeFromName(fileName))
                    .append(LINE_FEED);
            writer.append("Content-Transfer-Encoding: binary").append(LINE_FEED);
            writer.append(LINE_FEED);
            writer.flush();

            FileInputStream inputStream = new FileInputStream(uploadFile);

            byte[] bytes = new byte[(int) uploadFile.length()];
            int byteLength = bytes.length;
            byte[] buffer = new byte[4096];
            int bytesRead = -1;
            int sendByte = 0;
            while ((bytesRead = inputStream.read(buffer)) != -1) {
                outputStream.write(buffer, 0, bytesRead);
                sendByte += bytesRead;
                int progress = (int)(sendByte / (float) byteLength * 100);
                Log.d(LOGTAG, "bytesRead: " + bytesRead + ", byteLength: " + byteLength + ", progress: " + progress);
                publishProgress(progress);
            }
            outputStream.flush();
            Log.d(LOGTAG, "Read byte finish");
            outputStream.close();
            Log.d(LOGTAG, "Close output stream");

            inputStream.close();
            Log.d(LOGTAG, "Close input stream");
            writer.append(LINE_FEED);
            writer.flush();
            Log.d(LOGTAG, "Writer flushed");
        }
        public void addHeaderField(String name, String value) {
            writer.append(name + ": " + value).append(LINE_FEED);
            writer.flush();
        }

        public List<String> finish() throws IOException {
            Log.d(LOGTAG, "Finishing");
            List<String> response = new ArrayList<String>();
            writer.append(LINE_FEED).flush();
            Log.d(LOGTAG, "Line feed flushed");
            writer.append("--" + boundary + "--").append(LINE_FEED);
            Log.d(LOGTAG, "Last line flushed");
            writer.close();
            Log.d(LOGTAG, "Writer closed");

            // checks server's status code first
            int status = httpConn.getResponseCode();
            Log.d(LOGTAG, "Server returned status: " + status);
            if (status == HttpURLConnection.HTTP_OK) {
                BufferedReader reader = new BufferedReader(new InputStreamReader(
                        httpConn.getInputStream()));
                String line = null;
                while ((line = reader.readLine()) != null) {
                    response.add(line);
                }
                reader.close();
                httpConn.disconnect();
            } else {
                throw new IOException("Server returned non-OK status: " + status);
            }
            return response;
        }
    }
}

to begin with I will suggest using the OKHTTP MultipartBody that's way better api to use here is a same class you can use just as you use MultiPart utility

public class MultipartRequest {
    public Context caller;
    public MultipartBody.Builder builder;
    private OkHttpClient client;

    public MultipartRequest(Context caller) {
        this.caller = caller;
        this.builder = new MultipartBody.Builder();
        this.builder.setType(MultipartBody.FORM);
        this.client = new OkHttpClient();
    }

    public void addString(String name, String value) {
        this.builder.addFormDataPart(name, value);
    }

    public void addFile(String name, String filePath, String fileName) {
        this.builder.addFormDataPart(name, fileName, RequestBody.create(
                MediaType.parse("image/jpeg"), new File(filePath)));
    }

    public void addTXTFile(String name, String filePath, String fileName) {
        this.builder.addFormDataPart(name, fileName, RequestBody.create(
                MediaType.parse("text/plain"), new File(filePath)));
    }

    public void addZipFile(String name, String filePath, String fileName)
    {
        this.builder.addFormDataPart(name, fileName, RequestBody.create(
                MediaType.parse("application/zip"), new File(filePath)));
    }

    public String execute(String url,String header) {
        RequestBody requestBody = null;
        Request request = null;
        Response response = null;

        int code = 200;
        String strResponse = null;

        try {
            requestBody = this.builder.build();
            request = new Request.Builder().header("Authorization", header)
                    .url(url).post(requestBody).build();



            Log.e("::::::: REQ :: " , ""+request);
            response = client.newCall(request).execute();
            Log.e("::::::: response :: " ,""+ response);

            if (!response.isSuccessful())
                throw new IOException();

            code = response.networkResponse().code();

            if (response.isSuccessful()) {
                strResponse = response.body().string();
            } else {

            }
        } catch (Exception e) {
            Log.e("Exception", ""+e);

        } finally {
            requestBody = null;
            request = null;
            response = null;
            builder = null;
            if (client != null)
                client = null;
            System.gc();
        }
        return strResponse;
    }
}

now to address your concern on how to get the progress here is a solution offerend on SO please check this out

OKHTTP 3 Tracking Multipart upload progress

that's a real good solution.

Here how i implemented this.

public class UploadFile extends Service {

    NotificationManager mNotifyManager;
    NotificationCompat.Builder mBuilder;
    private static final String TAG = "HelloService";

    private boolean isRunning  = false;

    @Override
    public void onCreate() {
        Log.i(TAG, "Service onCreate");

        isRunning = true;
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        mNotifyManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
        mBuilder = new NotificationCompat.Builder(UploadFile.this);
        mBuilder.setContentTitle("File uploaded").setSmallIcon(
                R.drawable.myicons);
        UpadtePost();
        return Service.START_STICKY;
    }
    private void UpadtePost() {

        new UploadFileToServer().execute();
    }
    private class UploadFileToServer extends AsyncTask<Void, Integer, String> {

        protected void onPreExecute() {
            // setting progress bar to zero
            mBuilder.setProgress(100, 0, false);
            mNotifyManager.notify(0, mBuilder.build());
            super.onPreExecute();
        }

        @Override
        protected void onProgressUpdate(Integer... progress) {
            mBuilder.setProgress(100,
                    Integer.parseInt(String.valueOf(progress[0])), false);
            mNotifyManager.notify(0, mBuilder.build());
        }

        @Override
        protected String doInBackground(Void... params) {
            return uploadFile();
        }

        private String uploadFile() {
            String responseString = null;

            HttpClient httpclient = new DefaultHttpClient();
            HttpPost httppost = new HttpPost(****);

            try {
                AndroidMultiPartEntity entity = new AndroidMultiPartEntity(
                        new AndroidMultiPartEntity.ProgressListener() {
                            public void transferred(long num) {
                                publishProgress((int) ((num / (float) totalSize) * 100));
                            }
                        });

                File sourceFile = new File(orignal1);
                entity.addPart("image", new FileBody(sourceFile));
                totalSize = entity.getContentLength();
                httppost.setEntity(entity);

                // Making server call
                HttpResponse response = httpclient.execute(httppost);
                HttpEntity r_entity = response.getEntity();

                int statusCode = response.getStatusLine().getStatusCode();
                if (statusCode == 200) {
                    // Server response
                    responseString = EntityUtils.toString(r_entity);
                } else {
                    responseString = "Error occurred! Http Status Code: "
                            + statusCode;
                }

            } catch (ClientProtocolException e) {
                responseString = e.toString();
            } catch (IOException e) {
                responseString = e.toString();


            }
            return responseString;

        }

        @Override
        protected void onPostExecute(String result) {
                session.showNot(result);
                mBuilder.setContentText("Upload complete").setProgress(0, 0,false);
                mNotifyManager.notify(6532365, mBuilder.build());
                mNotifyManager.cancel(6532365);
            super.onPostExecute(result);
        }
    }
    @Override
    public IBinder onBind(Intent arg0) {
        Log.i(TAG, "Service onBind");
        return null;
    }

    @Override
    public void onDestroy() {

        isRunning = false;

        Log.i(TAG, "Service onDestroy");
    }
}

Multipart class

public class AndroidMultiPartEntity extends MultipartEntity

{

    private final ProgressListener listener;

    public AndroidMultiPartEntity(final ProgressListener listener) {
        super();
        this.listener = listener;
    }

    public AndroidMultiPartEntity(final HttpMultipartMode mode,
                                  final ProgressListener listener) {
        super(mode);
        this.listener = listener;
    }

    public AndroidMultiPartEntity(HttpMultipartMode mode, final String boundary,
                                  final Charset charset, final ProgressListener listener) {
        super(mode, boundary, charset);
        this.listener = listener;
    }

    @Override
    public void writeTo(final OutputStream outstream) throws IOException {
        super.writeTo(new CountingOutputStream(outstream, this.listener));
    }

    public static interface ProgressListener {
        void transferred(long num);
    }

    public static class CountingOutputStream extends FilterOutputStream {

        private final ProgressListener listener;
        private long transferred;

        public CountingOutputStream(final OutputStream out,
                                    final ProgressListener listener) {
            super(out);
            this.listener = listener;
            this.transferred = 0;
        }

        public void write(byte[] b, int off, int len) throws IOException {
            out.write(b, off, len);
            this.transferred += len;
            this.listener.transferred(this.transferred);
        }

        public void write(int b) throws IOException {
            out.write(b);
            this.transferred++;
            this.listener.transferred(this.transferred);
        }
    }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM