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

6
回复
619
查看
[复制链接]

758

主题

1466

帖子

1857

安币

手工艺人

发表于 2018-3-20 10:52:08 | 显示全部楼层 |阅读模式

            1 服务器接口简介

        此处我使用的服务器接口是使用flask编写,具体实现代码:

[Java] 查看源文件 复制代码
# -*- coding: utf-8 -*-
from flask import flask, render_template, jsonify, request
import time
import os
import base64
app = flask(__name__)
upload_folder = 'e:\myupload\picture'
app.config['upload_folder'] = upload_folder
basedir = os.path.abspath(os.path.dirname(__file__))
allowed_extensions = set(['txt', 'png', 'jpg', 'xls', 'jpg', 'png', 'xlsx', 'gif', 'gif','mp4'])
# 用于判断文件后缀
def allowed_file(filename):
 return '.' in filename and filename.rsplit('.', 1)[1] in allowed_extensions
# 上传文件
@app.route('/api/upload', methods=['post'], strict_slashes=false)
def api_upload():
 file_dir = os.path.join(basedir, app.config['upload_folder'])
 if not os.path.exists(file_dir):
  os.makedirs(file_dir)
 f = request.files['myfile'] # 从表单的file字段获取文件,myfile为该表单的name值
 if f and allowed_file(f.filename): # 判断是否是允许上传的文件类型
  fname = f.filename
  print fname
  ext = fname.rsplit('.', 1)[1] # 获取文件后缀
  unix_time = int(time.time())
  new_filename = str(unix_time) + '.' + ext # 修改了上传的文件名
  f.save(os.path.join(file_dir, new_filename)) # 保存文件到upload目录
  print new_filename
  token = base64.b64encode(new_filename)
  print token
  return jsonify({"errno": 0, "errmsg": "上传成功", "token": token})
 else:
  return jsonify({"errno": 1001, "errmsg": "上传失败"})
if __name__ == '__main__':
 app.run(debug=true)


2 android端代码实现

        代码分三部分:

        分别是xml布局文件,activity类,和okhttp网络通信类。

        2.1 xml布局文件

        activity_video_upload.xml:

[Java] 查看源文件 复制代码
<linearlayout xmlns:android="http://schemas.android.com/apk/res/android"
 android:layout_width="fill_parent"
 android:layout_height="fill_parent"
 android:orientation="vertical" >
 <linearlayout
  android:layout_width="wrap_content"
  android:layout_marginleft="10dp"
  android:layout_marginright="10dp"
  android:layout_height="60dp"
  android:layout_margintop="80dp"
  android:orientation="horizontal">
  <textview
   android:layout_width="match_parent"
   android:layout_height="50dp"
   android:layout_gravity="center_vertical"
   android:gravity="center"
   android:text="视频名称:"
   android:textcolor="@color/black2"
   android:textsize="18dp"/>
  <edittext
   android:id="@+id/upload_video_name"
   android:layout_width="280dp"
   android:layout_height="50dp"
   android:layout_gravity="center_vertical"
   android:hint="请输入上传视频名称"
   android:layout_marginleft="5dp"
   android:textsize="18dp"
   />
 </linearlayout>
 <button
  android:id="@+id/video_select"
  android:layout_width="match_parent"
  android:layout_height="44dp"
  android:layout_marginleft="100dp"
  android:layout_marginright="100dp"
  android:layout_margintop="80dp"
  android:background="@drawable/exit_btn_blue"
  android:text="选择视频"
  android:textstyle="bold"
  android:textcolor="@android:color/white"
  android:textsize="20sp"/>
 <button
  android:id="@+id/video_upload"
  android:layout_width="match_parent"
  android:layout_height="44dp"
  android:layout_marginleft="100dp"
  android:layout_marginright="100dp"
  android:layout_margintop="40dp"
  android:background="@drawable/exit_btn_blue"
  android:text="点击上传"
  android:textstyle="bold"
  android:textcolor="@android:color/white"
  android:textsize="20sp"/>
 <textview
  android:id="@+id/post_text"
  android:layout_margintop="40dp"
  android:layout_width="match_parent"
  android:layout_height="wrap_content"
  android:gravity="center"
  android:text="0" />
 <progressbar
  android:id="@+id/post_progress"
  android:layout_marginleft="20dp"
  android:layout_marginright="20dp"
  style="

        2.2 activity类

        videouploadactivity类:

