안드로이드

[Kotlin/Android] Internet Connect (1) Dependency, Retrofit ,Scalars, Moshi, Permission

란서 2022. 1. 16. 01:04

Web service 와 JSON

 

우리는 web server 에 저장된 데이터를 어플리케이션으로 가져오고 싶을 때가 있다.

web server에 접근하기 하여 데이터를 받아오는 행위 =  "web service".

 

따라서 web의 component와 프로토콜을 사용하는 REST 아키텍쳐를 이용하여 Web service를 요청해보도록 하자.

 

보통 web service를 요청하는 방식은 URIs를 경유하는 기본적인 방식이 있다. ( URIs 내에 URL 방식이 있는듯?)

 

이렇게 web serivce를 요청하면 일반적으로 web은 JSON을 사용하여 포맷한 데이터를 넘겨준다. 

 

*JSON이란?  구조화된 데이터를 표현하기 위한 교환 형식으로 보통 dictionary, hash map, associatiate array 등으로 불려지는 Key-Value Pair 타입의 Collection을 말한다.

 

web service를 요청하면 "JSON Array"를 응답으로 받는다.

 

 

Dependency & Support Language

web service를 요청하기 위해서 retrofit 라이브러리를 사용한다. retrofit 라이브러를 사용하기 위한 dependency는 다음과 같다.

    //Retrofit라이브러리와 컨버터, version_retrofit 2.9.0
    implementation "com.squareup.retrofit2:retrofit:$version_retrofit"
    implementation "com.squareup.retrofit2:converter-scalars:$version_retrofit"
    implementation "com.squareup.retrofit2:converter-moshi:$version_retrofit"
    
    //Moshi 라이브러리  version_moshi = "1.8.0"
    implementation "com.squareup.moshi:moshi-kotlin:$version_moshi"

retrofit은 converter를 필요로 한다.  scalars 컨버터와 moshi컨버터 현재까지 두 종류의 컨버터를 배웠고 더 있을수도 있다. 

scalars컨버터는 약간 JSON을 단순 string만으로 전환하는 컨버터 같고

moshi컨버터는 JSON을 사용자가 지정한 data class구조 (key = 식별자, value = 값) 로 전환할 수 있는 컨버터 .

(moshi 컨버터를 사용하기 위해서는 moshi 라이브러리 추가.)

 

둘 중 하나만 써도 된다. 

 


retrofit 사용하는 타사 라이브러리는 보통 Java 8을 사용한다.  (사실 이해를 잘못했다)

따라서 다음과 같이 Java 8 언어에 대한 support를 추가해줘야 한다.

 

    compileOptions{
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8

    }

    kotlinOptions {
        jvmTarget = JavaVersion.VERSION_1_8.toString()
    }

 

 

Retrofit 라이브러리를 이용하여 Web service와 연결하기.

 

Retrofit이란? App에서 Web Serivce를 요청하고 Web 컨텐츠를 받을 수 있도록 (응답) 네트워크 API를 생성하는 라이브러리이다. 

 

네트워크 API는 web server로 부터 data를 Web Service를 통해 가져오고 (Fetch)

실제 App에서 해당 데이터를 사용할 수 있도록 Object형태로 전환할 수 있다. (Decode)

 

또한 궁극적으로 Background Thread 에서 web service 요청과 응답 활동을 수행할 수 있도록 하는 것과 같은 많은 세부사항을 구현할 수 있는 네트워크 계층을 생산한다.


  • package, network 를 만들고 MarsApiService파일과 MarsProperty를 만든다.

 

패키지 network

MarsApiService.kt 파일은 App의 네트워크 계층을 보유. 즉, Retrofit라이브러리 및 Converter를 사용하여 Web Service를 요청할 수 있는 클래스 및 인터페이스를 구현한다.


  • Retrofit 라이브러리를 이용하여 Network API 만들기.

 

