網(wǎng)絡訪問組件的思考四(volley簡單上傳下載)

參考:
http://blog.csdn.net/bboyfeiyu/article/details/42266869

具體代碼:
https://github.com/zhaoyubetter/basenet

Volley 框架沒有提供上傳下載功能,這里參考了網(wǎng)絡上的一些資料。簡單封裝了一下,使其擁有了 小文件 的上傳下載功能;
大文件Volley是個坑;

** okhttp,上傳下載大文件是沒問題的,開發(fā)中推薦使用 okhttp**

上傳文件的簡單封裝##

將http form表單請求報文的數(shù)據(jù)格式,用volley來模擬,實現(xiàn)文件上傳(支持表單普通字段,與文件字段);

class MultipartBody {


    private final static char[] MULTIPART_CHARS = "-_1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ".toCharArray();

    private final String CONTENT_TYPE = "Content-Type: ";
    private final String CONTENT_DISPOSITION = "Content-Disposition: ";
    

    /**
     * 字節(jié)流參數(shù)
     */
    private final String TYPE_OCTET_STREAM = "application/octet-stream";
    /**
     * 二進制參數(shù)
     */
    private final byte[] BINARY_ENCODING = "Content-Transfer-Encoding: binary\r\n\r\n".getBytes();

    /**
     * 換行符
     */
    private final String NEW_LINE_STR = "\r\n";

    /**
     * 分隔符
     */
    private String mBoundary = null;
    /**
     * 輸出流
     */
    ByteArrayOutputStream mOutputStream = new ByteArrayOutputStream();


    private StringBuilder mSb = new StringBuilder();


    public MultipartBody() {
        this.mBoundary = generateBoundary();
    }

    /**
     * 生成分隔符
     *
     * @return
     */
    private String generateBoundary() {
        final StringBuffer buf = new StringBuffer();
        final Random rand = new Random();
        for (int i = 0; i < 30; i++) {
            buf.append(MULTIPART_CHARS[rand.nextInt(MULTIPART_CHARS.length)]);
        }
        return buf.toString();
    }

    /**
     * 開頭分隔符
     * --WebKitFormBoundaryMcD0BA59mk3aFx4I
     */
    private void writeFirstBoundary() throws IOException {
        mOutputStream.write(("--" + mBoundary + NEW_LINE_STR).getBytes());
        mSb.append(("--" + mBoundary + NEW_LINE_STR));
    }

    /**
     * 添加文本參數(shù)
     */
    public void addStringPart(String paramName, String paramValue) {
        // writeToOutputStream(paramName, paramValue.getBytes(), TYPE_TEXT_CHARSET, BIT_ENCODING, "");
        writeToOutputStream(paramName, paramValue.getBytes(), null, null, "");
    }

    /**
     * 添加二進制參數(shù), 例如Bitmap的字節(jié)流參數(shù)
     *
     * @param paramName
     * @param rawData
     */
    public void addBinaryPart(String paramName, final byte[] rawData) {
        writeToOutputStream(paramName, rawData, TYPE_OCTET_STREAM, BINARY_ENCODING, "no-file");
    }

    /**
     * 添加文件參數(shù),可以實現(xiàn)文件上傳功能
     *
     * @param key
     * @param file
     */
    public void addFilePart(final String key, final File file) {
        InputStream fin = null;
        try {
            fin = new FileInputStream(file);
            writeFirstBoundary();
            mOutputStream.write(getContentDispositionBytes(key, file.getName()));
            final String type = CONTENT_TYPE + TYPE_OCTET_STREAM + NEW_LINE_STR;
            mOutputStream.write(type.getBytes());
            mOutputStream.write(NEW_LINE_STR.getBytes());

            final byte[] tmp = new byte[4096];
            int len = 0;
            while ((len = fin.read(tmp)) != -1) {
                mOutputStream.write(tmp, 0, len);
            }
            mOutputStream.write(NEW_LINE_STR.getBytes());
            mOutputStream.flush();
        } catch (final IOException e) {
            e.printStackTrace();
        } finally {
            closeSilently(fin);
        }
    }


