Androidネットワークプログラミング(6)ボレー戦闘、Tencent Cloudへのファイルのアップロード

以前のブログ投稿「Android Network Programming(5)Volley Framework Usage」で、GETとPOSTのネットワークリクエストに対する基本的な使い方簡単に紹介しました。今日は、Volleyを使用してファイルをアップロードする方法をさらに探ります。

1フォーム構造

ファイルのアップロードは実際にはフォームを送信することですが、フォームの送信にはファイルのバイナリ値である特定のフィールドがあります。Tencent CloudアップロードAPIにアクセスして、Volleyアップロードの使用方法を説明しましょう。始める前に、フォームから送信されたデータ形式を見てみましょう。以下は、Tencent Cloudによってアップロードされたパケットキャプチャデータの例です。

POST /files/v2/<向腾讯云申请的appid>/<appid里头对应的bucket_name>/[文件夹]/<文件名> HTTP/1.1
Accept: */*
Authorization: XXX这里是腾讯云appid等一系列值生成的签名XXX
Content-Type: multipart/form-data;boundary=------------------------------分界字符
User-Agent: Dalvik/2.1.0 (Linux; U; Android 5.0.2; MI2 MIUI/6.10.20)
Host: gz.file.myqcloud.com
Connection: Keep-Alive
Accept-Encoding: gzip
Content-Length: 778
 
--------------------------------分界字符
Content-Disposition: form-data;name="insertOnly"
 
0
--------------------------------分界字符
Content-Disposition: form-data; name="op"
 
upload
--------------------------------分界字符
Content-Disposition: form-data; name="sha"
 
XXX这里是文件的SHA-1值XXX
--------------------------------分界字符
Content-Disposition: form-data;name="biz_attr"
 
 
--------------------------------分界字符
Content-Disposition: form-data;name="filecontent"
Content-Type: text/plain
 
XXX这里是文件转二进制的byte[]值XXX
--------------------------------分界字符—

上記のデータパケットを分析してみましょう。2行に分かれています。1行目から9行目がヘッダー、10行目から最後までが本文(コミット済みデータ)です。Volleyでは、指定するいくつかの点を除いて、ほとんどのヘッダーが自動的に生成されます。たとえば、最初の行のPOSTとHTTP / 1.1の間の行は送信されたURLです。4行目のContent-Typeは送信されたパラメーターのタイプを指定します。境界の後ろにはカスタム区切り文字があり、これは以下と一致している必要があります。TencentCloudは、署名検証、つまり3行目も追加する必要があります。次に、身体部分の分析を続けます。身体部分のすべてのデータは手縫いによって生成されます。これらがすべて規則的であることに満足しています。

 

2 UploadRequest

私たちは「バレーボールフレームワークの使用してプログラミングAndroidのネットワーク(E)」で紹介しStringRequestJSONRequestImageRequestそれらはから継承されている使用、リクエスト我々はUploadRequestを書くためにそれらを模倣することができますので、クラス。

次のように、新しいUploadRequestクラスを作成します。

public class UploadRequest extends Request<JSONObject> {

    private final static int TIME_OUT = 5 *60 * 1000;                                                  // 5分钟

    private Map<String,Object> mParams;
    private byte[] mFileByte;
    private String mAuthorization;
    private finalResponse.Listener<JSONObject> mListener;

    public UploadRequest(String url, Map<String, Object> params, String authorization, byte[]fileByte, Response.Listener<JSONObject> listener, Response.ErrorListenererrorListener) {
        super(Request.Method.POST,url, errorListener);
        mParams =params;
        mAuthorization= authorization;
        mFileByte =fileByte;
        this.mListener= listener;

        setShouldCache(false);
        setRetryPolicy(newDefaultRetryPolicy(TIME_OUT,DefaultRetryPolicy.DEFAULT_MAX_RETRIES,DefaultRetryPolicy.DEFAULT_BACKOFF_MULT));
    }

    @Override
    protected Response<JSONObject>parseNetworkResponse(NetworkResponse response) {
        try {
            String je = newString(response.data,HttpHeaderParser.parseCharset(response.headers,"utf-8"));
            return Response.success(newJSONObject(je), HttpHeaderParser.parseCacheHeaders(response));
        } catch (UnsupportedEncodingException var3) {
            return Response.error(newParseError(var3));
        } catch (JSONException var4) {
            return Response.error(newParseError(var4));
        }
    }

    @Override
    protected void deliverResponse(JSONObject jsonObject) {
        if(mListener != null){
            mListener.onResponse(jsonObject);
        }
    }
}

最初のステップは、UploadRequestクラスにリクエストを継承させることです。TencentCloudはアップロード後にJSONタイプのデータを返すため、JSONObjectタイプとして指定されます。

2番目のステップは、コンストラクターを定義することです。コンストラクターは、要求されたURL、パラメーター、Tencent Cloudシグネチャ、アップロードされるファイルのバイナリ値、アップロード成功コールバック、アップロード失敗コールバックを受け取ります。関数エンティティでは、Volleyのキャッシュがfalseに設定され、リクエストのタイムアウト時間が5分に設定されています。もちろん、これらの2つの値をコンストラクターから渡して指定することもできます。

3番目のステップは、必要な2つのメソッドparseNetworkResponseとdeliverResponseを書き直すことです。parseNetworkResponseは、JsonRequestクラスのparseNetworkResponseメソッドをコピーできます。deliveryResponseは、正常なアップロードを指定するコールバックです。

次に、getBodyContentType、getHeaders、およびgetBodyの3つの非常に重要なメソッドを引き続き書き換えます。

private final static String BOUNDARY = "------------------------------lyz_zyx";   // 数据分界线

@Override
public String getBodyContentType() {
    return "multipart/form-data;boundary=" + BOUNDARY;
}

@Override
public Map<String, String> getHeaders() throwsAuthFailureError {
    Map<String, String> headers = newHashMap<>();
    headers.putAll(super.getHeaders());
   if (mAuthorization!= null && mAuthorization.isEmpty()){
        headers.put("Authorization",mAuthorization);
    }
    headers.put("Accept","*/*");             //这句一定要加上,否则上传的腾讯云上的文件会是0B,若加sha1校验,则上传失败
    return headers;
}