Retrofit이 Network API를 만들기 위해서는 2가지 재료가 필요하다. 1.converter와 2.baseUrl

  1. ConverterFactory
    Web Service 요청으로 부터 받아오는 JSON응답을 App에서 사용할 수 있는 형태(타입)으로 전환하는 컨버터가 필요합니다. 예를 들어 scalarsConverterFactory 또는 moshiConverterFactory 가 있다.


  2. baseUrl 
    Web Service를 요청하는 가장 기본적인 방식은 Url을 사용한다. 따라서 Url을 이용하는 경우 접속할 인터넷 서버의 Url이 필요하다. Url String을 상수로 만든다.

    0) Retrofit.Builder() 를 호출.
    1) addConverterFactory() 를 호출. -> 인자로 ConverterFactory를 받는다.
    2) baseUrl(BASE_URL) 을 호출. -> 인자로 URL을 담고있는 문자열을 받는다.

    private val retrofit = Retrofit.Builder()
            .addConverterFactory(ScalarsConverterFactory.create())
            .baseUrl(BASE_URL)
        .build()​
    ScalarsConverter는 JSON 응답을 String을 포함한 원시타입으로 전환하는 컨버터.


    또는 
     MoshiConverter는 JSON 응답을 사용자가 지정한 Kotlin Data Object class 타입으로 전환하는 컨버터

    private val moshi = Moshi.Builder()
        .add(KotlinJsonAdapterFactory())
        .build()
    
    private val retrofit = Retrofit.Builder()
            .addConverterFactory(MoshiConverterFactory.create(moshi)) 
            .baseUrl(BASE_URL)
        .build()​

 


  • retrofit (=Network API) 을 만든 뒤, 이제 해당 API와 웹 서버통신하는 방법을 구현하는 "인터페이스"를 정의한다. 

우리는 Web Server에 저장된 데이터를 요청하고 응답받은 JSON을 APP에서 사용할 수 있는 타입으로 받고자 한다. 

이외에도 우리는 Web Server에 데이터를 보낼 수도 있고, 또 Web Server에 존재하는 모든 데이터가 아닌 특정한 데이터만을 받길 원할수도 있다.

따라서 인터페이스 내에 "요청 메소드"를 구현한다.
(Room DAO가 Room Database에 유사하게 쿼리를 날리는 것처럼) 

interface MarsApiService {
    @GET("realestate")
    fun getProperties(): Call<String>
}


MarsApiService 인터페이스 내에

@GET() 이라는 어노테이션을 통해 해당 요청 메서드의 기능을 구체화할 수 있다.
@GET 은 간단하게 말하자면 주어진 URI에 들어가서 데이터를 조회하는 요청 메소드이며, 인자로 주어진 문자열을 주소 맨 뒤에 붙여서 해당 web server로 찾아들어간다. 

예를 들어 "https://android-kotlin-fun-mars-server.appspot.com/" 이 BASE URL로 설정이 되어있고,

@GET("realestate") 어노테이션을 통해 요청메소드를 구현한다면

https://android-kotlin-fun-mars-server.appspot.com/realestate -> 로 찾아 들어 간다는 뜻.

 

또한 getProperites() 메서드는 Call<> Object를 반환하는데, Call 타입은 Web Service에 요청을 시작하기 위해 사용.

네트워크 API (val retrofit)에 "요청 메소드"가 구현된 인터페이스를 넘겨준다면 "Web Service 요청이 가능한 네트워크 API" 완성.

 

(이게 맞는말인지 좀 더 공부해야 할듯)


  •  네트워크API 싱글톤 + lazy 초기화

Web Service 요청이 가능한 네트워크 API 를 만들 때 싱글톤으로 정의하여 메모리에 정적 멤버로 남기고 하나의 retrofit 객체만 사용되도록 만든다. (Database 처럼) 또한 API 변수는 리소스를 많이 소비하기 때문에 lazy 초기화를 이용하여 변수가 사용되는 시점에서 초기화 될 수 있도록 하자.

 

object MarsApi{
    val retrofitService : MarsApiService by lazy{
        retrofit.create(MarsApiService::class.java)
    }
}



이로써 Retrofit 라이브러리를 이용하여 기능이 구현된 네트워크 API를 만드는 최종 코드는 다음과 같다.

 


private const val BASE_URL = "https://android-kotlin-fun-mars-server.appspot.com/"

private val retrofit = Retrofit.Builder()
        .addConverterFactory(ScalarsConverterFactory.create())
        .baseUrl(BASE_URL)
    .build()
    
interface MarsApiService {
    @GET("realestate")
    fun getProperties(): Call<String>

}

object MarsApi{
    val retrofitService : MarsApiService by lazy{
        retrofit.create(MarsApiService::class.java)
    }
}

 

 

Internet Permission 설정

 

인터넷에 연결하면 항상 보안문제가 발생한다. 따라서 기본적으로 앱은 보안 설정을 해주지 않으면 인터넷에 연결되지 않는다. 명시적으로 안드로이드 앱에 인터넷과의 접근이 허용된다는 코드를 구현해야 하낟.

 

In AndroidManifrests.xml

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.android.marsrealestate">

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

    <application
        ...>