본문 바로가기

프로그래밍/Android

[Android] Retrofit

https://square.github.io/

 

Square Open Source

As a company built on open source, here are some of the internally-developed libraries we have contributed back to the community. Tweets Join us Engineering Blog – corner.squareup.com Careers Page – squareup.com/careers

square.github.io

http://square.github.io/retrofit/

 

Retrofit

A type-safe HTTP client for Android and Java

square.github.io

 

기본적인 Retrofit 사용법( RxAndroid2 사용 )

rxjava를 사용하기 위해서는 CallAdapterFactory 에 RxJava2CallAdapter를 설정해야 rxjava 타입을 사용할 수 있다. 

 

인터페이스를 정의

interface SampleRestfulService{

   @Annotation

   fun apiFuntion1 () : Observable<Model>

 

   @Annotation

   fun apiFuntion2 () : Single<Model>

 

   @Annotation

   fun apiFuntion3 () : Flowable<Modle>

}

 

Flowable은 RxJava2(RxAndroid2) 에서 대기열 버퍼에 대해 흐름제어 기능이 추가된 객체이다. 

리액티브 프로그래밍에서 push로 무한정 밀어넣을 수 없는 상황이 발생하는데, 이경우 backpressure가 발생한다고 한다. 이 backpressure를 핸들링 하기 위해 필요한게 Flowable 이라고 생각하면 된다.

일반적인 rest api 정도에서야 Observable이면 충분한데, 대량의 api 호출과 각 처리간에 일정 시간이 필요한 경우 Flowable을 사용을 고려한다.

 

 

Retrofit은 GET,POST 를 위한 어노테이션들을 제공한다.

 

GET

REQUEST, URL 변환 처리

   ex) users/user/repos?sort=sorting

 

   주소치환 : 입력받을 변수앞에 @Path("파라미터명") 를 사용하면 해당 파라미터를 변수값으로 치환하게된다.

   @GET("users/{user}/repos")

   fun getTestFunction( @Path("user") user:String ) : Observable<ResponseModel>

 

 

   쿼리문 치환 : @Query("name") 을 사용 : 

   @GET("users/{user}/repos")

   fun getTestFunction( @Path("user") user:String, @Query("sort") sort:String ) : Observable<ResponseModel>

 

   여러개의 퀴리의 경우 @QueryMap options:Map<String, String> 을 사용해 한번에 지정가능하다.

 

   url을 입력받는 경우

   @GET

   fun getTestFunction( @Url user:String  ) : Observable<ResponseModel>

 

POST

REQUEST BODY

   @POST("users/new")

   fun createUser( @Body user : UserModel )

 

FORM ENCODED

   @FormUrlEncoded

   @Post("user/edit")

   fun updateUser( @Field("filed_name") first:String ) : Observable<ResponseModel>

 

   @FieldMap

 

헤더

   @Headers({

        "Accept: application",

        "User-Agent: "

   })

 

 

 


build.gradle 설정

 

retrofit

implementation 'com.squareup.retrofit2:retrofit:2.4.0'

implementation 'com.squareup.retrofit2::converter-gson:2.4.0'

implementation 'com.squareup.retrofit2:adapter-rxjava:2.4.0'

 

ok http

implementation 'com.squareup.okhttp3:okhttp:3.10.0'

implementation 'com.squareup.okhttp3:logging-interceptor:3.10.0'

 

 

rx android

implementation 'io.reactivex.rxjava2:rxandroid:2.0.2'

implementation 'io.reactivex.rxjava2:rxjava:2.1.14'

 

 

api 인터페이스

 

interface SampleApi{

   @FormUrlEncoded

   @POST("/post_url")

   fun postTestFunction( @Field("field_name") filed : String ) : Observable<MyModel>

 

}

 

모델 정의

json 형태에 맞게 모델구성

ex) { "result": 0 , "value": 200, "desc":"GOOD", "data" : { "value1": true, "value2": 0 } }

json 키값과 변수명을 맞춰준다.

class MyModel{

   val result:Integer = 0

   val value:Integer = 200

   desc:String = ""

   val data:MyModelItem = MyModelItem()

}

 

아래처럼 변수명을 별도로 지정하려면 @SerializedName 사용

class MyModelItem( @SerializedName("value1") val myValue1 : Boolean,

                           @SerializedName("value2") val myValue2 : Integer)

 

 

배열의 경우 List 로 정의한다.

ex) { "result": 0 , "value": 200, "desc":"GOOD", "data" : [ { "value1": true, "value2": 0 },  { "value1": true, "value2": 0 }] }

class MyModel( val result:Integer, val value:Integer, desc:String, val data:List<MyModelItem>)

 

 

 

Retrofit adapter

// http클라이언트는 ok http를 사용하므로 해당 객체 생성

fun createOkHttpClient : OkHttpClient {

   val interceptor = HttpLoggingInteceptor()

   if( BuildConfig.DEBUG ) {

      interceptor.level = HttpLoggingInterceptor.Level.Body

   } else {

      interceptor.level = HttpLoggingInterceptor.Level.NONE

   }

   

   // ok http client 생성

   return OkHttpClient.Builder()

                .addNetworkInterceptor(interceptor)

                .sslSocketFactory( createSslSocketFactory( 

                .build()

}

 

 

fun createRetrofitApi : SampleApi

{

   // retrofit 객체 생성

   // rxjava2를 위한 call adapter factory와 json 변환을 위한 converter factory를 설정

   Retrofit retrofit =

      Retrofit.Builder()

         .baseUrl( "http://api.sample.com/")

         .client( createOkHttpClient() )

         .addConverterFactory( GsonConverterFactory.create())

         .addCallAdapterFactory( RxJava2CallAdapterFactory.create() )

         .build()

 

   // api 서비스 생성

   SampleApi api = retrofit.create(SampleApi::class.java)

   return api

}

 

 

 

MainActivity

 

 

lateinit var disposable: CompositeDisposable

lateinit var retrofitAdapter : RetrofitAdapter

 

override fun onCreate( savedInstanceState: Bundle?) {

   super.onCreate( savedInstanceState )

   setContentView( R.layout.activity_main )

 

   // CompositeDisposable 객체에 Observable 객체들을 넣게 된다.

   // 취소시 각각의 Observable을 처리하는게 아니라 CompositeDisposable을 정리하면 모든 처리가 취소된다.

   disposable = CompositeDisposable()

 

 

   retrofitAdapter = RetrofitAdapter()

 

   SampleApi api = retrofitAdapter.createRetrofitApi()

 

   disposable.add( 

       api.postTestFunction("test")

       // result 를 판단해 필요한 데이터만 전달

       // verify 관련 처리가 필요없는 경우 그냥 subscribe 에서 처리해도 됨.

       .flatMap {

          if( it.result == 0 ) {

             Observable.just( it.data )

          } else {

             Observable.error( IllegalStateException("error") )

          }

       }

       .observeOn( AndroidSchedulers.mainThread())

       .subscribeOn( Schedulers.newThread())

       .subscribe(

          { response: MyModelItem ->

             // 응답처리

          }, { error: Throwable ->

             // exception

          }

      ))

}

 

override fun onDestroy() {

   // 제거

   disposable.clear()

 

   super.onDestroy()

}