@Override
public byte[] getBody() throwsAuthFailureError {
    if (mParams== null) {
        return null;
    }
    ByteArrayOutputStream bos = newByteArrayOutputStream() ;
    String enterNewline = "\r\n";
    String fix = "--";
    StringBuffer sb= newStringBuffer() ;
    try {
        Iterator iter = mParams.entrySet().iterator();
        while (iter.hasNext()){
            Map.Entry entry = (Map.Entry)iter.next();
            Object key = entry.getKey();
            Object val =entry.getValue();

            sb.append(fix + BOUNDARY+ enterNewline);
            sb.append("Content-Disposition:form-data; name=\"" +key + "\"" +enterNewline);
            sb.append(enterNewline);
            sb.append(val +enterNewline);
        }
        sb.append(fix + BOUNDARY+ enterNewline);
        sb.append("Content-Disposition:form-data; name=\"filecontent\""+ enterNewline);
        sb.append("Content-Type:text/plain" + enterNewline);
        sb.append(enterNewline);

        bos.write(sb.toString().getBytes("utf-8"));
        bos.write(mFileByte);

        StringBuffer sbEnd= newStringBuffer() ;
        sbEnd.append(enterNewline) ;
        sbEnd.append(fix + BOUNDARY+ fix + enterNewline);

        bos.write(sbEnd.toString().getBytes("utf-8"));
    } catch (IOExceptione) {
        e.printStackTrace();
    }

    return bos.toByteArray();
}

getBodyContentTypeメソッドによって返される文字列は、前述のヘッダーの4行目です。

getHeadersメソッドは、AcceptとAuthorizationの2つの値を追加します。これは、ヘッダー行の2行目と3行目で前述したものです。

getBodyメソッドは、前述のボディパーツであり、手動でスプライスする必要があります。その前に、コンストラクターによって渡されたmParams値のループが作成されます。ループが完了すると、コンストラクターによって渡されたmFileByteパーツが接続されます。

UploadRequestクラス全体が完成しました。最初の目的はTencent Cloudのアップロード機能用に設計することでしたが、実際、UploadRequestクラスは、署名が渡されない限り、アップロードされたファイルを送信する他の通常のフォームにも完全に共通です。

最後に、呼び出す方法:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    Button btn1 =(Button)findViewById(R.id.btn1);
    btn1.setOnClickListener(newView.OnClickListener() {
        @Override
        public void onClick(Viewv) {
            uploadFile("/sdcard/upload_log.zip");
        }
    });
}

/**
 * 执行上传文件
 * @param filePath
 */
private void uploadFile(String filePath) {
    File file = newFile(filePath);
    if (!file.exists()){
        return;
    }
    UploadFileData uploadFileData = newUploadFileData();
   uploadFileData.setFileName(file.getName());
    Common.getFileByteAndSha1(file,uploadFileData);

    String url = String.format(REQUEST_UPLOAD_URL,uploadFileData.getFileName());

    Map<String, Object> params = newHashMap<>();
    params.put("op","upload");
    params.put("sha",uploadFileData.getFileSha1().toLowerCase()); // 注意,sha1值必须小写,这点腾讯云API没提到
    params.put("biz_attr","");
    params.put("insertOnly",0);

    String authorization = getSign();

    RequestQueue requestQueue = Volley.newRequestQueue(getApplicationContext());
    UploadRequest uploadRequest = new UploadRequest(url, params, authorization,uploadFileData.getFileByte(),
            new Response.Listener<JSONObject>(){
                @Override
                publicvoid onResponse(JSONObject jsonObject) {
                    //TODO 上传成功
                }
            },
            new Response.ErrorListener(){
                @Override
                publicvoid onErrorResponse(VolleyError volleyError) {
                    //TODO 上传失败
                }
            });
    requestQueue.add(uploadRequest);
}

対応するコード、呼び出しプロセスは、最初にモバイルファイルディレクトリを指定し、次にファイルに対応させ、そのsha1値とバイナリ値を計算し、Tencent Cloudから提供された情報を通じてアップロードされた署名を計算します。最後のステップは、準備したUploadRequestを作成することです。次に、クラスのオブジェクトがRequestQueueに渡されます。別のポイントとして、対応する権限を宣言することを忘れないでください。

<uses-permission android:name="android.permission.INTERNET" />
<uses-permissionandroid:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permissionandroid:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>

3まとめ

このブログ投稿では、主にフォームの構造と、Volleyを使用してフォームを生成し、ネットワークをリクエストする方法について説明します。Tencent Cloudの使用に関して、この例では、フォームの送信を解析するために、最も独創的な使用方法が示されています。プロジェクトがパッケージのサイズを気にしない場合は、Tencent Cloud APIによって提供されるAndroid SDKパッケージを使用できます。プロジェクトでそのjarを参照するだけで、対応するAPI導入メソッドは非常に簡単になります。10行のコードで全体を完了することができますアップロード機能の詳細はここでは紹介しません。詳細については、TencentのAPI https://www.qcloud.com/document/api/436/6066を参照してください。また、このプロジェクトの完全なソースコードは、こちらからダウンロードできます

 

元の記事を106件公開 37 件を賞賛 80,000回

おすすめ

転載: blog.csdn.net/lyz_zyx/article/details/73089230