[출처 - RxJava 프로그래밍 : 리액티브 프로그래밍 기초부터 안드로이드 까지 한번에]
본 글은 'RxJava 프로그래밍 : 리액티브 프로그래밍 기초부터 안드로이드 까지 한번에' 를 학습하면서 정리한 글입니다.
ReativeX를 이용하여 Android의 RecyclerView를 만들어 보겠습니다.
RecyclerView는 간단하게 설명해서 ListView의 각 item들이 생성되고 삭제되는 비효율적인 문제를 해결하기 위해 나온 View로 쓰지 않는 View를 재 활용하는 View 입니다. (자세한 내용은 여기서 확인해 보시면 좋을것 같습니다.)
만약 build.gradle에 v7라이브러리를 쓰고 있다면 다음을 추가하고
implementation 'com.android.support:recyclerview-v7:28.0.0'
androidx를 사용하고 있다면
implementation 'androidx.recyclerview:recyclerview:1.0.0'
를 추가합니다.
그리고 code를 작성합니다. (code를 작성하면 느낀건 RecyclerView 자체는 별 문제 없고 action에 대한 부분은 ReactiveX 방식으로 coding 한듯 합니다.)
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/main_recyclerview"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
i_test_item.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal" android:layout_width="match_parent"
android:layout_height="wrap_content">
<ImageView
android:id="@+id/i_img"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<TextView
android:id="@+id/i_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>
Item
import android.graphics.drawable.Drawable
class RecyclerItem(i : Drawable, n : String){
var name : String = n
var img : Drawable = i
}
Holder
import android.view.View
import androidx.recyclerview.widget.RecyclerView
import io.reactivex.Observable
import kotlinx.android.synthetic.main.i_test_item.view.*
class MyViewHolder(itemView : View) : RecyclerView.ViewHolder(itemView) {
val nameTView = itemView.i_name
val iconimg = itemView.i_img
fun getClickObserver(item :RecyclerItem) : Observable<RecyclerItem>{
return Observable.create { e-> itemView.setOnClickListener {
viwe-> e.onNext(item)
} }
}
}
Adapter
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import io.reactivex.subjects.PublishSubject
class MyViewAdapter () : RecyclerView.Adapter<MyViewHolder>(){
private val mItems : ArrayList<RecyclerItem> = ArrayList<RecyclerItem>()
val mPublishSubject: PublishSubject<RecyclerItem> = PublishSubject.create()
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
return MyViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.i_test_item,parent,false))
}
override fun getItemCount(): Int {
return mItems.size
}
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
val item = mItems[position]
holder.iconimg.setImageDrawable(item.img)
holder.nameTView.text = item.name
holder.getClickObserver(item).subscribe(mPublishSubject)
}
fun updateItems(items : ArrayList<RecyclerItem>){
mItems.addAll(items)
}
fun updateItems(item: RecyclerItem){
mItems.add(item)
}
}
Activity
import android.content.Intent
import android.content.pm.ResolveInfo
import android.os.Bundle
import android.widget.Toast
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.trello.rxlifecycle3.components.support.RxAppCompatActivity
import io.reactivex.Observable
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.rxkotlin.toObservable
import io.reactivex.schedulers.Schedulers
import kotlinx.android.synthetic.main.activity_main.*
class MainActivity : RxAppCompatActivity() {
val TAG: String = "Test_RxAndroid"
lateinit var mRecyclerView : RecyclerView
lateinit var mAdapter: MyViewAdapter
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
mRecyclerView = main_recyclerview
mRecyclerView.layoutManager = LinearLayoutManager(this)
mAdapter = MyViewAdapter()
mRecyclerView.adapter = mAdapter
mAdapter.mPublishSubject.subscribe { s->toast(s.name) }
}
override fun onStart() {
super.onStart()
getItemObservable()
.observeOn(AndroidSchedulers.mainThread())
.subscribe{
item->
mAdapter.updateItems(item)
mAdapter.notifyDataSetChanged()
}
}
fun toast(title: String){
Toast.makeText(this,title,Toast.LENGTH_SHORT).show()
}
fun getItemObservable():Observable<RecyclerItem>{
val pm = packageManager
val i = Intent(Intent.ACTION_MAIN,null)
i.addCategory(Intent.CATEGORY_LAUNCHER)
return pm.queryIntentActivities(i,0).toObservable()
.sorted(ResolveInfo.DisplayNameComparator(pm))
.subscribeOn(Schedulers.io())
.observeOn(Schedulers.io())
.map { item ->
val img = item.activityInfo.loadIcon(pm)
val title = item.activityInfo.loadLabel(pm).toString()
return@map RecyclerItem(img, title)
}
}
}
결과는 핸드폰에 깔리 app의 icon과 app 이름으로 된 리스트들이 recyclerview로 나타냅니다.
그리고 아이템을 클릭하면 title이름이 toast로 나타납니다.
code를 간단히 설명하면
1. onCreate에서 RecyclerView를 셋팅합니다.
2. onStart에서 getItemObservable을 통하여 폰의 application들의 icon과 이름을 획득합니다.
3. 획득한 데이터들을 AndroidMainThread에서 RecyclerView에 update 합니다.(notifyDataSetChanged를 하면 mAdapter의 데이터를 갱신해줍니다.)
4. 클릭 시 MyViewHolder의getClickObserver에서 ClickListner가 동작하고, 그 값으로 다시 subscribe가 동작하여 toast 함수가 동작합니다.
결과 화면은 다음과 같습니다.
'2023년 이전 > ReativeX' 카테고리의 다른 글
RxAndroid - Volley 사용(fromCallable, fromFuture ) (0) | 2020.02.18 |
---|---|
RxAndroid - 안드로이드 스레드 대체(AsyncTask) (0) | 2020.02.17 |
RxJava, RxKotlin - RxAndroid 란? (0) | 2020.02.10 |
RxJava, RxKotlin - 스케줄러를 활용하여 콜백 지옥 벗어나기 (0) | 2020.02.10 |
RxJava, RxKotlin - 스케줄러(3) (0) | 2020.01.28 |