티스토리 뷰

336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.

이번 구글 I/O 에서 안드로이드 개발자인 나에게 가장 인상적이었던 것은 Android Architecture Components 였다 (앞으로 약칭 AAC)

RxJava의 컨셉을 이용한 LiveData와 MVVM 패턴의 성공적인 안드로이드 적용을 위한 ViewModel 그리고 모바일 개발에서 항상 골치를 썩이는 생명주기를 관리하는 Lifecycle Component 를 발표할때 여러 곳에서 활용 가능할것이라고 생각해서 가슴이 두근댔다.

없던 개념을 만들어 낸것은 아니지만 안드로이드 프레임워크 내에서 개발하기에 적합한 라이브러리를 내어준 것에 감탄한다.

하지만 게으름으로 인해서 계속 방치해두다가 이번에야 말로 뭔가 만들어보자는 생각으로 Realm의 DAO를 대체할 유틸을 AAC를 통해 개발해보았다.


1.  그래들에 추가


allprojects
{
    repositories
{
        jcenter
()
       
maven { url 'https://maven.google.com' }
   
}
}

일단은 그래들에 AAC 관련 라이브러리들을 임포팅해야한다.  레포지토리에 메이븐을 추가하고.

  • compile "android.arch.lifecycle:runtime:1.0.0-alpha5"
  • compile "android.arch.lifecycle:extensions:1.0.0-alpha5"
  • annotationProcessor "android.arch.lifecycle:compiler:1.0.0-alpha5"
 LifecyclesLiveData,, ViewModel, 를 사용하기 위해 디펜던시에 위 사항들을 등록해준다.


2. 지금 Realm을 사용하는 구조.

현재 프로젝트 내에서 Realm은 아래와 같은 구조로 사용되고 있다.

RealmDAO - 램 DB 와의 IO 를 위한 클래스

RealmObject - 렘의 DB 테이블 같은 역할 및 렘DB의 result 를 저장할 클래스

PojoModel - api 로부터의 결과물을 담을 클래스


여기서 DAO 클래스 내부에는 find , save , delete 등의 메소드가 존재하며 각 메소드는 static으로 제공되어 호출될때 인스턴스를 생성하고 종료한다


3. 바꾸려는 Realm의 구조.

Realm Instance를 액티비티의 라이프 사이클에 따라 생성 / 소멸 하도록 하고 , Realm 의 데이터 변화를 감지하여 갱신할 수 있도록 한다.


4. 이를 위해 필요한 것

RealmViewModel - Realm 객체를 들고 있으며 Activity 의 LifeCycle를 인지
RealmLiveData - Realm 변화를 인지하고 Callback을 발생시킴

5. 코딩을 해보자 . 

목표로 하는 기능은 Push 알림이 모여 있는 알림센터 화면을 보고 있을때 Push가 도착하면 실시간으로 화면이 변경되도록 하는 것입니다.

* LiveReamData - LiveData 를 통해 생명주기에 따른 처리가 가능하도록 수정

class LiveRealmData<T : RealmModel>(private val results: RealmResults<T>?) : LiveData<RealmResults<T>>() {

private val listener = RealmChangeListener<RealmResults<T>> { results -> value = results }


override fun onActive() {
results?.addChangeListener(listener)
}


override fun onInactive() {
results?.removeChangeListener(listener)
}
}




* NotiItemViewModel - ViewModel 에 LiveReamData를 추가하여 리액티브한 처리가 가능하도록 처리하고,  생명주기가 끝나는 시점에 realm instance를 종료시키도록 처리함


class
NotiItemViewModel : ViewModel() {



var realmInstance: Realm = Realm.getDefaultInstance()

lateinit private var notiItemResult: LiveData<ArrayList<NotiItem>>



init {

subscribeToNotiItemAptList()

}



override fun onCleared() {

realmInstance.close()

super.onCleared()

}



fun getNotiItemResult(): LiveData<ArrayList<NotiItem>> {

return notiItemResult

}



private fun subscribeToNotiItemAptList() {

val loans = LiveRealmData(NotiItemDAO(realmInstance).findAllByTypeToRealmResults("apt"))

notiItemResult = Transformations.map(loans) { objects ->

objects.mapNotNullTo(ArrayList<NotiItem>()) {

populateNotiItem(it)

}
}

}



private fun populateNotiItem(obj: RONotiItem?): NotiItem? {

if (obj == null) {

return null

}

return NotiItem(obj)
}

}


* NoticenterFragment - ViewModelProvier를 통해 NotiItemViewModel을 가져오고 이를 통해 realm data를 observe 할수있도록 개발


class NoticenterAPTFragment : Fragment() {


lateinit var notiItemViewmodel: NotiItemViewModel


override fun onCreateView(inflater: LayoutInflater?, container: ViewGroup?,

savedInstanceState: Bundle?): View? {

// Inflate the layout for this fragment

with(inflater!!.inflate(R.layout.fragment_noticenter_apt, container, false)) {

empty_view.visibility = View.INVISIBLE

notiItemViewmodel = ViewModelProviders.of(activity as BaseActivity).get(NotiItemViewModel::class.java)

notiItemViewmodel.getNotiItemResult().observe(activity as BaseActivity, Observer<ArrayList<NotiItem>> {

Logger.d("notiEvent", "notiItemViewmodel onChanged " + it.toString())

items = it

adapter?.let {

adapter?.setItems(items)

adapter?.notifyDataSetChanged()

}

})

adapter = NoticenterAPTAdapter(this@with)

adapter?.setItems(NotiItemDAO(notiItemViewmodel.realmInstance).findAllByType("apt"))

noticenter_apt_list.layoutManager = LinearLayoutManager(activity)

noticenter_apt_list.adapter = adapter

return this@with
}
}


inner class NoticenterAPTAdapter(internal var view: View) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {

private val items = ArrayList<NotiItem>()


override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
Logger.d(TAG, String.format("onCreateViewHolder: viewType=%d", viewType))

return ItemViewHolder(parent)
}


override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
Logger.d(TAG, String.format("onBindViewHolder: holder=%s, position=%d", holder, position))

val item = items[position]

(holder as? ItemViewHolder)?.bind(item)

}


override fun getItemCount(): Int {
return items.size
}


fun setItems(items: ArrayList<NotiItem>?) {
this.items.clear()

if (items == null || items.size <= 0)
view.empty_view!!.visibility = View.VISIBLE
else
this.items.addAll(items)
}
}

companion object {
private val TAG = NoticenterAPTFragment::class.java.simpleName

fun newInstance(): NoticenterAPTFragment {

return NoticenterAPTFragment()

}
}
}

그 외 활용에 대한 문의는 댓글로 남겨주시면 대응하겠습니다.


감사합니다.



공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
«   2024/05   »
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
글 보관함