항상 이론만 공부하다보니 내가 아는게 맞나? 싶은 생각만 들었다.

사실 외부 동아리때문에 프로젝트를 MVVM으로 진행하다보니 DataBinding과 LiveData와 MVVM패턴에는 조금 익숙해져 있었지만, 아직 서버를 연동하지 못 했고 유동적인 Data가 없다보니 Retrofit과 RxJava를 예제만 봐왔었고 직접 코딩해보지 않았다.

 

곧 서버 API를 붙힌다고하니 연습을 해보려 해본 예제이다.

 

API는 Github에 있는 API를 사용하여 팔로워를 가져오는 API를 사용했다.

이때 나의 팔로워는 1명이기에... 그냥 그렇다...

 

어쨋든 내가 생성한 Model 이다

 

class User(
    val login: String,
    val id: Long,
    val node_id: String,
    val avatar_url: String,
    val gravatar_id: String,
    val url: String,
    val html_url: String,
    val followers_url: String,
    val following_url: String,
    val gists_url: String,
    val starred_url: String,
    val subscriptions_url: String,
    val organizations_url: String,
    val repos_url: String,
    val events_url: String,
    val received_events_url: String,
    val type: String,
    val site_admin: Boolean
)
{
    override fun toString(): String {
        return id.toString()+node_id+url+html_url
    }
}

굉장히 많은 API 반환값이 있지만 .... 나는 간단히 돌아가는 것만 확인하고 후에 진행할 것이기 때문에 쉽게 짯다...

 


다음은 Repository로

API를 사용하는 함수를 모아놓은 class(라고 하는게 맞나??)이다.

class GithubRepository {

    private val api = ApiManager.githubApi

    /*fun getMyRepos(): Single<List<MyRepos>> =
        api.getMyRepos()

    fun getMyProfile(): Single<MyInfo> =
        api.getMyProfile()

    fun getGithubRepos(): Single<List<GithubRepo>> =
        api.getRepos()
*/
    fun getUser(): Maybe<User> =
        api.getUser()

    fun getFollowers() : Observable<List<User>> = api.getFollowers("wlgusdn")

    fun updateUser(): Completable =
        api.updatteUser()

/*
    fun searchGithubRepos(q: String): Single<List<GithubRepo>> =
        api.searchRepos(q)
            .map {
                it.asJsonObject.getAsJsonArray("items")
                    .map{
                        ApiManager.gson.fromJson(it, GithubRepo::class.java)!!
                    }
            }//map으로 필터역할을 해서 반환
            .subscribeOn(Schedulers.io())
*/
}

주석 처리된 함수들은 사용하지 않는 함수들이다.

Maybe , Single Observable Flowable 등의 많은 객체가 존재하지만 각각의 용도와 장단점은 천천히 공부해봐야겠다.

글을 쓰는 다음날 공부해봐야지...(사족으로 알고리즘과 안드로이드 두개만해도 하루가 끝나는데 자격증은 언제따지...)

 


ApiManager라고 불리는 Object를 생성한다.

이 객체에서는 App과 Network를 통신하게 하는 okHttp와 API를 사용할 수 있게 하는 Retrofit을 생성한다.

okhttp가 retrofit에 맞춰져있기에 사용한다고 알고 있으며, 이전에 사용하던 httpresponseurl 인가??? 긴 객체를 사용하여 Network와 통신하는 것은 잘 안쓰게 될것 같다... 왜냐면 Runnable생성하고 그 안에서 파라미터 넘겨주고 파라미터 받고.. 너무 귀찮고 또한 Retrofit의 장점인 Json으로 파싱까지 해주기 떄문에 결론은 Retrofit짱!!

 

또한 Interceptor은 2개를 생성가능한데...

쉽게 말하면

App->Network로 갈 때의 Intercept 동작을 하는 Interceptor

Network->App로 갈 때의 Intercept 동작을 하는 Interceptor 두개가 존재한다고 한다

나는 App->Network로 갈 때의 Intercept 동작을 하는 Interceptor만 생성했고 이건 Log를 보기 위함이다.

 

object ApiManager
{
    val gson =
        GsonBuilder()
            .setLenient()
            .create()

    private val okHttpClientBuilder =
        OkHttpClient.Builder()
            .addInterceptor(provideLoggingInterceptor())//App Intercept
            .build()

    private val githubAdapter by lazy {
        Retrofit.Builder()
            .baseUrl("https://api.github.com/")//기본적으로 통신할 API주소
            .client(okHttpClientBuilder)//통신을 할 주체?(Ok HTTP)
            .addConverterFactory(GsonConverterFactory.create(gson))//받은 응답을 Observable로 반환가능
            .addCallAdapterFactory(RxJava2CallAdapterFactory.create())//Json 형식으로 Data를 보내고 이를 파싱가능
            .build()
    }

    val githubApi: GithubApi by lazy {
        githubAdapter.create(
            GithubApi::class.java)
    }

    private fun provideLoggingInterceptor(): HttpLoggingInterceptor {
        val interceptor = HttpLoggingInterceptor()
        interceptor.level = HttpLoggingInterceptor.Level.BODY

        return interceptor
    }
}

메인 요리? 라고 볼 수 있는 Retrofit으로 API 통신하는 함수를 선언하는 인터페이스이다.

 

   @GET("user/starred/{owner}/{repo}")
    fun checkStar(
        @Path("owner") owner: String,
        @Path("repo") repo: String
    ): Completable

    @GET("users/{username}/followers")
    fun getFollowers(@Path("username") username: String):Observable<List<User>>
    

보이는 그대로이다 

여느 REST API처럼 GET PUT POST DELETE가 가능하며

@Path를 통해 파라미터로 쉽게 보낼수 있다.

 


이 뒤로는 내가 알고 있던 MVVM패턴이다.

 

MVVM에 대한 것들은 내 이전 포스팅에 많이 적혀있으니 정리하면 되겠다.

 

중요한 것으로는 ViewModel 코드인데

예전처럼 LiveData만을 사용하여 하지 않고

Retrofit을 사용하여 반환된 Observable객체(Observable,Single,Flowable...)들로 반환하여 쓰레드를 결정하고

subscribe()를 통해 수행할 UI작업을 결정한다.

이때 DataBinding으로 따로 UI적인 부분을 만지지않는 것이 Point~

 

 

class MainViewModel : ViewModel()
{

    val repository = GithubRepository()
    val disposable = CompositeDisposable()
    var text = MutableLiveData<List<User>>()

    fun getUserRepo(): Maybe<User> =
        repository.getUser()
            .subscribeOn(Schedulers.io())   //이전 stream에 대한 스레드 지정
            .observeOn(AndroidSchedulers.mainThread())  //아래에 대한 스레드 지정

    fun getFollowers() : Observable<List<User>> =
        repository.getFollowers()
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())


    fun getf()
    {
        disposable.add(getFollowers().subscribe({ t: List<User>? ->
            text.value=t
        }))
    }


}

(+ 내가 하고싶었던 코드는 원래 아래의 코드이다)

fun getFollowers() : Observable<List<User>> =
        repository.getFollowers()
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe{ t ->
            //LiveData 값 = t 
            }

아래의 코드를 하고 싶었는데 이상하게 계속해서 t가 disposable로 나왔다....

그래서 내일 공부할 것이다~

 

MVVM에 이어 Retrofit과 RxJava까지 조금씩 이해가 되고있다..

iOS는 언제 공부하지...

 

 

+ Recent posts