Android中实现OkHttp上传文件到服务器并带进度

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android中实现OkHttp上传文件到服务器并带进度相关的知识,希望对你有一定的参考价值。

在上一讲中 OkHttp下载文件并带进度条 中,我们知道怎样去下载文件了。那上传文件呢

一、编写服务器端

在上一讲服务器下新建UploadFileServlet,代码如下:然后重启服务器!

  1. @WebServlet("/UploadFileServlet")
  2. @MultipartConfig
  3. public class UploadFileServlet extends HttpServlet {
  4. private static final long serialVersionUID = 1L;
  5. public UploadFileServlet() {
  6. super();
  7. // TODO Auto-generated constructor stub
  8. }
  9. /**
  10. * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse
  11. * response)
  12. */
  13. protected void doGet(HttpServletRequest request, HttpServletResponse response)
  14. throws ServletException, IOException {
  15. this.doPost(request, response);
  16. }
  17. /**
  18. * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse
  19. * response)
  20. */
  21. protected void doPost(HttpServletRequest request, HttpServletResponse response)
  22. throws ServletException, IOException {
  23. System.out.println("doPost==");
  24. request.setCharacterEncoding("utf-8");
  25. //获取file命名的part,注意要与android端一样
  26. Part part = request.getPart("file");
  27. // 获取请求头,请求头的格式:form-data; name="file"; filename="snmp4j--api.zip"
  28. String header = part.getHeader("content-disposition");
  29. System.out.println(header);
  30. String fileName = getFileName(header);
  31. // 存储路径
  32. String savePath = "D:/huang/upload";
  33. // 把文件写到指定路径
  34. part.write(savePath + File.separator + fileName);
  35. response.setCharacterEncoding("UTF-8");
  36. PrintWriter writer = response.getWriter();
  37. writer.print("上传成功");
  38. }
  39. public String getFileName(String header) {
  40. /**
  41. * header 为 form-data; name="file"; filename="dial.png"
  42. * String[] tempArr1 =
  43. * header.split(";");代码执行完之后,在不同的浏览器下,tempArr1数组里面的内容稍有区别
  44. * 火狐或者google浏览器下:tempArr1={form-data,name="file",filename=
  45. * "snmp4j--api.zip"}
  46. * IE浏览器下:tempArr1={form-data,name="file",filename="E:\\snmp4j--api.zip"}
  47. */
  48. String[] tempArr1 = header.split(";");
  49. /**
  50. * 火狐或者google浏览器下:tempArr2={filename,"snmp4j--api.zip"}
  51. * IE浏览器下:tempArr2={filename,"E:\\snmp4j--api.zip"}
  52. */
  53. String[] tempArr2 = tempArr1[2].split("=");
  54. // 获取文件名,兼容各种浏览器的写法
  55. String fileName = tempArr2[1].substring(tempArr2[1].lastIndexOf("\\\\") + 1).replaceAll("\\"", "");
  56. return fileName;
  57. }
  58. }
复制代码

二、Android端

1.布局,上一讲activity_main代码中添加 :

 

  1. <Button
  2. android:id="@+id/ok_post_file"
  3. android:layout_width="match_parent"
  4. android:layout_height="wrap_content"
  5. android:text="上传文件" />
  6. <TextView
  7. android:id="@+id/post_text"
  8. android:layout_width="match_parent"
  9. android:layout_height="wrap_content"
  10. android:gravity="center"
  11. android:text="0" />
  12. <ProgressBar
  13. android:id="@+id/post_progress"
  14. style="?android:attr/progressBarStyleHorizontal"
  15. android:layout_width="match_parent"
  16. android:layout_height="wrap_content"
  17. android:max="100" />
复制代码

2.OkHttpUtil新增上传文件方法:

  1. public static void postFile(String url, final ProgressListener listener, Callback callback, File...files){
  2. MultipartBody.Builder builder = new MultipartBody.Builder();
  3. builder.setType(MultipartBody.FORM);
  4. Log.i("huang","files[0].getName()=="+files[0].getName());
  5. //第一个参数要与Servlet中的一致
  6. builder.addFormDataPart("file",files[0].getName(), RequestBody.create(MediaType.parse("application/octet-stream"),files[0]));
  7. MultipartBody multipartBody = builder.build();
  8. Request request = new Request.Builder().url(url).post(new ProgressRequestBody(multipartBody,listener)).build();
  9. okHttpClient.newCall(request).enqueue(callback);
  10. }
复制代码

3.ProgressRequestBody是自定义RequestBody类,用来监听进度:

  1. public class ProgressRequestBody extends RequestBody {
  2. public static final int UPDATE = 0x01;
  3. private RequestBody requestBody;
  4. private ProgressListener mListener;
  5. private BufferedSink bufferedSink;
  6. private MyHandler myHandler;
  7. public ProgressRequestBody(RequestBody body, ProgressListener listener) {
  8. requestBody = body;
  9. mListener = listener;
  10. if (myHandler==null){
  11. myHandler = new MyHandler();
  12. }
  13. }
  14. class MyHandler extends Handler {
  15. //放在主线程中显示
  16. public MyHandler() {
  17. super(Looper.getMainLooper());
  18. }
  19. @Override
  20. public void handleMessage(Message msg) {
  21. switch (msg.what){
  22. case UPDATE:
  23. ProgressModel progressModel = (ProgressModel) msg.obj;
  24. if (mListener!=null)mListener.onProgress(progressModel.getCurrentBytes(),progressModel.getContentLength(),progressModel.isDone());
  25. break;
  26. }
  27. }
  28. }
  29. @Override
  30. public MediaType contentType() {
  31. return requestBody.contentType();
  32. }
  33. @Override
  34. public long contentLength() throws IOException {
  35. return requestBody.contentLength();
  36. }
  37. @Override
  38. public void writeTo(BufferedSink sink) throws IOException {
  39. if (bufferedSink==null){
  40. bufferedSink = Okio.buffer(sink(sink));
  41. }
  42. //写入
  43. requestBody.writeTo(bufferedSink);
  44. //刷新
  45. bufferedSink.flush();
  46. }
  47. private Sink sink(BufferedSink sink) {
  48. return new ForwardingSink(sink) {
  49. long bytesWritten = 0L;
  50. long contentLength = 0L;
  51. @Override
  52. public void write(Buffer source, long byteCount) throws IOException {
  53. super.write(source, byteCount);
  54. if (contentLength==0){
  55. contentLength = contentLength();
  56. }
  57. bytesWritten += byteCount;
  58. //回调
  59. Message msg = Message.obtain();
  60. msg.what = UPDATE;
  61. msg.obj = new ProgressModel(bytesWritten,contentLength,bytesWritten==contentLength);
  62. myHandler.sendMessage(msg);
  63. }
  64. };
  65. }
  66. }
复制代码

4.在MainActivity添加上传按钮点击事件,代码如下:

  1. File file = new File(basePath + "/1.mp4");
  2. String postUrl = "http://192.168.0.104:8080/OkHttpServer/UploadFileServlet";
  3. OkHttpUtil.postFile(postUrl, new ProgressListener() {
  4. @Override
  5. public void onProgress(long currentBytes, long contentLength, boolean done) {
  6. Log.i(TAG, "currentBytes==" + currentBytes + "==contentLength==" + contentLength + "==done==" + done);
  7. int progress = (int) (currentBytes * 100 / contentLength);
  8. post_progress.setProgress(progress);
  9. post_text.setText(progress + "%");
  10. }
  11. }, new Callback() {
  12. @Override
  13. public void onFailure(Call call, IOException e) {
  14. }
  15. @Override
  16. public void onResponse(Call call, Response response) throws IOException {
  17. if (response != null) {
  18. String result = response.body().string();
  19. Log.i(TAG, "result===" + result);
  20. }
  21. }
  22. }, file);
复制代码

相关效果图: 

技术分享图片

上传完成后,在电脑D:\\huang\\upload下可以看到:

技术分享图片

以上是关于Android中实现OkHttp上传文件到服务器并带进度的主要内容,如果未能解决你的问题,请参考以下文章

Android使用OKHttp库实现视频文件的上传到服务器

JavaWeb中实现文件上传的方式有哪些?

问题:JavaWeb中实现文件上传的方式有哪些?

在fragment中实现Android上传图片至本地JavaWeb服务器

okhttp3实现post方式上传文件加参数

Android--okhttp与php交互,文件上传下载