• RxJava2
    • 보통 Retrofit과 함께 사용한다.
    • MVVM 패턴과는 직접적인 연관은 없고, 모든 디자인패턴에서 사용할 수 있는 느낌?
    • Java8 람다식을 사용해 코드를 더 간결하게 쓸 수 있지만... 지금 그거까지 건드리면 머리 터진다...
    • Observable과 Observer 두개의 관점으로 나뉜다.
    • Observable 객체에서 .method()를 사용하여 다양한 역할/설정이 가능하다.
    • 함수중에는 filter / create / transform 형식의 함수들이 존재한다.
    • LiveData와 얼추 역할이 비슷하다. 인줄 알았지만 아니다...
    • 사용하는 가장 큰 이유 : 코드간결 -> 유지보수 측면 Good
    • 아래의 링크를 통해 함수의 역할들을 배울 수 있다.
    • RxAndroid와 같이 사용하여 쓰레딩을 쉽게 한다.
    • LiveData와 다르게 Disposable이라는 객체를 사용하여 더이상 '구독'하지 않는 상황이거나 사용하지 않을 때는 LifeCycle를 건드려야한다. (LiveData는 직접 건드리지 않아도 알아서 됨)
  • RxAndroid
    • 쓰레딩을 쉽게해주는 역할을 한다.
      • subscribeOn() - Background
      • observeOn() - Main Thread

