본문 바로가기

Android/Basic

[Android] HttpURLConnection 예제

최종 업데이트 20.09.25

HttpURLConnection 을 이용하여 웹페이지의 내용(html) 을 읽어오는 예제



0. 먼저 Manifest.xml 에 권한을 추가한다.

<uses-permission android:name="android.permission.INTERNET"/>


1. 웹페이지의 내용을 뿌려줄 화면 레이아웃을 구성한다.

editText에 있는 링크에 접속해서 textView에 내용 뿌려주는 뷰로 구성되어있다.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity">

<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">

<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Button" />

<EditText
android:id="@+id/editText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:ems="10"
android:inputType="textPersonName"
android:text="https://m.naver.com" />
</LinearLayout>

<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/holo_blue_dark">

<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">

<TextView
android:id="@+id/textView"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
</ScrollView>
</LinearLayout>


2. 웹페이지에 연결할 Thread 클래스를 만든다.

스레드를 따로 만들어야하는 이유는, 작업시간이 오래걸릴 수 있는 IO 작업(서버통신)을 메인스레드에서 작업할 경우 블로킹이 발생할 수 있기때문에 안드로이드 자체적으로 익셉션이 발생한다. 따라서 IO 작업은 백그라운드 스레드로 수행해야한다.

class RequestThread extends Thread {
public void run(){

try {
URL url = new URL(urlStr);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();

if (conn != null){
conn.setConnectTimeout(10000); // 10초 대기 후 응답이 없으면 끝
conn.setRequestMethod("GET");
conn.setDoInput(true); // 서버에서 받기 가능
conn.setDoOutput(true); // 서버에 보내기 가능

int resCode = conn.getResponseCode(); // 서버에 연결 시도

// reader는 바이트 배열이 아니라, 문자열로 처리할 수 있음
// BufferedReader는 한줄씩 읽어들임
BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
String line = null;

while (true) {
line = reader.readLine();
if (line == null) break;

println(line);
}

reader.close();
conn.disconnect();
}

} catch(Exception e){
e.printStackTrace();
}
}
}

public void println(final String data){
handler.post(new Runnable() {
@Override
public void run() {
textView.append(data + "\n");
}
});
}


백그라운드 스레드에서 실행한 작업 결과를 바로 textView 에 뿌리려고하면 익셉션이 발생한다. 안드로이드 뷰에 접근할 수 있는 스레드는 메인스레드로 한정되어있기 때문이다. 따라서 메인스레드로 작업 결과물을 패스할 수 있도록 핸들러를 이용해 메인스레드 작업큐로 보내야한다.

위처럼 해야하는 이유가 궁금하다면 여기를 읽어보길 바란다. 오래된 아티클이지만 안드로이드가 백그라운드를 다루는 개념을 쉽게 이해할 수 있을 것이다.


# 메인액티비티 전체코드

public class MainActivity extends AppCompatActivity {
EditText editText;
TextView textView;

Handler handler = new Handler();

String urlStr;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

editText = findViewById(R.id.editText);
textView = findViewById(R.id.textView);

findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
urlStr = editText.getText().toString();

RequestThread thread = new RequestThread();
thread.start();
}
});
}

class RequestThread extends Thread {
public void run(){

try {
URL url = new URL(urlStr);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();

if(conn != null){
conn.setConnectTimeout(10000); // 10초 대기 후 응답이 없으면 끝
conn.setRequestMethod("GET");
conn.setDoInput(true); // 서버에서 받기 가능
conn.setDoOutput(true); // 서버에 보내기 가능

int resCode = conn.getResponseCode(); // 서버에 연결 시도

// reader는 바이트 배열이 아니라, 문자열로 처리할 수 있음
// BufferedReader는 한줄씩 읽어들임
BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
String line = null;

while(true){
line = reader.readLine();
if(line == null) break;

println(line);
}

reader.close();
conn.disconnect();
}

} catch(Exception e){
e.printStackTrace();
}
}
}

public void println(final String data){
handler.post(new Runnable() {
@Override
public void run() {
textView.append(data + "\n");
}
});
}
}

사실 스레드 클래스를 위처럼 짜면 메모리 릭 위험성이 존재하므로 그대로 따라하면 안된다. 왜 메모리릭이 발생하는지 모른다면 스스로 공부해보길 바란다 ^.'