在Android中上载带有进度条且没有OutOfMemory错误的大文件

在Android中上载带有进度条且没有OutOfMemory错误的大文件,android,file-upload,out-of-memory,multipartform-data,Android,File Upload,Out Of Memory,Multipartform Data,我在上传大视频文件(高达150MB)时遇到一些问题 1.当我使用此代码时。我可以用进度条上传小文件,但由于我的文件很大,所以android会给我OutOfMemory错误 2.如果我使用此代码。我可以上传大文件(这确实是一个很好的解决方案),但不知道如何显示进度(如完成20%或完成80%等)。所以请指导我。最后我得到了问题的解决方案,我想与大家分享 1.第一个解决方案此解决方案适用于小文件,如高达15MB的图像上载。但如果文件非常大,我无法摆脱OutOfMemory错误 2.第二个解决方案()确

我在上传大视频文件(高达150MB)时遇到一些问题

1.当我使用此代码时。我可以用进度条上传小文件,但由于我的文件很大,所以android会给我OutOfMemory错误


2.如果我使用此代码。我可以上传大文件(这确实是一个很好的解决方案),但不知道如何显示进度(如完成20%或完成80%等)。所以请指导我。

最后我得到了问题的解决方案,我想与大家分享

1.第一个解决方案此解决方案适用于小文件,如高达15MB的图像上载。但如果文件非常大,我无法摆脱OutOfMemory错误

2.第二个解决方案()确实是一个很好的解决方案,为了显示进度条,我使用了一个自定义的MultipartEntity类。代码如下:

    import java.io.FilterOutputStream;
    import java.io.IOException;
    import java.io.OutputStream;
    import java.nio.charset.Charset;

    import org.apache.http.entity.mime.HttpMultipartMode;
    import org.apache.http.entity.mime.MultipartEntity;

    public class CustomMultiPartEntity extends MultipartEntity

{

    private final ProgressListener listener;

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

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

    public CustomMultiPartEntity(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);
        }
    }
}
我的活动代码是

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
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.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.util.EntityUtils;

import com.example.fileupload.CustomMultiPartEntity.ProgressListener;

import android.app.Activity;
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ProgressBar;
import android.widget.TextView;

