안드로이드 AsyncTask를 이용한 HttpUrlConnection
구글검색해서 구현하려다 한글전송이 안되고, 클래스구조와 코드가 복잡해지고 기타등등 이유로 정리용 포스팅입니다.
설명은 검색하면 많이 나오니 간략하게 씁니다.
묻지도 따지지도 말고 아래와 같이 클래스를 하나 만들고 고대로 붙여넣으세요.
RequestHttpURLConnection.java
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 | public class RequestHttpURLConnection { public String request(String _url, ContentValues _params) { HttpURLConnection urlConn = null; // URL 뒤에 붙여서 보낼 파라미터. StringBuffer sbParams = new StringBuffer(); /** * 1. StringBuffer에 파라미터 연결 * */ // 보낼 데이터가 없으면 파라미터를 비운다. if (_params == null) sbParams.append(""); // 보낼 데이터가 있으면 파라미터를 채운다. else { // 파라미터가 2개 이상이면 파라미터 연결에 &가 필요하므로 스위칭할 변수 생성. boolean isAnd = false; // 파라미터 키와 값. String key; String value; for (Map.Entry<String, Object> parameter : _params.valueSet()) { key = parameter.getKey(); value = parameter.getValue().toString(); // 파라미터가 두개 이상일때, 파라미터 사이에 &를 붙인다. if (isAnd) sbParams.append("&"); sbParams.append(key).append("=").append(value); // 파라미터가 2개 이상이면 isAnd를 true로 바꾸고 다음 루프부터 &를 붙인다. if (!isAnd) if (_params.size() >= 2) isAnd = true; } } /** * 2. HttpURLConnection을 통해 web의 데이터를 가져온다. * */ try { URL url = new URL(_url); urlConn = (HttpURLConnection) url.openConnection(); // [2-1]. urlConn 설정. urlConn.setReadTimeout(10000); urlConn.setConnectTimeout(15000); urlConn.setRequestMethod("POST"); // URL 요청에 대한 메소드 설정 : GET/POST. urlConn.setDoOutput(true); urlConn.setDoInput(true); urlConn.setRequestProperty("Accept-Charset", "utf-8"); // Accept-Charset 설정. urlConn.setRequestProperty("Context_Type", "application/x-www-form-urlencoded"); // [2-2]. parameter 전달 및 데이터 읽어오기. PrintWriter pw = new PrintWriter(new OutputStreamWriter(urlConn.getOutputStream())); pw.write(sbParams.toString()); pw.flush(); // 출력 스트림을 flush. 버퍼링 된 모든 출력 바이트를 강제 실행. pw.close(); // 출력 스트림을 닫고 모든 시스템 자원을 해제. // [2-3]. 연결 요청 확인. // 실패 시 null을 리턴하고 메서드를 종료. if (urlConn.getResponseCode() != HttpURLConnection.HTTP_OK) return null; // [2-4]. 읽어온 결과물 리턴. // 요청한 URL의 출력물을 BufferedReader로 받는다. BufferedReader reader = new BufferedReader(new InputStreamReader(urlConn.getInputStream(), "UTF-8")); // 출력물의 라인과 그 합에 대한 변수. String line; String page = ""; // 라인을 받아와 합친다. while ((line = reader.readLine()) != null) { page += line; } return page; } catch (MalformedURLException e) { // for URL. e.printStackTrace(); } catch (IOException e) { // for openConnection(). e.printStackTrace(); } finally { if (urlConn != null) urlConn.disconnect(); } return null; } } | cs |
AsyncTask
통신하고자 하는 액티비티에 비동기통신을 위한 클래스를 하나 선언하고 AsyncTask 클래스를 상속하세요.
상속하면 오버라이드가 필요한 메소드들이 있다고 경고창이 뜰 텐데, 시키는대로 메소드들을 오버라이드하세요.
AsyncTask의 과정은 다음과 같습니다.
좀 더 근본적인 과정에 대해 자세히 알고 싶다면, 자세한 사항은 이곳을 확인하세요:
귀찮으시면 아래의 코드를 고대로 붙여넣으세요.
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 | } // onCreate() 끝 public class NetworkTask extends AsyncTask<Void, Void, String> { String url; ContentValues values; NetworkTask(String url, ContentValues values){ this.url = url; this.values = values; } @Override protected void onPreExecute() { super.onPreExecute(); //progress bar를 보여주는 등등의 행위 } @Override protected String doInBackground(Void... params) { String result; RequestHttpURLConnection requestHttpURLConnection = new RequestHttpURLConnection(); result = requestHttpURLConnection.request(url, values); return result; // 결과가 여기에 담깁니다. 아래 onPostExecute()의 파라미터로 전달됩니다. } @Override protected void onPostExecute(String result) { // 통신이 완료되면 호출됩니다. // 결과에 따른 UI 수정 등은 여기서 합니다. Toast.makeText(getApplicationContext(), result, Toast.LENGTH_LONG).show(); } } | cs |
과정
간단하게 위 과정을 설명하자면
- 필드에는 통신하고자 하는 url과 파라미터로 붙을 ContentValues가 존재하며, 통신을 위해 해당 클래스객체를 생성할 때 생성자로 두 필드를 받습니다.
- onPreExecute() 이후 doInBackground() 메소드가 호출되어 미리 만들어 놓은 RequestHttpUrlConnection 클래스를 이용해 통신하고(이 때 생성자로 입력한 url과 ContentValues 전달) 결과값인 result를 담아 리턴합니다.
- onPostExecute() 메소드가 호출되고, 결과값인 result를 통해 처리합니다.
- 위 과정에 생략된 onProgressUpdate()는 진행 중 처리하고 싶은 로직을 작성하면 됩니다. 일반적으로 진행 중.. (50%) 이런 프로그레스바의 진행정도를 변경할때 사용합니다.
호출
아래와 같이 필요한 부분에서 execute()하면 됩니다.
로그인과정이라고 가정한 간단한 예입니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | /* 버튼 클릭 */ btn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { String id = login_et_id.getText().toString().trim(); String pw = login_et_pw.getText().toString(); /* DB 대조 */ ContentValues values = new ContentValues(); values.put("id", id); values.put("pw", pw); NetworkTask networkTask = new NetworkTask(url, values); networkTask.execute(); } }); | cs |
요약
- 생성한 ContentValues 객체에 put(key, value)을 이용해 파라미터를 밀어넣고
- NetworkTask 객체를 생성해 생성자 파라미터로 url과 ContentValues 객체를 넣은 후
- execute() 한 뒤
- 받아온 결과(result)를 onPostExecute()에서 처리하면 됩니다. (UI 수정, Activity 이동 등)