Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/android/189.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Can';t抓取http POST文件上传进度(Android)_Android_Http_Post_Upload_Progress - Fatal编程技术网

Can';t抓取http POST文件上传进度(Android)

Can';t抓取http POST文件上传进度(Android),android,http,post,upload,progress,Android,Http,Post,Upload,Progress,我正在开发一个Android应用程序,使用户可以将文件上传到Twitpic等服务。 上传后没有任何外部库,效果很好。我唯一的问题是,我无法获取任何进度,因为所有上传都是在我收到响应时完成的,而不是在将字节写入outputstream时完成的。 以下是我的工作: URL url = new URL(urlString); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setDoInput(true

我正在开发一个Android应用程序,使用户可以将文件上传到Twitpic等服务。 上传后没有任何外部库,效果很好。我唯一的问题是,我无法获取任何进度,因为所有上传都是在我收到响应时完成的,而不是在将字节写入outputstream时完成的。 以下是我的工作:

URL url = new URL(urlString); 
HttpURLConnection conn = (HttpURLConnection) url.openConnection(); 
conn.setDoInput(true); 
conn.setDoOutput(true); 
conn.setUseCaches(false); 
conn.setRequestMethod("POST"); 
conn.setRequestProperty("Connection", "Keep-Alive"); 
conn.setRequestProperty("Content-Type", "multipart/form-data;boundary=" + boundary); 
DataOutputStream dos = new DataOutputStream(conn.getOutputStream());
然后我将表单数据写入dos,现在这在这里并不重要。之后,我写入文件数据本身(从“in”读取,这是我要发送的数据的输入流):

之后,我发送多部分表单数据以指示文件的结尾。然后,我关闭溪流:

in.close(); 
dos.flush(); 
dos.close(); 
这一切都很好,到目前为止没有问题。然而,我的问题是,到目前为止,无论文件有多大,整个过程都需要大约1到2秒钟。 当我阅读回复时,上传本身似乎发生了:

DataInputStream inStream = new DataInputStream(conn.getInputStream());
这需要几秒钟或几分钟,具体取决于文件的大小和internet连接的速度。 我现在的问题是: 1) 为什么在我将字节写入“dos”时不发生上传? 2) 我怎样才能抓取一个进度,以便在上传过程中同时显示一个进度对话框

/编辑: 1) 我在标题中设置了内容长度,这稍微改变了问题,但在任何情况下都不会 解决方法: 现在,在将最后一个字节写入流后,将上载整个内容。因此,这并不能改变无法获取进度的情况,因为数据是立即写入的。 2) 我在ApacheHttpClient v4中尝试了多端口。这里根本没有OutputStream,因为所有数据都是在执行请求时写入的。所以再一次,没有办法取得进展


有没有人对如何在多部分/表单上传中获取流程有任何其他想法?

在过去的几天里,我已经尝试了很多,我想我已经找到了最初问题的答案:

无法使用HttpURLConnection获取进度,因为Android中存在错误/异常行为:

这将是固定后弗罗约,这是不能等待的事情

因此,我发现的唯一其他选择是使用ApacheHttpClient。正确,但它指的是通用Java。那里使用的类在Android中不再可用(HttpClient 3.1曾经是SDK的一部分)。因此,您可以添加来自HttpClient 4(特别是apache-mime4j-0.6.jar和HttpTime-4.0.1.jar)的库,并使用第一个答案(由Tuler提供)和最后一个答案(由Hamy提供)的组合:

这适用于HttpClient 4,但缺点是我的apk现在的大小为235 kb(当我使用问题中描述的多部分上传时为90 kb),更糟糕的是,安装的应用程序大小为735 kb(以前约为170 kb)。
那太可怕了。只有在上传过程中才能获得进度,应用程序大小现在是以前的4倍多。

可以从DefaultHttpClient获取进度。事实是它一直在排队

response = defaultHttpClient.execute( httpput, context );
在发送完整的数据之前,并不一定意味着您无法获取进度。也就是说,HttpContext在执行这一行时会发生变化,所以如果您通过不同的线程接近它,您可能会观察到其中的变化。你需要的是适配器。它嵌入了HttpConnectionMetrics

final AbstractClientConnAdapter connAdapter = (AbstractClientConnAdapter) context.getAttribute(ExecutionContext.HTTP_CONNECTION);
final HttpConnectionMetrics metrics = connAdapter.getMetrics();
int bytesSent = (int)metrics.getSentBytesCount();

如果您定期检查,您将观察进度。确保正确处理线程,并保护所有try/catch。特别是,处理上下文不再有效(IllegalStateException)的情况,该情况在Put被取消或完成时发生。