    /**
     * 將數(shù)據(jù)寫入到輸出流中
     *
     * @param paramName
     * @param rawData
     * @param type
     * @param encodingBytes
     * @param fileName
     */
    private void writeToOutputStream(String paramName,
                                     byte[] rawData,
                                     String type,
                                     byte[] encodingBytes,
                                     String fileName) {
        try {
            writeFirstBoundary();
            if (type != null && type.length() > 0) {
                mOutputStream.write((CONTENT_TYPE + type + NEW_LINE_STR).getBytes());
            }
            mOutputStream.write(getContentDispositionBytes(paramName, fileName));
            mOutputStream.write(NEW_LINE_STR.getBytes());
            mSb.append(new String(rawData));

            if (encodingBytes != null) {
                mOutputStream.write(encodingBytes);
            }

            mOutputStream.write(rawData);
            mOutputStream.write(NEW_LINE_STR.getBytes());
        } catch (final IOException e) {
            e.printStackTrace();
        }
    }

    private byte[] getContentDispositionBytes(String paramName, String fileName) {
        StringBuilder stringBuilder = new StringBuilder();
        stringBuilder.append(CONTENT_DISPOSITION + "form-data; name=\"" + paramName + "\"");
        if (!TextUtils.isEmpty(fileName)) {
            stringBuilder.append("; filename=\"" + fileName + "\"");
        }
        return stringBuilder.append(NEW_LINE_STR).toString().getBytes();
    }


    public long getContentLength() {
        return mOutputStream.toByteArray().length;
    }

    // Content-Type: multipart/form-data; boundary=
    public String getContentType() {
        return "multipart/form-data; boundary=" + mBoundary;
    }

    public void writeTo(final OutputStream outstream) throws IOException {
        // 參數(shù)最末尾的結束符
        final String endString = "--" + mBoundary + "--" + NEW_LINE_STR;
        // 寫入結束符
        mOutputStream.write(endString.getBytes());
        outstream.write(mOutputStream.toByteArray());
    }


    private void closeSilently(Closeable closeable) {
        try {
            if (closeable != null) {
                closeable.close();
            }
        } catch (final IOException e) {
            e.printStackTrace();
        }
    }
}

新增類 PostUploadRequest,實現(xiàn)request:

class PostUploadRequest extends Request<String> {

    private Response.Listener mListener;

    private MultipartBody mMultiPartEntity = new MultipartBody();

    @Override
    protected Response<String> parseNetworkResponse(NetworkResponse response) {
        String parsed = "";
        try {
            parsed = new String(response.data, HttpHeaderParser.parseCharset(response.headers));
        } catch (UnsupportedEncodingException e) {
            parsed = new String(response.data);
        }
        return Response.success(parsed, HttpHeaderParser.parseCacheHeaders(response));

    }

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

    public Map<String, File> getUploadFiles() {
        return null;
    }

    public PostUploadRequest(int method, String url, Response.ErrorListener listener, Response.Listener mListener) {
        super(method, url, listener);
        this.mListener = mListener;
        // 超時設置 10 分鐘
        setRetryPolicy(new DefaultRetryPolicy(10 * 60 * 1000, 0, DefaultRetryPolicy.DEFAULT_BACKOFF_MULT));
        setShouldCache(false);
    }


