网络访问组件的思考四(volley简单上传下载)

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

具体代码:
https://github.com/zhaoyubetter/basenet

Volley 框架没有提供上传下载功能,这里参考了网络上的一些资料。简单封装了一下,使其拥有了 小文件 的上传下载功能;
大文件Volley是个坑;

** okhttp,上传下载大文件是没问题的,开发中推荐使用 okhttp**

上传文件的简单封装##

将http form表单请求报文的数据格式,用volley来模拟,实现文件上传(支持表单普通字段,与文件字段);

class MultipartBody {


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

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

    /**
     * 字节流参数
     */
    private final String TYPE_OCTET_STREAM = "application/octet-stream";
    /**
     * 二进制参数
     */
    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));
    }

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

    /**
     * 添加二进制参数, 例如Bitmap的字节流参数
     *
     * @param paramName
     * @param rawData
     */
    public void addBinaryPart(String paramName, final byte[] rawData) {
        writeToOutputStream(paramName, rawData, TYPE_OCTET_STREAM, BINARY_ENCODING, "no-file");
    }

    /**
     * 添加文件参数,可以实现文件上传功能
     *
     * @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);
        }
    }


    /**
     * 将数据写入到输出流中
     *
     * @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 {
        // 参数最末尾的结束符
        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,实现request:

class PostUploadRequest extends Request {

    private Response.Listener mListener;

    private MultipartBody mMultiPartEntity = new MultipartBody();

    @Override
    protected Response 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 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 {
            // 参数部分
            Map params = getParams();
            if (params != null && params.size() > 0) {
                for (Map.Entry entry : params.entrySet()) {
                    mMultiPartEntity.addStringPart(entry.getKey(), entry.getValue());
                }
            }

//          // 文件部分
            final Map uploadFiles = getUploadFiles();
            if (uploadFiles != null && uploadFiles.size() > 0) {
                for (Map.Entry 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() {
            @Override
            public void onResponse(String response) {
                if (mCallBack != null) {
                    mCallBack.onSuccess(response);
                }
            }
        }) {
            @Override
            public Map getHeaders() throws AuthFailureError {
                Map superHeader = super.getHeaders();
                if (mHeader != null && mHeader.size() > 0) {
                    superHeader = mHeader;
                }
                return superHeader;
            }

            // 设置Body参数
            @Override
            protected Map getParams() throws AuthFailureError {
                Map tParams = super.getParams();
                if (mParams != null && mParams.size() > 0) {
                    tParams = mParams;
                }
                return tParams;
            }

            @Override
            public Map getUploadFiles() {
                return mUploadFiles;
            }
        };

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

下载文件的简单封装##

新增DownRequest实现Request类:

public class DownRequest extends Request {

    private final Response.Listener mListener;

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

    @Override
    protected Response parseNetworkResponse(NetworkResponse response) {
        return Response.success(response.data, HttpHeaderParser.parseCacheHeaders(response));
    }

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

下载实现:

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() {
            @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 getHeaders() throws AuthFailureError {
                Map superHeader = super.getHeaders();
                if (mHeader != null && mHeader.size() > 0) {
                    superHeader = mHeader;
                }
                return superHeader;
            }

            // 设置Body参数
            @Override
            protected Map getParams() throws AuthFailureError {
                Map tParams = super.getParams();
                if (mParams != null && mParams.size() > 0) {
                    tParams = mParams;
                }
                return tParams;
            }
        };

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

你可能感兴趣的:(网络访问组件的思考四(volley简单上传下载))