请改用WatchedInputStream。 它很好用,很好用

  • 使用WatchedInputStream包装输入流
  • watchedStream.setListener

    setListener(新的WatchedInputStream.Listener(){

    公共无效通知(整型读取){ //执行某些操作以更新UI。
    } }


  • 试试这个,它很管用

    connection = (HttpURLConnection) url_stripped.openConnection();
        connection.setRequestMethod("PUT");
        String boundary = "---------------------------boundary";
        String tail = "\r\n--" + boundary + "--\r\n";
        connection.addRequestProperty("Content-Type", "image/jpeg");
        connection.setRequestProperty("Connection", "Keep-Alive");
        connection.setRequestProperty("Content-Length", ""
                + file.length());
        connection.setDoOutput(true);
    
        String metadataPart = "--"
                + boundary
                + "\r\n"
                + "Content-Disposition: form-data; name=\"metadata\"\r\n\r\n"
                + "" + "\r\n";
    
        String fileHeader1 = "--"
                + boundary
                + "\r\n"
                + "Content-Disposition: form-data; name=\"uploadfile\"; filename=\""
                + fileName + "\"\r\n"
                + "Content-Type: application/octet-stream\r\n"
                + "Content-Transfer-Encoding: binary\r\n";
    
        long fileLength = file.length() + tail.length();
        String fileHeader2 = "Content-length: " + fileLength + "\r\n";
        String fileHeader = fileHeader1 + fileHeader2 + "\r\n";
        String stringData = metadataPart + fileHeader;
    
        long requestLength = stringData.length() + fileLength;
        connection.setRequestProperty("Content-length", ""
                + requestLength);
        connection.setFixedLengthStreamingMode((int) requestLength);
        connection.connect();
    
        DataOutputStream out = new DataOutputStream(
                connection.getOutputStream());
        out.writeBytes(stringData);
        out.flush();
    
        int progress = 0;
        int bytesRead = 0;
        byte buf[] = new byte[1024];
        BufferedInputStream bufInput = new BufferedInputStream(
                new FileInputStream(file));
        while ((bytesRead = bufInput.read(buf)) != -1) {
            // write output
            out.write(buf, 0, bytesRead);
            out.flush();
            progress += bytesRead;
            // update progress bar
            publishProgress(progress);
        }
    
        // Write closing boundary and close stream
        out.writeBytes(tail);
        out.flush();
        out.close();
    
        // Get server response
        BufferedReader reader = new BufferedReader(
                new InputStreamReader(connection.getInputStream()));
        String line = "";
        StringBuilder builder = new StringBuilder();
        while ((line = reader.readLine()) != null) {
            builder.append(line);
        }
    

    参考资料:

    也许这个答案会给你一些提示:@pableu:我已经研究过了。问题是:Android SDK中没有RequestEntity。它是Apache HttpClient 3.1的一部分,Android不再使用它。现在,我甚至尝试加载新的4.0.1库,但我认为没有可能在这里取得进展。还有其他想法吗?关于关于.apk和安装大小,您在SourceForge上查看过ProGuard吗?它会将您的应用程序缩小到原来的位置,甚至更小:)这是一个非常好的解决方案!非常感谢发布您不再需要apache-mime4j-0.6.jar,因为在4.1 alpha 2版以后的版本中,apache-mime4j-0.6.jar的依赖项被删除。它不能正确使用InputStreamBody。字节数与原始文件不匹配。
    final AbstractClientConnAdapter connAdapter = (AbstractClientConnAdapter) context.getAttribute(ExecutionContext.HTTP_CONNECTION);
    final HttpConnectionMetrics metrics = connAdapter.getMetrics();
    int bytesSent = (int)metrics.getSentBytesCount();
    
    connection = (HttpURLConnection) url_stripped.openConnection();
        connection.setRequestMethod("PUT");
        String boundary = "---------------------------boundary";
        String tail = "\r\n--" + boundary + "--\r\n";
        connection.addRequestProperty("Content-Type", "image/jpeg");
        connection.setRequestProperty("Connection", "Keep-Alive");
        connection.setRequestProperty("Content-Length", ""
                + file.length());
        connection.setDoOutput(true);
    
        String metadataPart = "--"
                + boundary
                + "\r\n"
                + "Content-Disposition: form-data; name=\"metadata\"\r\n\r\n"
                + "" + "\r\n";
    
        String fileHeader1 = "--"
                + boundary
                + "\r\n"
                + "Content-Disposition: form-data; name=\"uploadfile\"; filename=\""
                + fileName + "\"\r\n"
                + "Content-Type: application/octet-stream\r\n"
                + "Content-Transfer-Encoding: binary\r\n";
    
        long fileLength = file.length() + tail.length();
        String fileHeader2 = "Content-length: " + fileLength + "\r\n";
        String fileHeader = fileHeader1 + fileHeader2 + "\r\n";
        String stringData = metadataPart + fileHeader;
    
        long requestLength = stringData.length() + fileLength;
        connection.setRequestProperty("Content-length", ""
                + requestLength);
        connection.setFixedLengthStreamingMode((int) requestLength);
        connection.connect();
    
        DataOutputStream out = new DataOutputStream(
                connection.getOutputStream());
        out.writeBytes(stringData);
        out.flush();
    
        int progress = 0;
        int bytesRead = 0;
        byte buf[] = new byte[1024];
        BufferedInputStream bufInput = new BufferedInputStream(
                new FileInputStream(file));
        while ((bytesRead = bufInput.read(buf)) != -1) {
            // write output
            out.write(buf, 0, bytesRead);
            out.flush();
            progress += bytesRead;
            // update progress bar
            publishProgress(progress);
        }
    
        // Write closing boundary and close stream
        out.writeBytes(tail);
        out.flush();
        out.close();
    
        // Get server response
        BufferedReader reader = new BufferedReader(
                new InputStreamReader(connection.getInputStream()));
        String line = "";
        StringBuilder builder = new StringBuilder();
        while ((line = reader.readLine()) != null) {
            builder.append(line);
        }