https://codingwithmitch.com/courses/rxjava-rxandroid-for-beginners/

  • Retrofit
    • 서버에 요청할 때 사용, OKHttp에 의존한다
    • 서버에서 받아온 Data를 Observable로 받을 수 있다.(Dependency를 추가해야함. implementation)
      • 즉 그 Observable은 RxJava2를 사용하여 Observe할 수 있으며 filter나 다양한 함수를 사용하여 Data를 조작할 수 있다.
    • MVVM패턴에서 interface로 선언을 한다.
  • DataBinding
    • MVVM 패턴에서 사용되는 기법
    • LiveData와 사용
    • MVC같은 패턴에서는 C에서 findbyviewId(?)로 객체를 생성하여 찾아서 textview.text="asd" 처럼 해줬지만 Reactive Programming을 함께 사용하여 일일히 그렇게 할 수 없기에 사용한다.
    • gradle:App 단위에서 databinding을 enable해줘야한다.
    • 사용할 layout을 <layout>으로 감싸고 그 안에 <data>로 변수를 사용할 수 있다.
      • 주로 ViewModel을 가져와 ViewModel내의 변수의 값을 스스로 받아와 설정(수정)한다.
    • View(Activity / Fragment)에서는 Databinding을 위해 코드를 써줘야한다.
      • MVC 패턴에서의 setcontentview() 대신에 
 val binding = DataBindingUtil
                .setContentView<ActivityMainBinding>(this, R.layout.activity_main)
        binding.lifecycleOwner = this // LiveData를 사용하기 위해서 없으면 Observe할때마다 refresh안딤

        //binding 객체는 layout의 객체로 생각한다?

        //ViewModelProviders를 사용하여 ViewModel을 불러온다.
        val viewModel = ViewModelProviders.of(this)[MainViewModel::class.java]
        binding.viewModel = viewModel//layout의 binding 객체의 name = viewModel 에 viewModel을 초기화
  • MVVM 패턴
    • 디자인 패턴 중 하나로 MVC / MVP / MVVM / MVI(?) 이건 처음들어봄
    • 작은 프로젝트에서는 File이 많아진다는 단점이 존재하지만 큰 프로젝트에서는 Activity하나당 View하나인 1:1 대응 관계를 벗어나 ViewModel하나에 여러개의 View가 붙을 수 있다.
    • 사용하는 가장 큰 이유는 역시 가독성
  • LiveData
    • 살아있는 Data?
    • DataBinding을 할 수 있는 객체
    • 변경이 되는 것을 알아 차릴 수 있다.
    • RxJava와는 다른 느낌
    • RxJava와 달리 스스로 Dispose()를 해준다(생명주기에 따라서)
  • 뇌로 하는 상상
    • 사용할 view(layout)을 <layout>으로 감싼 뒤 <data>로 Data를 받아올 ViewModel을 변수로 생성 및 작업 
    • View와 ViewModel을 연결한다.(View에서 ViewModel을 생성한다. ViewModelProviders를 사용)
    • View에서 sercontentview() 대신 binding 작업을 한다.
    • ViewModel에서 Observable<LiveData<T>>을 생성한다.
    • Retrofit(Interface)에서 HTTP 통신 Method(?)를 만들고 반환 자료형은 Observable,Flowable
    •  Retrofit(Class)에서 전에 만든 Method를 구현한다.
    • ViewModel에서 Retrofit(Class)를 객체로 생성하여 원할 때 API를 호출하여 결과값(Observable)반환
    • ViewModel에서 Observer를 만든다.(.subscribe(......)를 사용하여)
    • Observer(subscribe()함수에서 LiveData를 받아온 Data로 바꿔준다.(받아온 Data는 Retrofit을 사용해 호출한 API의 반환값)
    • onNext()를 통해 LiveData<T>가 변경되면 DataBinding을 했기 때문에 View에서 자동으로 변경됨

 

 

 

 

Disposable - Observer가 더이상 필요없거나 Data를 받아오지 않을 때를 위한 객체

 

  • 모든 RxJava의 메커니즘
    • Observable<T>를 생성
    • Observable.subOn().obOn()
    • Observer를 사용하여 Observable 객체를 관찰
  • 만약 더이상 필요하지 않은 Observer는?

Activity와 Fragment의 onDestroy() // ViewModel의 onCleared() 에서 disposable를 없앤다.

 

disposable.clear()와 disposable.dispose()를 사용한다.

dispose()는 완전히 Observer가 필요 없어질 때 사용한다.

Flowable 이란?

- Observable과 같은 RxJava2에서 쓰이는 관찰 가능한 객체이다.

- 사용하는 가장 큰 이유는 backpressure를 처리하기 위함이다.

- Observable : backpressure - aware X

- Flowable : backpressure - aware O

 

+ backpressure - Observer에게 방출되는(관찰하는) Data가 너무 많으면 처리 불가.

                       Memory Leak 발생

 

backpressure에서 2가지 알아야할 용어가 있다.

  • Hot Source
    • Push 관계로 생각
    • Observable은 Observer를 신경쓰지 않는다. 계속해서 Data를 Push한다.
    • 즉, 관찰은 Observer에게 달려있다.
    • 이때, Data를 처리하기 위해 버퍼링이나 다른 방법을 사용해야함.
  • Cold Source 
    • Hot Source의 반대
    • Data가 느리게 Push되는 것으로 생각
    • Observer가 원할 때 Data를 직접 Pull(?)한다

 

Flowable 객체 생성

Flowable.range(0,100)
		.subscribeOn()
        .observeOn()
        ....

 

Hot Source의 문제를 해결하기 위해 

 

무제한 버퍼를 두어 해결 가능하다.

 

Flowable.range(0,100)
		.onBackpressureBuffer()// Data를 받아오는 곳에 무제한 버퍼를 둔다
		.subscribeOn()
        .observeOn()
        ....

 

 

 

 

 

RxJava를 사용해보자

 

순서는 4단계로 이루어진다.

1. Observable 생성

2. Observable에 연산자 적용

3. 작업을 수행할 Thread와 결과를 생성할 Thread를 지정

4. Observer를 Observable에 등록 후 결과를 확인

 

단일 객체와 리스트 객체를 Observable로 생성하는 코드를 비교해보자.

단일 객체
리스트 객체

예제 코드를 올리겠다.

 

Observable의 데이터 형태이다.

 

우리는 이 Task라는 class의 Object를 생성하여 Observable하게 만들고 Observer가 관찰하게 할 것이다.

class Task(description : String, isComplete : Boolean, priority : Int)
{
    var description = description
    var isComplete = isComplete
    var priority = priority



}

 


MVVM에서 Model 역할을 하는 class이다.

다른 예로 들자면 DB에서 Data를 가져오는 역할과 비슷하다.

 

class DataSource
{

    //Task 생성
    fun createTasksList() : List<Task>
    {
        var tasks = ArrayList<Task>()
        tasks.add(Task("Task out the trash",true,3))
        tasks.add(Task("Walk the dog",false,2))
        tasks.add(Task("Make my bed",true,1))
        tasks.add(Task("Upload the dishwasher",false,0))
        tasks.add(Task("Make dinner",true,5))

        return tasks
    }

}

MainActivity내의 코드이다.

 val taskObservable = Observable // create a new Observable object
            .fromIterable<Task>(DataSource().createTasksList()) // apply 'fromIterable' operator
            .subscribeOn(Schedulers.io()) // designate worker thread (background)
            .observeOn(AndroidSchedulers.mainThread()) // designate observer thread (main thread)

        taskObservable.subscribe(object : Observer<Task?> {
            override fun onComplete() {
                Log.d(TAG, "omComplete : called.")


            }

            override fun onSubscribe(d: Disposable) {
                Log.d(TAG, "onSubscribe : called.")
                disposable.add(d)
            }

            override fun onNext(t: Task) {
                Log.d(TAG, "onNext : " + Thread.currentThread().name)
                Log.d(TAG, "onNext : " + t.description)
                  //Thread.sleep(1000)
            }

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

 

taskObservable이라는 Observable 객체를 생성한다.

.fromIterable() -> 이전 class에서 가져온 Data를 넣어 순서대로 돌린다.

.subscribeOn() -> 데이터를 Background에서 뿌린다(?) 

.observeOn() -> 데이터를 Main Thread에서 관찰한다.

 

 

.subscribe() -> 넘어오는 Data를 관찰할 때마다 각각의 Method가 수행된다.

처음 관찰이 진행될 때 onSubscribe()

위에서 발행된(뿌려진) Data를 하나씩 가져올 때마다 onNext() 

모든 Data를 가져왔거나 Complete가 불렸을 때 onComplete()

 

 

 

 

 

 

 

+ Recent posts