[Java] 查看源文件 复制代码
package com.liu.dance.video;
import android.app.activity;
import android.content.contentresolver;
import android.content.context;
import android.content.intent;
import android.database.cursor;
import android.net.uri;
import android.os.environment;
import android.provider.mediastore;
import android.support.v7.app.appcompatactivity;
import android.os.bundle;
import android.util.log;
import android.view.menuitem;
import android.view.view;
import android.widget.edittext;
import android.widget.progressbar;
import android.widget.textview;
import android.widget.toast;
import com.liu.dance.r;
import com.liu.dance.util.httputil;
import com.liu.dance.util.progresslistener;
import java.io.file;
import java.net.uri;
import java.io.file;
import java.io.fileoutputstream;
import java.io.ioexception;
import java.io.inputstream;
import okhttp3.call;
import okhttp3.callback;
import okhttp3.response;
public class videouploadactivity extends appcompatactivity {
 public static final string tag = videouploadactivity.class.getname();
 public final static int vedio_ku = 101;
 private string path = "";//文件路径
 private progressbar post_progress;
 private textview post_text;
 @override
 protected void oncreate(bundle savedinstancestate) {
  super.oncreate(savedinstancestate);
  setcontentview(r.layout.activity_video_upload);
  getsupportactionbar().settitle("视频上传");
  getsupportactionbar().setdisplayhomeasupenabled(true);
  final edittext video_name = (edittext)findviewbyid(r.id.upload_video_name);
  post_progress = (progressbar) findviewbyid(r.id.post_progress);
  post_text = (textview) findviewbyid(r.id.post_text);
  findviewbyid(r.id.video_select).setonclicklistener(new view.onclicklistener() {
   @override
   public void onclick(view view) {
    seletevedio();
    video_name.settext(path);
   }
  });
  findviewbyid(r.id.video_upload).setonclicklistener(new view.onclicklistener() {
   @override
   public void onclick(view view) {
//    toast.maketext(videouploadactivity.this, "路径:"+basepath, toast.length_long).show();
    if(path.equals(""))
     toast.maketext(videouploadactivity.this, "请选择视频后,再点击上传!", toast.length_long).show();
    else {
     file file = new file( path);
     string posturl = "http://120.79.82.151/api/upload";
     httputil.postfile(posturl, new progresslistener() {
      @override
      public void onprogress(long currentbytes, long contentlength, boolean done) {
       log.i(tag, "currentbytes==" + currentbytes + "==contentlength==" + contentlength + "==done==" + done);
       int progress = (int) (currentbytes * 100 / contentlength);
       post_progress.setprogress(progress);
       post_text.settext(progress + "%");
      }
     }, new callback() {
      @override
      public void onfailure(call call, ioexception e) {
      }
      @override
      public void onresponse(call call, response response) throws ioexception {
       if (response != null) {
        string result = response.body().string();
        log.i(tag, "result===" + result);
       }
      }
     }, file);
    }
   }
  });
 }
 @override
 public boolean onoptionsitemselected(menuitem item) {
  switch (item.getitemid()) {
   case android.r.id.home:
    finish();
    break;
   default:
    break;
  }
  return super.onoptionsitemselected(item);
 }
 public void seletevedio() {
  // todo 启动相册
  intent intent = new intent();
  intent.settype("video/*");
  intent.setaction(intent.action_get_content);
  intent.addcategory(intent.category_openable);
  startactivityforresult(intent,videouploadactivity.vedio_ku);
 }
 /**
  * 选择回调
  */
 @override
 public void onactivityresult(int requestcode, int resultcode, intent data) {
  switch (requestcode) {
   // todo 视频
   case videouploadactivity.vedio_ku:
    if (resultcode == activity.result_ok) {
     try {
      uri uri = data.getdata();
      uri = geturi(this, data);
      file file = null;
      if (uri.tostring().indexof("file") == 0) {
       file = new file(new uri(uri.tostring()));
       path = file.getpath();
      } else {
       path = getpath(uri);
       file = new file(path);
      }
      if (!file.exists()) {
       break;
      }
      if (file.length() > 100 * 1024 * 1024) {
//       "文件大于100m";
       break;
      }
      //视频播放
//      mvideoview.setvideouri(uri);
//      mvideoview.start();
      //开始上传视频,
//      submitvedio();
     } catch (exception e) {
      string a=e+"";
     } catch (outofmemoryerror e) {
      string a=e+"";
     }
    }
    break;
  }
 }
 public static uri geturi(context context, android.content.intent intent) {
  uri uri = intent.getdata();
  string type = intent.gettype();
  if (uri.getscheme().equals("file") && (type.contains("image/"))) {
   string path = uri.getencodedpath();
   if (path != null) {
    path = uri.decode(path);
    contentresolver cr = context.getcontentresolver();
    stringbuffer buff = new stringbuffer();
    buff.append("(").append(mediastore.images.imagecolumns.data).append("=")
      .append("'" + path + "'").append(")");
    cursor cur = cr.query(mediastore.images.media.external_content_uri,
      new string[] { mediastore.images.imagecolumns._id },
      buff.tostring(), null, null);
    int index = 0;
    for (cur.movetofirst(); !cur.isafterlast(); cur.movetonext()) {
     index = cur.getcolumnindex(mediastore.images.imagecolumns._id);
     // set _id value
     index = cur.getint(index);
    }
    if (index == 0) {
     // do nothing
    } else {
     uri uri_temp = uri
       .parse("content://media/external/images/media/"
         + index);
     if (uri_temp != null) {
      uri = uri_temp;
      log.i("urishi", uri.tostring());
     }
    }
   }
  }
  return uri;
 }
 private string getpath(uri uri) {
  string[] projection = {mediastore.video.media.data};
  cursor cursor = managedquery(uri, projection, null, null, null);
  int column_index = cursor
    .getcolumnindexorthrow(mediastore.video.media.data);
  cursor.movetofirst();
  return cursor.getstring(column_index);
 }
}

        2.3 okhttp网络通信类

        httputil类:

