본문 바로가기
2023년 이전/ReativeX

RxAndroid - 안드로이드 스레드 대체(AsyncTask)

by JeongUPark 2020. 2. 17.
반응형

[출처 - RxJava 프로그래밍 : 리액티브 프로그래밍 기초부터 안드로이드 까지 한번에]

본 글은 'RxJava 프로그래밍 : 리액티브 프로그래밍 기초부터 안드로이드 까지 한번에' 를 학습하면서 정리한 글입니다.

 

 

안드로이드는 기본적으로 싱글스레드 모델로, main 스레드에서 UI를 처리합니다. 그래서 main 스레드에서 많은 시간을 소모하는 작업을 할 경우 ANR이 발생하여 앱이 죽을 수도 있습니다. 더 자세한 내용은 여기서 확인 하시면 좋습니다.

그러므로 처리하는데 오래 걸리는 파일 입출력, 네트워크 통신등은 별도의 스레드를 사용하여 작업하는 것이 좋습니다.

 

그럼 처리방법중 AsyncTask에 RxAndroid 적용해보겠습니다.

AsyncTask는 안드로이드에서 제공하는 스레드 사용 방식중 하나입니다. 별도의 handler 클래스나 스레드 없이 UI 스레드에서 백그라운드 작업을 수행하고 결과를 표시할 수 있습니다.

 

우선 기본 AsyncTask를 보겠습니다. (xml은 단순 TextView만 추가되어 있습니다. 그리고 작업전에 build.gradle에

    implementation 'androidx.recyclerview:recyclerview:1.0.0'
    implementation 'io.reactivex.rxjava2:rxandroid:2.1.1'
    implementation 'io.reactivex.rxjava2:rxjava:2.2.17'
    implementation 'io.reactivex.rxjava2:rxkotlin:2.4.0'
    implementation 'com.jakewharton.rxbinding3:rxbinding:3.1.0'
    implementation("com.jakewharton.rxbinding2:rxbinding:2.2.0")
    implementation("com.trello.rxlifecycle3:rxlifecycle:3.1.0")
    implementation("com.trello.rxlifecycle3:rxlifecycle-android:3.1.0")
    implementation("com.trello.rxlifecycle3:rxlifecycle-components:3.1.0")

이것들을 추가해 주어야 동작합니다.)

 

Activity

package jeongu.test.rx_async

import android.os.AsyncTask
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.TextView
import kotlinx.android.synthetic.main.activity_main.*

class MainActivity : AppCompatActivity() {

    val mMyAsyncTask = MyAsyncTask()
    var mAndroidText : TextView? = null
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        mAndroidText = main_text
        initAndroidAsync()
    }

    fun initAndroidAsync(){
        mMyAsyncTask.execute("Hello","async","world")
    }
    inner class MyAsyncTask : AsyncTask<String, Void, String>() {
        override fun doInBackground(vararg p0: String?): String {
            val word =  StringBuilder()
            for(s in p0){
                word.append(s).append(" ")
            }
            return word.toString()
        }

        override fun onPostExecute(result: String?) {
            super.onPostExecute(result)
            mAndroidText!!.text = result
        }

    }
}

이렇게 작성후 동작시키면

 

이렇게 나타납니다. 그럼 리엑티브를 사용하여 다시 만들어 보겠습니다.

 

Activity

package jeongu.test.rx_async

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import android.widget.TextView
import io.reactivex.MaybeObserver
import io.reactivex.Observable
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.Disposable
import kotlinx.android.synthetic.main.activity_main.*

class MainActivity : AppCompatActivity() {
    private val TAG = "RxAndroid Async Test"
    var mAndroidText : TextView? = null
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        mAndroidText = main_text
        initRxAsync()
    }

    fun initRxAsync(){
        Observable.just("Hello","Rx","World")
            .reduce{x,y->"$x $y"}
            .observeOn(AndroidSchedulers.mainThread())
//            .subscribe(getObserver())
            .subscribe(
                {s -> mAndroidText!!.text = s},
                {e->Log.e(TAG,e.message)},
                {Log.i(TAG,"done")})
    }
    fun getObserver(): MaybeObserver<String> {
        return object : MaybeObserver<String>{
            override fun onSuccess(t: String) {
                mAndroidText!!.text = t
            }

            override fun onComplete() {
                Log.i(TAG, "done")
            }

            override fun onSubscribe(d: Disposable) {
            }

            override fun onError(e: Throwable) {
                Log.e(TAG,e.message)
            }

        }
    }
}

 

위에서 getObserver를 사용할 수도 있고, 단순히 subscribe로도 데이터를 만들 수 있습니다. 단 여기서 중요한것은 observeOn에 AndroidSchedulers.mainThread로 구독자가 실행될 스레드를 안드로이드의 UI 스레드로 지정하는게 중요합니다. 그리고 또한 onError 부분에서 Error 발생 시 처리를 할 수 있습니다. 그냥 Async를 사용할 때보다 더 활용도가 높아지고 code도 직관적인것 같습니다.

 

Async와 subscibe를 비교해보면 아래와 같이 됩니다.

AsyncTask RxAndroid
excute() subscribe()
doInBackground() 리액티브 연산자와 함꼐 사용하는 onSubscribe()
onPostExecuted() observer

 

반응형