public class MainActivity extends Activity implements OnClickListener {
    private ProgressBar pb;
    private final String filename = "/mnt/sdcard/vid.mp4";
    // private final String filename = "/mnt/sdcard/a.3gp";
    private String urlString = "http://10.0.2.2:8080/FileUploadServlet1/UploadServlet";
    private TextView tv;
    long totalSize = 0;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        tv = (TextView) findViewById(R.id.textView1);
        findViewById(R.id.button1).setOnClickListener(this);
        tv.setText("init");
        pb = (ProgressBar) findViewById(R.id.progressBar1);

    }

    private class Uploadtask extends AsyncTask<Void, Integer, String> {
        @Override
        protected void onPreExecute() {
            pb.setProgress(0);
            tv.setText("shuru");
            super.onPreExecute();
        }

        @Override
        protected void onProgressUpdate(Integer... progress) {
            pb.setProgress(progress[0]);
        }

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

        private String upload() {
            String responseString = "no";

            File sourceFile = new File(filename);
            if (!sourceFile.isFile()) {
                return "not a file";
            }
            HttpClient httpclient = new DefaultHttpClient();
            HttpPost httppost = new HttpPost(urlString);


            try {
                CustomMultiPartEntity entity=new CustomMultiPartEntity(new ProgressListener() {

                    @Override
                    public void transferred(long num) {
                        publishProgress((int) ((num / (float) totalSize) * 100));                       
                    }
                });

                entity.addPart("type", new StringBody("video"));
                entity.addPart("uploadedfile", new FileBody(sourceFile));
                totalSize = entity.getContentLength();
                httppost.setEntity(entity);
                HttpResponse response = httpclient.execute(httppost);
                HttpEntity r_entity = response.getEntity();
                responseString = EntityUtils.toString(r_entity);

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

            return responseString;

        }


        @Override
        protected void onPostExecute(String result) {
            tv.setText(result);
            super.onPostExecute(result);
        }

    }

    @Override
    public void onClick(View v) {
        // TODO Auto-generated method stub
        new Uploadtask().execute();
    }

}
import java.io.DataInputStream;
导入java.io.DataOutputStream;
导入java.io.File;
导入java.io.FileInputStream;
导入java.io.IOException;
导入java.net.HttpURLConnection;
导入java.net.MalformedURLException;
导入java.net.URL;
导入org.apache.http.HttpEntity;
导入org.apache.http.HttpResponse;
导入org.apache.http.client.ClientProtocolException;
导入org.apache.http.client.HttpClient;
导入org.apache.http.client.methods.HttpPost;
导入org.apache.http.entity.mime.HttpMultipartMode;
导入org.apache.http.entity.mime.MultipartEntity;
导入org.apache.http.entity.mime.content.FileBody;
导入org.apache.http.entity.mime.content.StringBody;
导入org.apache.http.impl.client.DefaultHttpClient;
导入org.apache.http.util.EntityUtils;
导入com.example.fileupload.CustomMultiPartEntity.ProgressListener;
导入android.app.Activity;
导入android.os.AsyncTask;
导入android.os.Bundle;
导入android.view.view;
导入android.view.view.OnClickListener;
导入android.widget.ProgressBar;
导入android.widget.TextView;
公共类MainActivity扩展活动实现OnClickListener{
私人ProgressBar pb;
私有最终字符串filename=“/mnt/sdcard/vid.mp4”;
//私有最终字符串filename=“/mnt/sdcard/a.3gp”;
专用字符串urlString=”http://10.0.2.2:8080/FileUploadServlet1/UploadServlet";
私家图文电视;
长totalSize=0;
@凌驾
创建时受保护的void(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tv=(TextView)findViewById(R.id.textView1);
findviewbyd(R.id.button1).setOnClickListener(this);
tv.setText(“init”);
pb=(ProgressBar)findViewById(R.id.progressBar1);
}
私有类Uploadtask扩展了AsyncTask{
@凌驾
受保护的void onPreExecute(){
pb.setProgress(0);
tv.setText(“shuru”);
super.onPreExecute();
}
@凌驾
受保护的void onProgressUpdate(整数…进度){
pb.setProgress(progress[0]);
}
@凌驾
受保护字符串doInBackground(无效…参数){
返回上传();
}
私有字符串上载(){
字符串responseString=“否”;
文件源文件=新文件(文件名);
如果(!sourceFile.isFile()){
返回“非文件”;
}
HttpClient HttpClient=新的DefaultHttpClient();
HttpPost HttpPost=新的HttpPost(urlString);
试一试{
CustomMultiPartEntity=新CustomMultiPartEntity(新ProgressListener()){
@凌驾
已转移的公共无效(长数值){
出版进度((int)((num/(float)totalSize)*100);
}
});
entity.addPart(“类型”,新的StringBody(“视频”);
addPart(“uploadedfile”,新的文件体(sourceFile));
totalSize=entity.getContentLength();
httppost.setEntity(实体);
HttpResponse response=httpclient.execute(httppost);
HttpEntity r_entity=response.getEntity();
responseString=EntityUtils.toString(r_实体);
}捕获(客户端协议例外e){
responseString=e.toString();
}捕获(IOE异常){
responseString=e.toString();
}
回报率;
}
@凌驾
受保护的void onPostExecute(字符串结果){
tv.setText(结果);
super.onPostExecute(结果);
}
}
@凌驾
公共void onClick(视图v){
//TODO自动生成的方法存根
新建Uploadtask().execute();
}
}

您是否尝试过在第一个链接的代码中使用200多个区块?是的,我尝试了多达500个区块,但没有成功,因此尝试使用Link2@VibhorBhardwaj:对于150MB的文件,即使是500个块也需要大约300KB的缓冲区。我可能会使用至少2000个块,这会将缓冲区大小降低到75KB左右。@Squonk我尝试过大小为200000的块,但仍然出现内存不足错误。您确定您所做的操作指示了实际的文件上传进度或文件系统的文件读取进度,这非常快吗?您好@VibhorBhardwaj谢谢。您的代码在mp3文件上传中可以完美工作。但在服务器端上传后无法播放音频。事件也无法在浏览器中播放。不推荐使用MultipartEntity。我们需要此代码的更新版本。