[Java] 查看源文件 复制代码
package com.liu.dance.util;
import android.util.log;
import java.io.file;
import java.util.concurrent.timeunit;
import okhttp3.mediatype;
import okhttp3.multipartbody;
import okhttp3.okhttpclient;
import okhttp3.request;
import okhttp3.requestbody;
/**
 * created by 舞动的心 on 2018/3/5.
 */
public class httputil {
 private static okhttpclient okhttpclient = new okhttpclient.builder().connecttimeout(10000, timeunit.milliseconds)
   .readtimeout(10000,timeunit.milliseconds)
   .writetimeout(10000, timeunit.milliseconds).build();
 public static final mediatype json = mediatype.parse("application/json; charset=utf-8");
 public static final mediatype media_type_markdown = mediatype.parse("text/x-markdown; charset=utf-8");public static void postfile(string url, final progresslistener listener, okhttp3.callback callback, file...files){
  multipartbody.builder builder = new multipartbody.builder();
  builder.settype(multipartbody.form);
  log.i("huang","files[0].getname()=="+files[0].getname());
  //第一个参数要与servlet中的一致
  builder.addformdatapart("myfile",files[0].getname(), requestbody.create(mediatype.parse("application/octet-stream"),files[0]));
  multipartbody multipartbody = builder.build();
  request request = new request.builder().url(url).post(new progressrequestbody(multipartbody,listener)).build();
  okhttpclient.newcall(request).enqueue(callback);
 }
}

        progresslistener接口:

[Java] 查看源文件 复制代码
package com.liu.dance.util;
/**
 * created by 舞动的心 on 2018/3/8.
 */
public interface progresslistener {
 void onprogress(long currentbytes, long contentlength, boolean done);
}

        progressmodel类:

[Java] 查看源文件 复制代码
package com.liu.dance.util;
import android.os.parcel;
import android.os.parcelable;
/**
 * created by 舞动的心 on 2018/3/8.
 */
