Invincible의 RxKotlin

RxKotlin은 RxJava, RxAndroid에 비해서 참고 자료가 부족하네요...

 

요즘 한창 RxJava를 공부하고 있는데, 공부하면서 정리도 할겸 공유도 할겸 블로그 글을 써볼까 합니다.

 

Rx(Reactive) 시리즈는 java 뿐만 아니라 다른 언어에서도 많이 사용합니다. 전 안드로이드에서 사용하기 위해서 RxKotlin을 채택하고 연습하기로 했습니다. 먼저 제가 공부를 하고 있는 책은 "리액티브 프로그래밍 기초부터 RxAndroid까지 한번에 RxJava프로그래밍" 저자는 유동환, 박정준이라고 되어 있네요.

Rx프로그래밍은 RxJava나 RxAndroid나 RxKotlin이나 비슷한것 같네요.

 

책에 있는 예제를 RxKotlin을 사용해서 프로그래밍 해봤습니다. 처음이라 그런지 한참 헤맸습니다.

RxKotlin을 사용하기 위해서는

1. build.gradle에 아래와 같이 추가 해야 합니다.

implementation("io.reactivex.rxjava2:rxkotlin:2.4.0")
implementation "io.reactivex.rxjava2:rxandroid:2.1.1"

 

RxJava를 기반으로 RxAndroid가 나오고 이걸 기반으로 RxKotlin이 나오기 때문에 버전은 약간씩 다르네요. 가장 최신기술은 RxJava에 있겠네요.

 

제가 하려고 하는 작업은 

안드로이드의 설치된 앱정보를 가져와 RecyclerView에 나오게 하려고 합니다.

 

먼저 xml 입니다.

1. recycler_test_activity.xml 입니다.

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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"
    android:orientation="vertical"
    tools:context=".MainActivity">

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recycler_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:scrollbars="vertical" />
</RelativeLayout>

2. 아답터에서 사용할 xml 모습입니다.

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <ImageView
        android:id="@+id/thumb_iv"
        android:layout_width="50dp"
        android:layout_height="50dp"
        android:layout_marginLeft="10dp"
        android:layout_marginTop="10dp" />

    <TextView
        android:id="@+id/text_tv"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginLeft="10dp"
        android:layout_marginTop="10dp"
        android:layout_toRightOf="@+id/thumb_iv" />
</RelativeLayout>

 

XML은 전부 완성된것 같으니 Activity클래스의 코드를 작성할 차례네요.

 

package com.example.rxtest

import android.content.Context
import android.content.Intent
import android.content.pm.ResolveInfo
import android.graphics.drawable.Drawable
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import io.reactivex.Observable
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers
import java.util.*
import kotlin.collections.ArrayList

class RecyclerTestActivity : AppCompatActivity() {

    private lateinit var recyclerView: RecyclerView
    private lateinit var context: Context

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.recycler_test_activity)

        context = this

        recyclerView = findViewById(R.id.recycler_view)
        recyclerView.apply {
            layoutManager = LinearLayoutManager(context)
            adapter = TestMenuListAdapter()
            setHasFixedSize(true)
        }

        val disposable = getItemObservable()
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe {
                (recyclerView.adapter as TestMenuListAdapter).run {
                    setItems(it)
                }
            }
    }