    /**
     * 請求體
     *
     * @return
     * @throws AuthFailureError
     */
    @Override
    public byte[] getBody() throws AuthFailureError {
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        try {
            // 參數(shù)部分
            Map<String, String> params = getParams();
            if (params != null && params.size() > 0) {
                for (Map.Entry<String, String> entry : params.entrySet()) {
                    mMultiPartEntity.addStringPart(entry.getKey(), entry.getValue());
                }
            }

//          // 文件部分
            final Map<String, File> uploadFiles = getUploadFiles();
            if (uploadFiles != null && uploadFiles.size() > 0) {
                for (Map.Entry<String, File> entry : uploadFiles.entrySet()) {
                    mMultiPartEntity.addFilePart(entry.getKey(), entry.getValue());
                }
            }

            // multipart body
            mMultiPartEntity.writeTo(bos);
        } catch (IOException e) {
            throw new AuthFailureError(e.getMessage());
        }
        return bos.toByteArray();
    }

    @Override
    public String getBodyContentType() {
        return mMultiPartEntity.getContentType();
    }
}

在 VolleyRequest類中使用:

private void upload() {
        mRequest = new PostUploadRequest(Request.Method.POST, mUrl, new Response.ErrorListener() {
            @Override
            public void onErrorResponse(VolleyError error) {
                if (mCallBack != null) {
                    mCallBack.onFailure(error);
                }
            }
        }, new Response.Listener<String>() {
            @Override
            public void onResponse(String response) {
                if (mCallBack != null) {
                    mCallBack.onSuccess(response);
                }
            }
        }) {
            @Override
            public Map<String, String> getHeaders() throws AuthFailureError {
                Map<String, String> superHeader = super.getHeaders();
                if (mHeader != null && mHeader.size() > 0) {
                    superHeader = mHeader;
                }
                return superHeader;
            }

            // 設置Body參數(shù)
            @Override
            protected Map<String, String> getParams() throws AuthFailureError {
                Map<String, String> tParams = super.getParams();
                if (mParams != null && mParams.size() > 0) {
                    tParams = mParams;
                }
                return tParams;
            }

            @Override
            public Map<String, File> getUploadFiles() {
                return mUploadFiles;
            }
        };

        mRequest.setTag(mTag);
        requestQueue.add(mRequest);
    }

下載文件的簡單封裝##

新增DownRequest實現(xiàn)Request類:

public class DownRequest extends Request<byte[]> {

    private final Response.Listener<byte[]> mListener;

    public DownRequest(int method, String url, Response.ErrorListener listener, Response.Listener<byte[]> downListener) {
        super(method, url, listener);
        this.mListener = downListener;
        setShouldCache(false);
    }

    @Override
    protected Response<byte[]> parseNetworkResponse(NetworkResponse response) {
        return Response.success(response.data, HttpHeaderParser.parseCacheHeaders(response));
    }

    @Override
    protected void deliverResponse(byte[] response) {
        if (null != mListener) {
            mListener.onResponse(response);
        }
    }
}

下載實現(xiàn):

private void down() {
        mRequest = new DownRequest(Request.Method.GET, mUrl, new Response.ErrorListener() {
            @Override
            public void onErrorResponse(VolleyError error) {
                if (mCallBack != null) {
                    mCallBack.onFailure(error);
                }
            }
        }, new Response.Listener<byte[]>() {
            @Override
            public void onResponse(byte[] response) {
                try {
                    FileUtils.saveFile(response, mDownFile);
                    if (mCallBack != null) {
                        mCallBack.onSuccess(response);
                    }
                } catch (Exception e) {
                    if (mCallBack != null) {
                        mCallBack.onFailure(e);
                    }
                }
            }
        }) {
            @Override
            public Map<String, String> getHeaders() throws AuthFailureError {
                Map<String, String> superHeader = super.getHeaders();
                if (mHeader != null && mHeader.size() > 0) {
                    superHeader = mHeader;
                }
                return superHeader;
            }

            // 設置Body參數(shù)
            @Override
            protected Map<String, String> getParams() throws AuthFailureError {
                Map<String, String> tParams = super.getParams();
                if (mParams != null && mParams.size() > 0) {
                    tParams = mParams;
                }
                return tParams;
            }
        };

        mRequest.setTag(mTag);
        requestQueue.add(mRequest);
    }
最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容