public class progressmodel implements parcelable {
 private long currentbytes;
 private long contentlength;
 private boolean done = false;
 public progressmodel(long currentbytes, long contentlength, boolean done) {
  this.currentbytes = currentbytes;
  this.contentlength = contentlength;
  this.done = done;
 }
 public long getcurrentbytes() {
  return currentbytes;
 }
 public void setcurrentbytes(long currentbytes) {
  this.currentbytes = currentbytes;
 }
 public long getcontentlength() {
  return contentlength;
 }
 public void setcontentlength(long contentlength) {
  this.contentlength = contentlength;
 }
 public boolean isdone() {
  return done;
 }
 public void setdone(boolean done) {
  this.done = done;
 }
 private static final creator<progressmodel> creator = new creator<progressmodel>() {
  @override
  public progressmodel createfromparcel(parcel parcel) {
   return new progressmodel(parcel);
  }
  @override
  public progressmodel[] newarray(int i) {
   return new progressmodel[i];
  }
 };
 @override
 public int describecontents() {
  return 0;
 }
 @override
 public void writetoparcel(parcel parcel, int i) {
  parcel.writelong(currentbytes);
  parcel.writelong(contentlength);
  parcel.writebyte((byte) (done==true

        progressrequestbody类:

[Java] 查看源文件 复制代码
package com.liu.dance.util;
import android.os.handler;
import android.os.looper;
import android.os.message;
import java.io.ioexception;
import okhttp3.mediatype;
import okhttp3.requestbody;
import okio.buffer;
import okio.bufferedsink;
import okio.forwardingsink;
import okio.okio;
import okio.sink;
/**
 * created by 舞动的心 on 2018/3/8.
 */
public class progressrequestbody extends requestbody {
 public static final int update = 0x01;
 private requestbody requestbody;
 private progresslistener mlistener;
 private bufferedsink bufferedsink;
 private myhandler myhandler;
 public progressrequestbody(requestbody body, progresslistener listener) {
  requestbody = body;
  mlistener = listener;
  if (myhandler==null){
   myhandler = new myhandler();
  }
 }
 class myhandler extends handler {
  public myhandler() {
   super(looper.getmainlooper());
  }
  @override
  public void handlemessage(message msg) {
   switch (msg.what){
    case update:
     progressmodel progressmodel = (progressmodel) msg.obj;
     if (mlistener!=null)mlistener.onprogress(progressmodel.getcurrentbytes(),progressmodel.getcontentlength(),progressmodel.isdone());
     break;
   }
  }
 }
 @override
 public mediatype contenttype() {
  return requestbody.contenttype();
 }
 @override
 public long contentlength() throws ioexception {
  return requestbody.contentlength();
 }
 @override
 public void writeto(bufferedsink sink) throws ioexception {
  if (bufferedsink==null){
   bufferedsink = okio.buffer(sink(sink));
  }
  //写入
  requestbody.writeto(bufferedsink);
  //刷新
  bufferedsink.flush();
 }
 private sink sink(bufferedsink sink) {
  return new forwardingsink(sink) {
   long byteswritten = 0l;
   long contentlength = 0l;
   @override
   public void write(buffer source, long bytecount) throws ioexception {
    super.write(source, bytecount);
    if (contentlength==0){
     contentlength = contentlength();
    }
    byteswritten += bytecount;
    //回调
    message msg = message.obtain();
    msg.what = update;
    msg.obj = new progressmodel(byteswritten,contentlength,byteswritten==contentlength);
    myhandler.sendmessage(msg);
   }
  };
 }
}

        界面效果:

        

        总结






        

11

主题

9461

帖子

-22

安币

QQ游客

推广达人

发表于 2018-3-20 11:09:05 | 显示全部楼层
帮帮顶顶!!

451

主题

1188

帖子

1942

安币

手工艺人

发表于 2018-3-20 12:05:30 | 显示全部楼层
楼主威武,以后多发干货,多办活动~!

0

主题

9524

帖子

1140

安币

Android大神

Rank: 6Rank: 6

发表于 2018-3-20 16:41:48 | 显示全部楼层
帮帮顶顶!!

1

主题

9262

帖子

2901

安币

Android大神

Rank: 6Rank: 6

发表于 2018-3-20 21:10:36 | 显示全部楼层
感觉楼主很用心,辛苦啦~

0

主题

9211

帖子

2371

安币

Android大神

Rank: 6Rank: 6

发表于 2018-3-21 01:12:40 | 显示全部楼层
帮帮顶顶!!

14

主题

9478

帖子

4723

安币

码皇(巴士元老)

Rank: 8Rank: 8

发表于 2018-3-21 05:15:23 | 显示全部楼层
感谢大神~
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

领先的中文移动开发者社区
18620764416
7*24全天服务
意见反馈:1294855032@qq.com

扫一扫关注我们

Powered by Discuz! X3.2© 2001-2019 Comsenz Inc.( 粤ICP备15117877号 )