//    private fun getItemObservable(): Observable<RecyclerItem> {
//        val pm = packageManager
//        val i = Intent(Intent.ACTION_MAIN).run {
//            addCategory(Intent.CATEGORY_LAUNCHER)
//        }
//
//        return pm.queryIntentActivities(i, 0).toObservable()
//            .sorted(ResolveInfo.DisplayNameComparator(pm))
//            .subscribeOn(Schedulers.io())
//            .observeOn(Schedulers.io())
////            .doOnNext {
////                Log.d("AAA", "title : ${it.activityInfo.loadLabel(pm)}")
////            }
//            .map { item ->
//                val image = item.activityInfo.loadIcon(pm)
//                val title = item.activityInfo.loadLabel(pm).toString()
//                return@map RecyclerItem(image, title)
//            }
//    }

    private fun getItemObservable(): Observable<MutableList<RecyclerItem>> {
        val pm = packageManager
        val i = Intent(Intent.ACTION_MAIN).run {
            addCategory(Intent.CATEGORY_LAUNCHER)
        }

        return Observable.fromArray(pm.queryIntentActivities(i, 0))
            .subscribeOn(Schedulers.io())
            .observeOn(Schedulers.io())
            .map { unSortedList ->
                val sortedList = ArrayList(unSortedList)
                Collections.sort(sortedList, ResolveInfo.DisplayNameComparator(pm))
                return@map sortedList
            }
            .flatMap { sortedList ->
                Observable.fromIterable(sortedList)
                    .map { item ->
                        val image = item.activityInfo.loadIcon(pm)
                        val title = item.activityInfo.loadLabel(pm).toString()
                        RecyclerItem(image, title)
                    }
                    .toList()
                    .toObservable()
            }
    }

    private inner class TestMenuListAdapter : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
        private val VIEW_TYPE_ITEM = 1

        private var mItems = ArrayList<RecyclerItem>()

        fun setItems(items: MutableList<RecyclerItem>) {
            mItems.addAll(items)
            notifyDataSetChanged()
        }

        fun setItems(items: RecyclerItem) {
            mItems.add(items)
            notifyDataSetChanged()
        }


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

        override fun getItemViewType(position: Int): Int {
            return VIEW_TYPE_ITEM
        }

        override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
            return ItemViewHolder(LayoutInflater.from(context).inflate(R.layout.app_item, parent, false))
        }

        override fun onBindViewHolder(viewHolder: RecyclerView.ViewHolder, position: Int) {
            when (viewHolder.itemViewType) {
                VIEW_TYPE_ITEM -> {
                    val vh = viewHolder as ItemViewHolder
                    val info = mItems?.get(position)
                    vh.textTv.text = info.title
                }
            }
        }

        private inner class ItemViewHolder(view: View) : RecyclerView.ViewHolder(view) {
            val thumbIv = view.findViewById(R.id.thumb_iv) as ImageView
            val textTv = view.findViewById(R.id.text_tv) as TextView
        }
    }

    private data class RecyclerItem(val thumb: Drawable?, val title: String?)
}

 

먼저 

Observable<RecyclerItem> 를 리턴하는 getItemObservable() 함수를 보시면 안드로이드 앱에서 설치된 앱리스트를 가져와서 각 아이템을 RecyclerItem으로 변경해서 아답터에 데이터를 추가합니다.

이러면 각 아이템에 대해서 notifyDataSetChanged()를 해야하는데, 이러면 효율이 떨어집니다. 

그래서 각 아이템을 list에 담아서 notifyDataSetChanged()를 한번만 할 수 있게 Observable<MutableList<RecyclerItem>> 를 리턴하도록 변경하였습니다. 더 좋은 방법이 있을 것 같은데, 저도 아직은 Rx와 안친해서 잘 모르겠네요.

 

각 함수 (map, flatmap, toList 등)를 적절히 조합하는게 최대 난제 인것 같습니다. 그럼 익숙해지는 그날까지 즐프요.

by Invincible Cooler 2020. 1. 15. 15:41

한국사 요점정리 앱은 개인정보를 수집하지 않습니다.

by Invincible Cooler 2018. 10. 4. 10:42

비트코인을 처음 시작할때 거래소는 무엇을 택해야 하는가?


세계1위의 빗썸 아니면 업비트? 결론부터 말하자면, 업비트를 강력추천한다.


빗썸은 아직 모바일 네이티브가 아닌, 모바일웹 화면으로 운영이 된다. 그에반해 업비트는 네이티브로 되어 있고, UI도 깔끔하다.


거래에서 가장 중요한게 내가 지금 수익률과 현재 거래가 어떻게 되고 있는가 인데, 가장기본이라고 생각했던 이런것조차 빗썸에서는 제공하지 않는다. 아무래도 빗썸은 인터페이스를 많이 바꿔야 할듯.


지금은 빗썸, 업비트를 포함한 모든 거래소에서 신규계정 발급을 막고 있어, 신규거래는 할수 없지만, 1월 20일 이후에는 가능하다고 하니, 왠만하면 업비트 사용을 강추드린다.


포탈을 검색해 보니, 빗썸은 출금도 바로바로 안해주는듯. 그에반해 업비트는 1분안에 모든게 완료. 못믿겠다면 직접 사용해 보시길.

'주식' 카테고리의 다른 글

미국의 금리 인상과 중국증시  (0) 2015.09.08
LG전자 그 세번째...  (0) 2015.07.30
LG전자 그 두번째 이야기.  (0) 2015.07.29
LG전자  (0) 2015.07.28
한국가스공사  (0) 2015.04.08
by Invincible Cooler 2018. 1. 1. 10:53
| 1 2 3 4 5 ··· 22 |