前段
HTTP POSTでファイルを送信するにはmultipartリクエストを送信する必要があるのですが、Volleyにそれ用のリクエストクラスが無かったので嫌々自作しました。本サンプルではStringRequestを拡張して作成していますが、適宜変更してください。
ソース
MultipartStringRequest.java
public class MultipartStringRequest extends StringRequest { private static final String CRLF = "\r\n"; private final String boundary = "----boundary" + System.currentTimeMillis(); // テキストパラメータ nameとvalue private Map<String, String> textParams = new HashMap<>(); // バイナリパラメータ nameとファイルパス private Map<String, String> binaryParams = new HashMap<>(); public MultipartStringRequest(String url, Response.Listener<String> listener, Response.ErrorListener errorListener) { super(Method.POST, url, listener, errorListener); } @Override public String getBodyContentType() { return "multipart/form-data;boundary=" + boundary; } @Override public byte[] getBody() throws AuthFailureError { ByteArrayOutputStream bos = new ByteArrayOutputStream(); DataOutputStream dos = new DataOutputStream(bos); try { writeTextPart(dos); writeBinaryPart(dos); dos.writeBytes("--" + boundary + "--" + CRLF); } catch (IOException e) { e.printStackTrace(); } return bos.toByteArray(); } private void writeTextPart(DataOutputStream dos) throws IOException { for (Map.Entry<String, String> e: textParams.entrySet()) { dos.write(encodeToByteArray("Content-Disposition: form-data; name=\"" + e.getKey() + "\"" + CRLF)); dos.writeBytes(CRLF); dos.write(encodeToByteArray(e.getValue() + CRLF)); dos.writeBytes("--" + boundary + CRLF); } } private void writeBinaryPart(DataOutputStream dos) throws IOException { for (Map.Entry<String, String> e: binaryParams.entrySet()) { UploadFile uploadFile = new UploadFile(e.getValue()); dos.write(encodeToByteArray("Content-Disposition: form-data; name=\"" + e.getKey() + "\"; filename=\"" + uploadFile.getName() + "\"" + CRLF)); dos.writeBytes("Content-Type: " + uploadFile.getMimeType() + CRLF); dos.writeBytes(CRLF); dos.write(uploadFile.getByteArray()); dos.writeBytes(CRLF); dos.writeBytes(CRLF); dos.writeBytes("--" + boundary + CRLF); } } public void setTextParams(Map<String, String> textParams) { this.textParams = textParams; } public void setBinaryParams(Map<String, String> binaryParams) { this.binaryParams = binaryParams; } protected byte[] encodeToByteArray(String str) { return str.getBytes(); } }
UploadFile.java
// 上記MultipartStringRequestと同じパッケージに class UploadFile { private final String filePath; UploadFile(String filePath) { this.filePath = filePath; } String getName() { return PathUtil.getFileName(filePath); } String getMimeType() { MimeTypeMap mime = MimeTypeMap.getSingleton(); String extension = PathUtil.getExtension(filePath); return extension != null ? mime.getMimeTypeFromExtension(extension) : null; } byte[] getByteArray() throws IOException { return FileUtil.readAsByteArray(new File(filePath)); } }
FileUtil.java
public class FileUtil { public static byte[] readAsByteArray(File file) throws IOException { long length = file.length(); byte[] bytes = new byte[(int)length]; InputStream is = new FileInputStream(file); int offset = 0; int numRead; while ((offset < bytes.length) && ((numRead = is.read(bytes, offset, bytes.length - offset)) >= 0)) { offset += numRead; } is.close(); return bytes; } }
PathUtil.java
public class PathUtil { public static String getFileName(String path) { return new File(path).getName(); } public static String getExtension(String path) { String extension = null; int index = path.lastIndexOf("."); if (index > 0) { extension = path.substring(index + 1); } return extension; } }
使い方は次のような感じです。普通のテキストパラメータはnameとvalueのハッシュを、画像等のアップロードファイルはnameとファイルパスのハッシュをセットしてあげます。
クライアント.java
MultipartStringRequest request = new MultipartStringRequest( "https://example.com/api/entryPoint", new Response.Listener<String>() { @Override public void onResponse(String response) { // do something } }, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError error) { // do something } } ); Map<String, String> textParams = new HashMap<>(); textParams.put("username", "hoge"); textParams.put("email", "a@b.com"); request.setTextParams(textParams); Map<String, String> binaryParams = new HashMap<>(); binaryParams.put("uploadFile", "/path/to/file.jpeg"); request.setBinaryParams(binaryParams); queue.add(request);
おまけ
multipartリクエストで、さらに「Shift-JIS」で「任意のRefererをセットする」という仕様のリクエストの作成例です。先ほどのMultipartStringRequest
を継承して作成しています。
HogeRequest.java
public class HogeRequest extends MultipartStringRequest { private final Map<String, String> headers = new HashMap<>(); public HogeRequest(String url, Response.Listener<String> listener, Response.ErrorListener errorListener) { super(url, listener, errorListener); } @Override public Map<String, String> getHeaders() throws AuthFailureError { return headers; } @Override protected String getParamsEncoding() { return "Shift_JIS"; } public void setReferer(String url) { headers.put("Referer", url); } @Override protected byte[] encodeToByteArray(String str) { byte[] result = null; try { result = str.getBytes("SJIS"); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } return result; } }
関連する記事
- 【Android】フリックイベントを実装する
- 【Android】10回に1回インタースティシャル広告を表示する
- 【Android】安全にonActivityResultを実行する
- 【Android】リストビューの自動スクロール機能を実装する
- Android StudioからAndroid-PullToRefreshを使用する