3

我有一个异步任务,应该在文件上传期间显示进度。一切正常,只是它看起来真的非常快地完成了文件上传,然后它就坐在那里 100% 等待。

我将其追溯到

URL url = new URL(urlServer);
connection = (HttpURLConnection) url.openConnection();

// Allow Inputs & Outputs
connection.setDoInput(true);
connection.setDoOutput(true);
connection.setUseCaches(false);

// Enable POST method
connection.setRequestMethod("POST");

connection.setRequestProperty("Connection", "Keep-Alive");
connection.setRequestProperty("Content-Type", "multipart/form-data;boundary=" + boundary);

outputStream = new DataOutputStream(connection.getOutputStream());
outputStream.writeBytes(twoHyphens + boundary + lineEnd);
outputStream.writeBytes("Content-Disposition: form-data; name=\"Filedata\";filename=\"" + pathToOurFile + "\"" + lineEnd);
outputStream.writeBytes(lineEnd);
long totalBytesWritten = 0;
while (bytesRead > 0) {
    outputStream.write(buffer, 0, bufferSize);
    outputStream.flush();
    if (mCancel) { throw new CancelException(); }

    totalBytesWritten += bufferSize;
    if (mProgressDialog != null) { 
            mProgressDialog.setProgress(Integer.valueOf((int) (totalBytesWritten / 1024L))); 
    }

    bytesAvailable = fileInputStream.available();
    bufferSize = Math.min(bytesAvailable, maxBufferSize);
    bytesRead = fileInputStream.read(buffer, 0, bufferSize);
}
outputStream.writeBytes(lineEnd);
outputStream.writeBytes(twoHyphens + boundary + twoHyphens + lineEnd);

// Responses from the server (code and message)
int serverResponseCode = connection.getResponseCode();

我注意到的是,直到它获取响应代码的最后一行之前没有真正的延迟。我认为正在发生的事情是数据正在缓冲,所以看起来它已经上传了它,但实际上并没有 - 它只是缓冲了它。然后当我调用 getResponseCode() 时,它别无选择,只能完成上传以获取上传状态。有什么方法可以让它实际上传,这样我才能得到合理的进展?

4

5 回答 5

2

这就是 HTTP Post 的设计方式,所以不要指望它会为您提供进度详细信息。

您可以使用市场上可用的几个文件上传器组件之一。他们在内部使用 flash 或 silverlight 或 iframe 来显示进度。

http://dhtmlx.com/docs/products/dhtmlxVault/index.shtml

http://www.element-it.com/multiple-file-upload/flash-uploader.aspx

如果你谷歌一下,你会发现很多这样的人。

他们在内部使用原始 IO 而不是 http post 来处理多个文件和进度通知。雅虎和谷歌也使用这种技术来制作邮件附件。

如果您真的喜欢冒险,您可以重新创建轮子 - 即编写您自己的组件。

编辑:

请指定是否要在 Windows 桌面应用程序或 Web 应用程序中执行此操作。

于 2012-09-10T06:10:19.263 回答
0

你可以这样做:

try { // open a URL connection to the Servlet
            FileInputStream fileInputStream = new FileInputStream(
                    sourceFile);
            URL url = new URL("http://10.0.2.2:9090/plugins/myplugin/upload");
            conn = (HttpURLConnection) url.openConnection();
            conn.setDoInput(true); // Allow Inputs
            conn.setDoOutput(true); // Allow Outputs
            conn.setUseCaches(false); // Don't use a Cached Copy
            conn.setRequestMethod("POST");
            conn.setRequestProperty("Connection", "Keep-Alive");
            conn.setRequestProperty("ENCTYPE", "multipart/form-data");
            conn.setRequestProperty("Content-Type",
                    "multipart/form-data;boundary=" + boundary);
            conn.setRequestProperty("uploadedfile", filename);
            // conn.setFixedLengthStreamingMode(1024);
            // conn.setChunkedStreamingMode(1);
            dos = new DataOutputStream(conn.getOutputStream());
            dos.writeBytes(twoHyphens + boundary + lineEnd);
            dos.writeBytes("Content-Disposition: form-data; name=\"uploadedfile\";filename=\""
                    + filename + "\"" + lineEnd);
            dos.writeBytes(lineEnd);
            bytesAvailable = fileInputStream.available();
            bufferSize = (int) sourceFile.length()/200;//suppose you want to write file in 200 chunks
            buffer = new byte[bufferSize];
            int sentBytes=0;
            // read file and write it into form...
            bytesRead = fileInputStream.read(buffer, 0, bufferSize);
            while (bytesRead > 0) {
                dos.write(buffer, 0, bufferSize);
                // Update progress dialog
                sentBytes += bufferSize;
                publishProgress((int)(sentBytes * 100 / bytesAvailable));
                bytesAvailable = fileInputStream.available();
                bytesRead = fileInputStream.read(buffer, 0, bufferSize);
            }
            // send multipart form data necesssary after file data...
            dos.writeBytes(lineEnd);
            dos.writeBytes(twoHyphens + boundary + twoHyphens + lineEnd);
            // Responses from the server (code and message)
            serverResponseCode = conn.getResponseCode();
            String serverResponseMessage = conn.getResponseMessage();
            // close streams
            fileInputStream.close();
            dos.flush();
            dos.close();
        } catch (MalformedURLException ex) {
            ex.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
于 2013-09-16T05:46:49.600 回答
0

您可以尝试使用 AsyncTask ...

在 onPreExecute 方法中创建一个进度对话框并在 onPostExecute 方法中关闭对话框。

将上传方法保留在 doInBackground() 中

例子 :

public class ProgressTask extends AsyncTask<String, Void, Boolean> {

    public ProgressTask(ListActivity activity) {
        this.activity = activity;
        dialog = new ProgressDialog(context);
    }

    /** progress dialog to show user that the backup is processing. */
    private ProgressDialog dialog;

    protected void onPreExecute() {
        this.dialog.setMessage("Progress start");
        this.dialog.show();
    }

        @Override
    protected void onPostExecute(final Boolean success) {
        if (dialog.isShowing()) {
            dialog.dismiss();
        }           
    }

    protected Boolean doInBackground(final String... args) {

// 你的上传代码

          return true;
       }
    }
}
于 2012-09-10T06:28:37.380 回答
0

HttpURLConnection.setFixedLengthStreamingMode(...) 成功了!

于 2012-09-10T14:06:38.747 回答
0

您可以按如下方式使用 Progress Dialog 类,

ProgressDialog progDailog = ProgressDialog.show(this,"Uploading", "Uploading File....",true,true);

new Thread ( new Runnable()
{
     public void run()
     {
      // your loading code goes here
     }
}).start();

Handler progressHandler = new Handler() 
{
     public void handleMessage(Message msg1) 
     {
         progDailog.dismiss();
     }
}
于 2012-09-10T06:06:41.427 回答