본문 바로가기
Android App/Kotlin

네트워크-데이터 통신(HttpURLConnection)

by AppJinny 2022. 12. 6.

*네트워크-데이터 통신(HttpURLConnection)

-안드로이드는 HTTP로 데이터 통신을 하기 위해 HttpURLConnection 클래스 지원

-HTTPS(보완 강화된 버전의 프로토콜) 사양으로 확장한 HttpsURLConnection 클래스 지원

-네트워크도 파일과 동일하게 요청하는 스마트폰에서 서버쪽의 데이터를 읽는 도구로 스트림 사용

-HttpURLConnection연결 시 파일에서 File클래스를 사용한 것처럼 서버의 기본정보를 읽어올 수 있음

-실제 데이터를 읽어오기 위해 HttpURLConnection에서 InputStream(읽기 전용 스트림)을 꺼내 사용

 

 

*HttpURLConnection사용하기

-웹 페이지 주소를 입력하여 서버로부터 응답받은 웹 페이지의 코드를 화면에 출력하는 앱 구현

 

-build.gradle

-- android{} 에 뷰바인딩 추가

//뷰바인딩
buildFeatures{
    viewBinding true
}

 

-AndroidManifest.xml

<!--  인터넷 접근 권한 명세  -->
    <uses-permission android:name="android.permission.INTERNET"/>

<!--  http주소에 대해 강화된 네트워크 보안정책으로 인한 오류 예외처리를 위해  -->
<!--  android:usesCleartextTraffic="true" 설정  -->
    <application

        android:usesCleartextTraffic="true"

 

-MainActivity.kt

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import com.heeyjinny.networkhttpurlconnection.databinding.ActivityMainBinding
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import java.io.BufferedReader
import java.io.InputStreamReader
import java.net.HttpURLConnection
import java.net.URL

/**웹 페이지 주소를 입력하여 서버로부터 응답받은 웹 페이지 코드를 화면에 출력하는 앱 만들기**/

//1
//인터넷 접근 권한 명세
//AndroidManifest.xml 작성

//2
//주소 입력받을 editText, 요청 Button
//응답 받은 코드 출력할 textView 추가
//activity_main.xml 작성

class MainActivity : AppCompatActivity() {

    //뷰바인딩
    val binding by lazy { ActivityMainBinding.inflate(layoutInflater) }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(binding.root)

        //3
        //요청버튼 클릭 시 코드실행
        binding.btnRequest.setOnClickListener {

            //4
            //버튼 클릭 시 백그라운드에서 네트워크 작업 요청하기위해
            //코루틴스코프 생성하고 디스패처 IO사용
            CoroutineScope(Dispatchers.IO).launch {

                //7
                //try-catch문으로 감싸서 예외처리하기(5~6코드)
                //네트워크관련 코드는 예외로 치명적인 오류(앱 다운)발생 위험이 있음
                //try 문에서 Exception 예외가 발생할 경우
                //catch (Exception e) 로 빠져서 그 안의 실행문을 실행하는 구조
                try {

                    //5
                    //주소입력 필드에 입력된 주소를 가져오기
                    //http의 주소는 보안 문제가 있으며 http를 사용하기 위해
                    //AndroidManifest.xml에 설정이 필요함...
                    //만약 설정을 하지 않았다면
                    //url의 앞이 https로 시작하지 않았을 때 https로 변경하는 코드 작성
                    var urlText = binding.editUrl.text.toString()
                    if (!urlText.startsWith("https")){
                        urlText = "https://${urlText}"
                    }

                    //5-1
                    //주소를 URL객체로 변환하고 변수에 저장
                    val url = URL(urlText)

                    //5-2
                    //openConnection()메서드에서 반환되는 값은
                    //URLConnection이라는 추상(설계)클래스임
                    //이 추상클래스를 사용하기 위해서는 실제 구현클래스를 사용해야되므로
                    //HttpURLConnectiond으로 형변환 시킴

                    //서버와의 연결을 생성하기 위해
                    //URL객체에서 openConnection()메서드를 사용하고
                    //HttpURLConnection으로 형변환
                    val urlConnection = url.openConnection() as HttpURLConnection

                    //5-3
                    //연결된 커넥션에 요청방식 설정
                    //HTTP메서드를 사용하며 대문자로 입력
                    urlConnection.requestMethod = "GET"

                    //6
                    //응답이 정상(HttpURLConnection.HTTP_OK) 이면 응답 데이터 처리
                    if (urlConnection.responseCode == HttpURLConnection.HTTP_OK){

                        //6-1
                        //실제 데이터를 읽어오기 위해서는
                        //HttpURLConnection에서 InputStream 이라는 읽기전용 스트림 꺼내 사용
                        //데이터를 읽어오는 입력스트림(InputStreamReader)에
                        //커넥션 스트림 연결
                        val streamReader = InputStreamReader(urlConnection.inputStream)
                        //6-2
                        //커넥션 스트림을 연결한 데이터를 읽어오는 스트림을
                        //버퍼에 담아 읽을 준비
                        val buffered = BufferedReader(streamReader)

                        //6-3
                        //반복문을 돌면서 읽어온 데이터를
                        //한 줄씩 읽어와 content변수에 저장
                        val content = StringBuilder()
                        while (true){
                            //읽을 데이터가 없을 때 break설정
                            val line = buffered.readLine()?:break
                            content.append(line)
                        }
                        //6-4
                        //사용한 스트림과 커넥션 모두 해제
                        buffered.close()
                        urlConnection.disconnect()

                        //6-5
                        //화면의 텍스트뷰에 content에 저장된 데이터 값 입력
                        //화면 텍스트뷰(UI)에 값을 세팅하기 때문에 Main디스패처 사용함
                        launch(Dispatchers.Main){
                            binding.textContent.text = content.toString()
                        }

                    }//if Http_OK

                }catch (e: Exception){

                    //7-1
                    //catch에 e.printStackTrace()메서드 사용
                    //e.printStackTrace() : 예외발생 시 로그를 출력하며
                    //서브스레드로 동작하기 때문에 print문 사용보다 성능이 좋음
                    e.printStackTrace()

                }

            }//코루틴스코프

        }//btnRequest click

    }//onCreate
}//MainActivity

 

-activity_main.xml 

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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"
    android:padding="16dp"
    tools:context=".MainActivity">

<!--  에디트텍스트, 버튼, 텍스트뷰 추가  -->

    <EditText
        android:id="@+id/editUrl"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:hint="주소를 입력하세요"
        android:layout_marginEnd="16dp"
        app:layout_constraintEnd_toStartOf="@+id/btnRequest"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <Button
        android:id="@+id/btnRequest"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:backgroundTint="@color/teal_700"
        android:text="요청"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <TextView
        android:id="@+id/textContent"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:text="textView"
        android:layout_marginTop="16dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/editUrl" />

</androidx.constraintlayout.widget.ConstraintLayout>

 

-결과

 

 

 


이 포스팅에 작성한 내용은 고돈호, ⌜이것이 안드로이드다⌟, 한빛미디어(주), 2022 에서 발췌하였습니다.