HttpURLConnection을 사용하여 Multipart Upload를 수행하고 그 과정을 ProgressBar로 보여주기를 하는 코드이다.
다음 순서대로 작성하고 적용하면 끝.
1. 인터페이스 생성
1 2 3 4 | public interface ProgressListener { void onProgressUpdate(int progress); } | cs |
2. MultipartUpload 클래스
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 | public class MultipartUpload { private final String boundary; private final String tail; private static final String LINE_END = "\r\n"; private static final String TWOHYPEN = "--"; private HttpURLConnection httpConn; private String charset; private PrintWriter writer; private OutputStream outputStream; private static final String TAG = "MultipartUtility"; int maxBufferSize = 1024; private ProgressListener progressListener; private long startTime; public MultipartUpload(String requestURL, String charset) throws IOException { this.charset = charset; boundary = "===" + System.currentTimeMillis() + "==="; tail = LINE_END + TWOHYPEN + boundary + TWOHYPEN + LINE_END; URL url = new URL(requestURL); httpConn = (HttpURLConnection) url.openConnection(); httpConn.setDoOutput(true); httpConn.setDoInput(true); httpConn.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundary); } public void setProgressListener(ProgressListener progressListener) { this.progressListener = progressListener; } public JSONObject upload(HashMap<String, String> params, HashMap<String, String> files) throws IOException { String paramsPart = ""; String fileHeader = ""; String filePart = ""; long fileLength = 0; startTime = System.currentTimeMillis(); ArrayList<String> paramHeaders = new ArrayList<>(); for (Map.Entry<String, String> entry : params.entrySet()) { String param = TWOHYPEN + boundary + LINE_END + "Content-Disposition: form-data; name=\"" + entry.getKey() + "\"" + LINE_END + "Content-Type: text/plain; charset=" + charset + LINE_END + LINE_END + entry.getValue() + LINE_END; paramsPart += param; paramHeaders.add(param); } ArrayList<File> filesAL = new ArrayList<>(); ArrayList<String> fileHeaders = new ArrayList<>(); for (Map.Entry<String, String> entry : files.entrySet()) { File file = new File(entry.getValue()); fileHeader = TWOHYPEN + boundary + LINE_END + "Content-Disposition: form-data; name=\"" + entry.getKey() + "\"; filename=\"" + file.getName() + "\"" + LINE_END + "Content-Type: " + URLConnection.guessContentTypeFromName(file.getAbsolutePath()) + LINE_END + "Content-Transfer-Encoding: binary" + LINE_END + LINE_END; fileLength += file.length() + LINE_END.getBytes(charset).length; filePart += fileHeader; fileHeaders.add(fileHeader); filesAL.add(file); } String partData = paramsPart + filePart; long requestLength = partData.getBytes(charset).length + fileLength + tail.getBytes(charset).length; httpConn.setRequestProperty("Content-length", "" + requestLength); httpConn.setFixedLengthStreamingMode((int) requestLength); httpConn.connect(); outputStream = new BufferedOutputStream(httpConn.getOutputStream()); writer = new PrintWriter(new OutputStreamWriter(outputStream, charset), true); for (int i = 0; i < paramHeaders.size(); i++) { writer.append(paramHeaders.get(i)); writer.flush(); } int totalRead = 0; int bytesRead; byte buf[] = new byte[maxBufferSize]; for (int i = 0; i < filesAL.size(); i++) { writer.append(fileHeaders.get(i)); writer.flush(); BufferedInputStream bufferedInputStream = new BufferedInputStream(new FileInputStream(filesAL.get(i))); while ((bytesRead = bufferedInputStream.read(buf)) != -1) { outputStream.write(buf, 0, bytesRead); writer.flush(); totalRead += bytesRead; if (progressListener != null) { float progress = (totalRead / (float) requestLength) * 100; progressListener.onProgressUpdate((int) progress); } } outputStream.write(LINE_END.getBytes()); outputStream.flush(); bufferedInputStream.close(); } writer.append(tail); writer.flush(); writer.close(); JSONObject jObj = null; StringBuilder sb = new StringBuilder(); // checks server's status code first int status = httpConn.getResponseCode(); if (status == HttpURLConnection.HTTP_OK) { BufferedReader reader = new BufferedReader(new InputStreamReader(httpConn.getInputStream(), "UTF-8"), 8); String line = null; while ((line = reader.readLine()) != null) { sb.append(line).append("\n"); } reader.close(); httpConn.disconnect(); } else { throw new IOException("Server returned non-OK status: " + status + " " + httpConn.getResponseMessage()); } try { jObj = new JSONObject(sb.toString()); } catch (JSONException | NullPointerException e) { e.printStackTrace(); } return jObj; } } | cs |
3. 사용법
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 | class UploadAsync extends AsyncTask<Object, Integer, JSONObject> implements ProgressListener { private ProgressDialog progressDialog; private Context mContext; private HashMap<String, String> param; private HashMap<String, String> files; public UploadAsync(Context context, HashMap<String, String> param, HashMap<String, String> files) { mContext = context; this.param = param; this.files = files; } @Override protected void onPreExecute() { super.onPreExecute(); startTime = System.currentTimeMillis(); progressDialog = new ProgressDialog(mContext); progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL); progressDialog.setMessage(mContext.getString(R.string.wait)); progressDialog.setMax(100); progressDialog.setCancelable(false); progressDialog.show(); } @Override protected JSONObject doInBackground(Object... params) { JSONObject json = null; try { String url = "http://요청할 URL"; MultipartUpload multipartUpload = new MultipartUpload(url, "UTF-8"); multipartUpload.setProgressListener(this); json = multipartUpload.upload(param, files); } catch (IOException e) { e.printStackTrace(); } return json; } @Override protected void onProgressUpdate(Integer... values) { super.onProgressUpdate(values); if (progressDialog != null && progressDialog.isShowing()) { if (values[1] == 1) { progressDialog.setProgress(values[0]); } else { progressDialog.setProgress(values[0]); } } } @Override protected void onPostExecute(JSONObject result) { super.onPostExecute(result); if (progressDialog.isShowing()) { progressDialog.dismiss(); } if (result != null) { try { if (result.getInt("success") == 1) { Toast.makeText(mContext, R.string.success, Toast.LENGTH_SHORT).show(); } } catch (JSONException e) { e.printStackTrace(); } } else { Toast.makeText(mContext, R.string.conntection_error, Toast.LENGTH_SHORT).show(); } } @Override public void onProgressUpdate(int progress) { publishProgress(progress, 0); } } | cs |
네트워크 작업이므로 반드시 스레드 안에서 실행해야 한다.
생성자로 접속할 url과 캐릭터셋을 넣고, 프로그레스를 받을 인터페이스 리스너를 등록 한 후 파라미터 파트와 파일 파트를 HashMap으로 구성하여 인자로 넘겨준다.
한가지 문제점은 실제로 접속하여 파일을 전송하는 과정이 progress되지 않는다는 점이다. MultipartUpload 클래스에 보면 outputstream에 쓰는 과정을 progress로 보여주는데 사실 이것이 파일이 전송됨을 의미하지는 않는다는 점이다. 단지 버퍼에서 읽는 부분일뿐.. 실제 예제를 만들어 progress가 100%가 후에 전송을 시작하여 마치 앱이 멈춘것 처럼 동작한다. 파일 크기가 작으면 전송이 빨리되어 약간의 딜레이가 생기겠지만 파일이 큰 경우 오류난것 처럼 보인다.
버퍼에 쓴다음 바로 flush를 해줘도 똑같다. setFixedLenghStreamingMode를 해주면 된다고는 하는데 안된다! 이거 실제 전송되는 부분 아시는분은 알려주시면 감사하겠습니다.
'Android' 카테고리의 다른 글
[Android] APK 생성시 이름 변경하기 (0) | 2016.11.10 |
---|---|
[Android] Android API 버전 정보(SDK INT) (0) | 2016.11.10 |
[Android] RecyclerView 에서 드래그앤드롭(drag&drop)과 스와이프(swpie&dismiss) 사용하기 (2) | 2016.11.10 |
[Android] Service와 IntentService의 차이점 (0) | 2016.11.10 |
[Android] Android SDK command line Linux 설치하기 (0) | 2016.11.10 |