안녕하세요. 안드로이드 PEACE-입니다.
안드로이드 스터디 [열 한번째] 글입니다.
안드로이드는 서버와 통신하기 위한 방법으로는 HTTP통신과 Soket통신이 있다. 오늘 다룰 내용은 HTTP통신으로 URL 접속을 통해 데이터를 읽어오는 방법이다. 우리는 주로 DB에 존재하는 데이터를 가져오기 위해 서버 통신을 한다. 하지만 안드로이드의 특성상 외부 DB에 직접 접근할 수 가 없도록 되어있어 중간 매체인 WEB을 활용해야한다. 이해를 위해 그림으로 쉽게 표현했다.
[그림 1] 안드로이드와 WEB, 그리고 DB 통신 과정
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="peace.httpurlconnection">
<!-- 네트워크 사용에 대한 퍼미션 -->
<uses-permission android:name="android.permission.INTERNET" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
두번째로 별도의 클래스(RequestHttpURLConnection)를 만들어 HttpURLConnection을 수행하는 기능 구현한다.
in RequestHttpConnection.class
import android.content.ContentValues;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Map;
public class RequestHttpURLConnection {
public String request(String _url, ContentValues _params){
// HttpURLConnection 참조 변수.
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.setRequestMethod("POST"); // URL 요청에 대한 메소드 설정 : POST.
urlConn.setRequestProperty("Accept-Charset", "UTF-8"); // Accept-Charset 설정.
urlConn.setRequestProperty("Context_Type", "application/x-www-form-urlencoded;cahrset=UTF-8");
// [2-2]. parameter 전달 및 데이터 읽어오기.
String strParams = sbParams.toString(); //sbParams에 정리한 파라미터들을 스트링으로 저장. 예)id=id1&pw=123;
OutputStream os = urlConn.getOutputStream();
os.write(strParams.getBytes("UTF-8")); // 출력 스트림에 출력.os.flush(); // 출력 스트림을 플러시(비운다)하고 버퍼링 된 모든 출력 바이트를 강제 실행.
os.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;
}
}
세번째로 MainActivity에서의 위젯을 처리하고 Network Processing에 대해서 비동기 처리하기 위해 AsyncTask를 구현한다.
in MainActivity.class
import android.content.ContentValues;
import android.os.AsyncTask;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.TextView;
public class MainActivity extends AppCompatActivity {
private TextView tv_outPut;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 위젯에 대한 참조.
tv_outPut = (TextView) findViewById(R.id.tv_outPut);
// URL 설정.
String url = "http:// .cafe24.com/LoadPat ";
// AsyncTask를 통해 HttpURLConnection 수행.
NetworkTask networkTask = new NetworkTask(url, null);
networkTask.execute();
}
public class NetworkTask extends AsyncTask<Void, Void, String> {
private String url;
private ContentValues values;
public NetworkTask(String url, ContentValues values) {
this.url = url;
this.values = values;
}
@Override
protected String doInBackground(Void... params) {
String result; // 요청 결과를 저장할 변수.
RequestHttpURLConnection requestHttpURLConnection = new RequestHttpURLConnection();
result = requestHttpURLConnection.request(url, values); // 해당 URL로 부터 결과물을 얻어온다.
return result;
}
@Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
//doInBackground()로 부터 리턴된 값이 onPostExecute()의 매개변수로 넘어오므로 s를 출력한다.
tv_outPut.setText(s);
}
}
}
다음은 MainActivity.class에 대한 레이아웃이다.
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="peace.httpurlconnection.MainActivity">
<TextView
android:id="@+id/tv_outPut"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="출력 공간"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</RelativeLayout>
4. 구현 화면
필자는 호스팅된 주소에 접속해 출력 결과를 TextView에 출력했다.
#참고사항
안드로이드에서 HttpURLConnection를 사용하는데 많은 기능을 제공한다.
예를들어 타임 제한을 걸어둘 수 있는 메서드도 있다. 안드로이드 디벨로퍼를 참고하길 바란다.
https://developer.android.com/reference/java/net/HttpURLConnection.html