Programmation réseau Android (6) Volley combat, téléchargement de fichiers sur Tencent Cloud

Nous avons brièvement présenté l'utilisation de base de Volley pour GET et POST pour les requêtes réseau dans le billet de blog précédent "Programmation réseau Android (5) Utilisation de Volley Framework" . Aujourd'hui, nous explorons plus en détail comment utiliser Volley pour télécharger des fichiers.

1 Structure du formulaire

Le téléchargement de fichier consiste en fait à soumettre le formulaire, mais il y a un certain champ dans la soumission du formulaire qui est la valeur binaire du fichier. Prenons l'accès à l'API de téléchargement Tencent Cloud pour expliquer l'utilisation du téléchargement Volley. Avant de commencer, examinons le format de données soumis par le formulaire. Voici un exemple de données de capture de paquets téléchargées par 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
--------------------------------分界字符—

Analysons le paquet de données ci-dessus. Il est divisé en deux parties: les lignes 1 à 9 sont des en-têtes et les lignes 10 à la fin sont des corps (données validées). Dans Volley, la plupart des en-têtes sont généralement générés automatiquement, à l'exception de quelques points à spécifier. Par exemple, la ligne entre POST et HTTP / 1.1 sur la première ligne est l'URL soumise; le Content-Type à la ligne 4 spécifie le type du paramètre soumis, et Derrière la frontière se trouve le caractère de délimitation personnalisé, qui doit être cohérent avec ce qui suit; Tencent Cloud doit également ajouter une vérification de signature, c'est-à-dire la troisième ligne. Ensuite, continuez d'analyser la partie du corps. Toutes les données de la partie du corps sont générées par la couture manuelle. Il est satisfaisant qu'elles soient toutes régulières.

 

2 UploadRequest

Nous avons introduit l'utilisation de StringRequest , JsonRequest et ImageRequest dans "Use of Volley Framework for Android Network Programming (5)" . Ils héritent tous de la classe Request , afin que nous puissions les imiter et écrire une UploadRequest.

Créez une nouvelle classe UploadRequest, comme suit:

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

La première étape consiste à faire en sorte que la classe UploadRequest hérite de Request. Comme Tencent Cloud renvoie des données de type JSON après le téléchargement, elles sont spécifiées comme type JSONObject;

La deuxième étape consiste à définir le constructeur. Le constructeur reçoit l'url demandée, les paramètres, la signature Tencent Cloud, la valeur binaire du fichier à télécharger, le rappel de succès de téléchargement et le rappel d'échec de téléchargement. Dans l'entité de fonction, le cache de Volley est défini sur false et le délai d'expiration de la demande est défini ici sur 5 minutes. Bien sûr, ces deux valeurs peuvent également être transmises par le constructeur pour spécifier;

La troisième étape consiste à réécrire les deux méthodes nécessaires parseNetworkResponse et deliveryResponse, parseNetworkResponse, nous pouvons copier la méthode parseNetworkResponse dans la classe JsonRequest, deliveryResponse est le rappel qui spécifie le téléchargement réussi;

Ensuite, continuez à réécrire trois méthodes très importantes, à savoir getBodyContentType, getHeaders et getBody:

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

La chaîne renvoyée par la méthode getBodyContentType est la quatrième ligne des en-têtes que nous avons mentionnés ci-dessus;

La méthode getHeaders ajoute deux valeurs, Accept et Authorization. C'est ce que nous avons mentionné ci-dessus dans la ligne d'en-tête 2 et la ligne 3;

La méthode getBody est la partie du corps mentionnée ci-dessus qui doit être épissée manuellement. Avant cela, une boucle pour la valeur mParams transmise par le constructeur est créée. Une fois la boucle terminée, la partie mFileByte transmise par le constructeur est connectée.

La classe UploadRequest entière est maintenant terminée. Bien que notre intention initiale était de concevoir la fonction de téléchargement de Tencent Cloud, en fait, la classe UploadRequest est également complètement commune à d'autres formulaires ordinaires pour soumettre des fichiers téléchargés, tant qu'aucune signature n'est transmise.

Enfin, comment appeler:

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

Code correspondant, le processus d'appel consiste à spécifier d'abord un répertoire de fichiers de téléphone mobile, puis à correspondre au fichier et à calculer sa valeur sha1 et sa valeur binaire, puis à calculer la signature téléchargée à l'aide des informations fournies par Tencent Cloud, la dernière étape consiste à construire une demande de téléchargement que nous avons préparée L'objet de la classe est ensuite remis à RequestQueue. Autre point, n'oubliez pas de déclarer les autorisations correspondantes:

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

3 Résumé

Ce billet de blog décrit principalement la structure du formulaire et comment utiliser Volley pour générer le formulaire pour demander le réseau. Concernant l'utilisation de Tencent Cloud, dans notre exemple, afin d'analyser la soumission du formulaire, la méthode d'utilisation la plus originale est donnée. Si votre projet ne prend pas en compte la taille du package, vous pouvez utiliser le package Android SDK fourni par l'API Tencent Cloud. Il vous suffit de référencer simplement son pot dans le projet, la méthode d'introduction de l'API correspondante peut être très simple. Dix lignes de code peuvent compléter l'ensemble La fonction de téléchargement ne sera pas présentée ici en détail. Pour plus de détails, voir l'API de Tencent https://www.qcloud.com/document/api/436/6066 . De plus, le code source complet de ce projet peut être téléchargé ici .

 

Publié 106 articles originaux · loué 37 · 80 000 vues

Je suppose que tu aimes

Origine blog.csdn.net/lyz_zyx/article/details/73089230
conseillé
Classement