일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- 비동기
- 플레이 콘솔 프로덕션
- Bottom sheet
- 플레이스토어 앱 게시 문제
- Dialog
- urlconnection
- 안드로이드 http
- Callback
- 공유 기능
- android api
- Retrofit
- 안드로이드스튜디오
- 달력 만들기
- android studio
- 안드로이드 api
- 안드로이드 스튜디오
- 앱개발
- 앱 출시
- Kotlin
- 레트로핏
- Exposed Drop-Down Menu
- Today
- Total
Strong 감자의 공부
Http로 데이터 통신 01- Http(s)URLConnection클래스 본문
Http로 데이터 통신 01- Http(s)URLConnection클래스
ugyeong 2023. 7. 7. 16:07
Http로 통신하는 방법에는 아래 두가지 방식이 있습니다.
1. Http(s)URLConnection클래스를 이용
2. retrofit라이브러리를 이용
오늘은 Http(s)URLConnection클래스를 이용해서 http 통신을 해보겠습니당!
결과물
먼저 manifest파일에서 인터넷 권한을 허용해줍니다.
<uses-permission android:name="android.permission.INTERNET" />
주소가 https 일경우 그대로 진행해도 되지만 최근 안드로이드 최신버전으로 업데이트 되면서 https통신이 아닌 통신작업은 기본적으로 차단되어있습니다.
W/System.err: java.io.IOException: Cleartext HTTP traffic to www.me.go.kr not permitted
manifest파일에 아래 코드를 추가해 줘야합니다.
<application android:usesCleartextTraffic="true">
- xml 코드
<?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"
xmlns:app="http://schemas.android.com/apk/res-auto"
tools:context=".framgnet.GoHttpUrlConnectionFragment"
android:orientation="vertical">
<TextView
android:id="@+id/title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="HttpUrlConnection"
android:gravity="center"/>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1">
<EditText
android:id="@+id/editUrl"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_marginStart="5dp"
android:layout_marginTop="5dp"
android:layout_marginEnd="5dp"
android:layout_marginBottom="5dp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toLeftOf="@+id/requestButton"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintHorizontal_weight="3.5"
android:hint="주소 입력하시오"
/>
<Button
android:id="@+id/requestButton"
android:layout_width="0dp"
android:layout_height="match_parent"
android:text="요청"
android:layout_marginLeft="5dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintLeft_toRightOf="@+id/editUrl"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintBaseline_toBaselineOf="@+id/editUrl"
app:layout_constraintHorizontal_weight="1"
/>
</androidx.constraintlayout.widget.ConstraintLayout>
<TextView
android:id="@+id/textContent"
android:layout_width="match_parent"
android:layout_height="0dp"
android:text="textview"
android:layout_weight="9"/>
</LinearLayout>
- Class.kt
package kr.co.gamja.NetworkFragment.framgnet
import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kr.co.gamja.NetworkFragment.databinding.FragmentGoHttpUrlConnectionBinding
import java.io.BufferedReader
import java.io.InputStreamReader
import java.net.HttpURLConnection
import java.net.URL
class GoHttpUrlConnectionFragment : Fragment() {
private var _binding: FragmentGoHttpUrlConnectionBinding? =null
private val binding get() =_binding!!
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
_binding= FragmentGoHttpUrlConnectionBinding.inflate(inflater, container,false)
val view = binding.root // view를 리턴해야해서 binding.root 리턴
return view
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { // 리사이클러뷰랑 binding을 여기서
super.onViewCreated(view, savedInstanceState)
binding.requestButton.setOnClickListener {
CoroutineScope(Dispatchers.IO).launch {
try {
var urlText = binding.editUrl.text.toString()
// 주소의 시작이 https인지 확인
// if (!urlText.startsWith("https")){
// urlText = "https://${urlText}"}
// 주소 URL객체로 변환 .net 으로 import
var url = URL(urlText)
/* openConnection 메서드로 서버와의 연결 생성
반환: URL에서 참조하는 원격 개체(url)에 대한 연결인 추상 클래스인 URLConnection 인스턴스
그래서 실제 구현 클래스인 HttpURLConnection으로 타입 캐스팅
public abstract class URLConnection*/
val urlConnection = url.openConnection() as HttpURLConnection
// 연결된 커넥션에 요청방식 설정
urlConnection.requestMethod = "GET"
// 응답 확인
if (urlConnection.responseCode == HttpURLConnection.HTTP_OK) {
// inputStream : 읽기 전용 스트림
val streamReader = InputStreamReader(urlConnection.inputStream)
val buffered = BufferedReader(streamReader)
val content = StringBuilder()
// 읽기
while (true) {
val line = buffered.readLine() ?: break
content.append(line)
}
buffered.close()
urlConnection.disconnect()
// UI업뎃은 메인 스레드에서만 할 수 있음
launch(Dispatchers.Main) {
binding.textContent.text = content.toString()
}
}
} catch (e: Exception) {
e.printStackTrace() // 예외 발생시 로그 출력함
}
}
}
}
override fun onDestroyView() {
super.onDestroyView()
_binding=null
}
}
- 글로벌 스코프와 코루틴 스코프
- 글로벌 스코프 : 앱의 생명주기와 함께 동작하는 것이고, 그렇기 때문에 앱의 시작부터 끝까지 실행돼야 하는것일 때 씁니다.
GlobalScope는 코루틴을 관리하지 않기 때문에 메모리 누수 및 불필요한 리소스 낭비를 초래할 수 있습니다.
언제 사용해야 하나요?
- 거의 사용하지 않는 것이 좋습니다.
- 앱 전체에서 실행되어야 하는 작업(예: 로그 전송, 통계 처리 등)에서만 제한적으로 사용합니다.
- 더 좋은 대안인 CoroutineScope 또는 WorkManager를 사용하는 것이 일반적입니다.
- 코루틴 스코프 : 특정한 때에만 실행할때 씁니다.
- 코루틴이 특정 생명주기에 맞춰 관리될 수 있도록 도와주는 스코프.
- 주로 UI 컴포넌트(예: Activity, Fragment) 또는 특정 작업(예: 네트워크 요청, 데이터 처리 등)과 연계하여 사용됩니다.
- 스코프를 정의하면 해당 스코프에서 실행된 모든 코루틴을 한 번에 취소하거나 관리할 수 있습니다.
- 코루틴이 더 이상 필요하지 않을 때 명시적으로 취소할 수 있어 메모리 누수를 방지합니다.
- 코루틴 디스패처
코루틴이 실행될 스레드를 정하는 디스패처를 정하는 것입니다.
여기서 사용하는 것은 Dispatchers.IO인데 이는이미지 다운로드, 파일 입출력에 최적화돼 있습니다.
네트워크 작업은 반드시 메인스레드가 아닌 서브스레드에서 진행을 해야합니다.
만약 메인스레드에서 http인스턴스를 생성하고 네트워킹을 시도할 경우 NetworkOnMainThreadException 예외가 발생합니다.
- 메인스레드는 UI와 관련된 작업(화면 업데이트, 사용자 입력 처리 등)을 수행합니다.
- 메인스레드는 한 번에 하나의 작업만 처리할 수 있으며, 이 작업이 오래 걸리면 사용자 경험이 크게 저하됩니다.
- 예를 들어, 네트워크 작업(HTTP 요청 등)은 응답이 느릴 수 있으며, 이 작업이 완료될 때까지 메인스레드가 차단(block)되면 애플리케이션이 "멈춘 것처럼" 보입니다.
- 안드로이드 3.0 (API 레벨 11)부터는 네트워크 작업을 메인스레드에서 수행하지 못하도록 강제하고 있습니다.
- 네트워크 작업은 불확실한 지연(네트워크 응답 시간, 서버 상태 등)이 발생할 수 있기 때문에, 이를 메인스레드에서 실행하면 앱이 응답 없음(ANR: Application Not Responding) 상태로 빠질 가능성이 높아집니다.
- 이를 방지하기 위해 안드로이드 프레임워크는 NetworkOnMainThreadException(런타임에러)을 던져 개발자가 서브스레드에서 네트워크 작업을 수행하도록 강제합니다.
혹시 요청을 눌러도 로드가 되지 않는다면 와이파이사용 중이면 재연결을 해보고 핫스팟이라면 핫스팟 말고 다른것을 이용하면 해결됩니당.
책) 이것이 안드로이드다