Android使用OKHttp庫(kù)實(shí)現(xiàn)視頻文件的上傳到服務(wù)器功能
1 服務(wù)器接口簡(jiǎn)介
此處我使用的服務(wù)器接口是使用Flask編寫,具體實(shí)現(xiàn)代碼:
# -*- 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端代碼實(shí)現(xiàn)
代碼分三部分:
分別是xml布局文件,Activity類,和Okhttp網(wǎng)絡(luò)通信類。
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="請(qǐng)輸入上傳視頻名稱" 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="點(diǎn)擊上傳" 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, "請(qǐng)選擇視頻后,再點(diǎn)擊上傳!", 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 啟動(dòng)相冊(cè)
Intent intent = new Intent();
intent.setType("video/*");
intent.setAction(Intent.ACTION_GET_CONTENT);
intent.addCategory(Intent.CATEGORY_OPENABLE);
startActivityForResult(intent,VideoUploadActivity.VEDIO_KU);
}
/**
* 選擇回調(diào)
*/
@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();
//開(kāi)始上傳視頻,
// 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網(wǎng)絡(luò)通信類
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 舞動(dòng)的心 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());
//第一個(gè)參數(shù)要與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 舞動(dòng)的心 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 舞動(dòng)的心 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 舞動(dòng)的心 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;
//回調(diào)
Message msg = Message.obtain();
msg.what = UPDATE;
msg.obj = new ProgressModel(bytesWritten,contentLength,bytesWritten==contentLength);
myHandler.sendMessage(msg);
}
};
}
}
界面效果:

總結(jié)
以上所述是小編給大家介紹的Android使用OKHttp庫(kù)實(shí)現(xiàn)視頻文件的上傳到服務(wù)器,希望對(duì)大家有所幫助,如果大家有任何疑問(wèn)請(qǐng)給我留言,小編會(huì)及時(shí)回復(fù)大家的。在此也非常感謝大家對(duì)腳本之家網(wǎng)站的支持!
相關(guān)文章
Android四種數(shù)據(jù)存儲(chǔ)的應(yīng)用方式
這篇文章主要介紹了Android四種數(shù)據(jù)存儲(chǔ)的應(yīng)用方式的相關(guān)資料,希望通過(guò)本文能幫助到大家,讓大家理解掌握Android存儲(chǔ)數(shù)據(jù)的方法,需要的朋友可以參考下2017-10-10
Android實(shí)現(xiàn)為GridView添加邊框效果
這篇文章主要為大家詳細(xì)介紹了Android實(shí)現(xiàn)為GridView添加邊框效果,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-12-12
Android LinearLayout實(shí)現(xiàn)自動(dòng)換行
這篇文章主要為大家詳細(xì)介紹了Android LinearLayout實(shí)現(xiàn)自動(dòng)換行,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-08-08
Android 獲取應(yīng)用簽名的實(shí)現(xiàn)
本文主要講下在android中如何獲取應(yīng)用簽名,也方便平時(shí)用來(lái)區(qū)分一個(gè)應(yīng)用是不是原包應(yīng)用,具有一定的參考價(jià)值,感興趣的可以了解一下2016-02-02
Android實(shí)現(xiàn)信號(hào)強(qiáng)度監(jiān)聽(tīng)的方法
這篇文章主要介紹了Android實(shí)現(xiàn)信號(hào)強(qiáng)度監(jiān)聽(tīng)的方法,是Android手機(jī)中很常見(jiàn)的一個(gè)實(shí)用功能,需要的朋友可以參考下2014-08-08
android studio 打包自動(dòng)生成版本號(hào)與日期,apk輸入路徑詳解
這篇文章主要介紹了android studio 打包自動(dòng)生成版本號(hào)與日期,apk輸入路徑詳解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-03-03
Android自定義控件實(shí)現(xiàn)時(shí)間軸
這篇文章主要為大家詳細(xì)介紹了Android自定義控件實(shí)現(xiàn)時(shí)間軸,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-04-04

