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

Posted 舞动的心

tags:

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

目录

1 服务器接口简介

2 Android端代码实现

2.1 xml布局文件

2.2 Activity类

2.3 Okhttp网络通信类

 

 


1 服务器接口简介

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

 

# -*- 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)

 

参考文章:https://www.cnblogs.com/mosson/p/6163233.html

 附加使用PostMan测试上传文件的操作方法:http://blog.csdn.net/u013420865/article/details/69665180

 


2 Android端代码实现

代码分三部分:

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

2.1 xml布局文件

activity_video_upload.xml:
<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="?android:attr/progressBarStyleHorizontal"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:max="100" />

</LinearLayout>

 

2.2 Activity类

VideoUploadActivity类:

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类:
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接口:
package com.liu.dance.util;

/**
 * Created by 舞动的心 on 2018/3/8.
 */

public interface ProgressListener {
    void onProgress(long currentBytes, long contentLength, boolean done);
}

 

 

ProgressModel类:
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?1:0));
    }

    protected ProgressModel(Parcel parcel) {
        currentBytes = parcel.readLong();
        contentLength = parcel.readLong();
        done = parcel.readByte()!=0;
    }
}

 

 

 ProgressRequestBody类:

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);
            }
        };
    }


}

 

 

界面效果:

 

参考文章:http://blog.csdn.net/gary__123456/article/details/74157403

 

以上是关于Android使用OKHttp库实现视频文件的上传到服务器的主要内容,如果未能解决你的问题,请参考以下文章

Android必知必会-使用okhttp的PUT方式上传文件

Android网络请求库RetrofitUtils

okhttputils Android 一个改善的okHttp封装库使用

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

Android通过OKHTTP上传文件不使用MultiPart

Android使用OkHttp实现带进度的上传下载