지난 포스팅에서는 Dependency Injection을 진행하고 GraphQL에서 사용되는 DAO 파일을 만들어 보았습니다.
확장자이름이 graphql 로 만들면 어떻게 DAO파일이 생성되는지 궁금해 하실수 있을텐데요. 빌드시 자동으로 graphql파일명과 관련된 클래스 파일이 생성됩니다.
프로젝트폴더에서 보시면 지정한 타입이 접미사로 붙고(query, mutation, subscription) 클래스파일이 만들어진것을
확인할 수 있습니다.
이제 repository를 세팅하겠습니다. 튜토리얼에서는 크게 3가지의 통신(Get-query, Post-mutation, WebSocket-subscription) 을 보여주는데 저는 아이템 리스트를 가져오는 메소드만 설명드리겠습니다. 우선 repository 생성합니다.
interface ApiRepository {
suspend fun getLaunchList() : Response<LaunchListQuery.Data>?
}
class DefaultRepository @Inject constructor(@ApplicationModule.ApiServerNetworkSource private val apolloClient : ApolloClient,
@ApplicationModule.ApiRealTimeServerNetworkSource private val apolloRealTimeClient: ApolloClient,
private val ioDispatcher: CoroutineDispatcher = Dispatchers.IO) : ApiRepository {
override suspend fun getLaunchList(): Response<LaunchListQuery.Data>? {
var result : Response<LaunchListQuery.Data> ?= null
withContext(ioDispatcher){
val response = apolloClient.query(LaunchListQuery()).toDeferred().await()
val launch = response.data?.launches
Log.d("LaunchList", launch.toString())
result = response
}
return result!!
}
}
이제 이 repository를 이용할 view model을 생성하겠습니다.
class MainViewModel @Inject constructor(
private val repository: DefaultRepository
) : ViewModel() {
private var _items :MutableLiveData<List<LaunchListQuery.Launch?>> = MutableLiveData(listOf())
val items : LiveData<List<LaunchListQuery.Launch?>> = _items
fun getItems(){
viewModelScope.launch {
val items = repository.getLaunchList()
_items.value = items?.data?.launches!!.launches
}
}
}
이제 메인에서 recyclerview를 이용하여 아이템 리스트를 보여주도록 하겠습니다. recyclerview adapter 는 listadapter를 사용했고 데이터바인딩을 이용해서 각각의 아이템을 뷰모델에 바인딩 시켜주었습니다.
package com.example.graphql_mvvm.main
import android.util.Log
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.ListAdapter
import androidx.recyclerview.widget.RecyclerView
import com.example.graphql_mvvm.databinding.MainItemBinding
import com.example.rocketreserver.LaunchListQuery
class MainAdapter(private val viewModel: MainViewModel,val itemClickListener: ItemClickListener)
: ListAdapter<LaunchListQuery.Launch, RecyclerView.ViewHolder>(LaunchDiffCallback()) {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
val binding = MainItemBinding.inflate(LayoutInflater.from(parent.context),parent,false)
return MainViewHolder(binding)
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int,payload:List<Any>) {
Log.d("TAG","onBindViewHolder")
val item = getItem(position)
when(holder){
is MainViewHolder ->{
holder.bind(viewModel,item)
holder.binding.idTextView.setOnClickListener {
itemClickListener.onClick(item.id)
}
}
}
}
class MainViewHolder (val binding : MainItemBinding): RecyclerView.ViewHolder(binding.root){
fun bind(viewModel: MainViewModel, item: LaunchListQuery.Launch){
binding.idTextView.text = item.id
binding.viewmodel = viewModel
binding.launch = item
binding.executePendingBindings()
}
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
}
}
class LaunchDiffCallback : DiffUtil.ItemCallback<LaunchListQuery.Launch>() {
override fun areItemsTheSame(oldItem: LaunchListQuery.Launch, newItem: LaunchListQuery.Launch): Boolean {
return oldItem.id == newItem.id
}
override fun areContentsTheSame(oldItem: LaunchListQuery.Launch, newItem: LaunchListQuery.Launch): Boolean {
return oldItem == newItem
}
}
아이템을 바인딩 시켜주기위한 바인더
object AdapterBinder {
@BindingAdapter("app:items")
@JvmStatic
fun setItems(view: RecyclerView, items: List<LaunchListQuery.Launch>?) {
(view.adapter as MainAdapter).submitList(items)
}
@BindingAdapter("app:image")
@JvmStatic
fun setImage(view: ImageView, url: String?) {
Glide.with(view.context).load(url).override(1000, 1000).into(view)
}
}
그리고 이제 메인을 작성해보겠습니다.
class MainActivity : DaggerAppCompatActivity() {
lateinit var binding : ActivityMainBinding
private var mAdapter: MainAdapter? = null
@Inject
lateinit var tokenIntercepter: TokenIntercepter
@Inject
lateinit var viewModelFactory: ViewModelProvider.Factory
private val viewModel by viewModels<MainViewModel> { viewModelFactory }
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater).apply {
viewmodel = viewModel
}
setContentView(binding.root)
binding.lifecycleOwner = this
val listener = object : ItemClickListener {
override fun onClick(id: String) {
}
}
mAdapter = MainAdapter(viewModel, listener)
tokenIntercepter.token = "Y2tkcmI3MDE3QGhhaWkuaW8="
binding.recyclerView.apply {
adapter = mAdapter
}
viewModel.getItems()
mAdapter!!.registerAdapterDataObserver(object : RecyclerView.AdapterDataObserver(){
override fun onItemRangeChanged(positionStart: Int, itemCount: Int) {
super.onItemRangeChanged(positionStart, itemCount)
(binding.recyclerView.layoutManager as LinearLayoutManager).scrollToPositionWithOffset(itemCount,0)
}
})
}
}
이제 간단하게 GraphQL을 이용해서 데이터를 가져오는 코드가 완성 되었습니다.
토큰인터셉터의 토큰은 위 프로젝트 진행할때 로그인 하는 부분이 있는데 이메일로 로그인을 하면 토큰을 발급해줍니다.
그 토큰을 인터셉터에 넣어주면 @Header 어노테이션을 이용할 필요가 없이 토큰을 넣을 수 있습니다.
토큰 뿐만이 아니라 다른 세팅값도 설정할 수 있는데 이전 포스팅의 토큰 인터셉터 코드를 참고해서 알아보시는 것도 좋을거 같습니다. 실행결과는 아래와 같습니다
깃허브 주소는 GRAPHQL_MVVM 프로젝트를 참고하시면 될거 같습니다.
https://github.com/ckdrb7017/BlogProject
'개발 > 안드로이드' 카테고리의 다른 글
안드로이드 구글STT에서 Recording이 안되는 이유 (9) | 2021.04.26 |
---|---|
Android MVVM Example 프로젝트 (0) | 2021.04.01 |
안드로이드 MVVM에 GraphQL 적용하기(1/2) (0) | 2020.07.19 |
Horizontal RecyclerView 자동으로 아이템 맞추기 (2) | 2020.07.04 |
안드로이드 액티비티 생명주기 (0) | 2020.04.22 |
댓글