RxAndroid Issue

1. Rx의 LifeCycle 관리

  • 비동기로 작업 중인 Rx의 Subscribe는 Activity나 Fragment가 종료된 뒤에도 동작 하고 있기 때문에 Memory leak이 발생할 수 있다. (만약 정상적으로 onComplete()onError()콜백으로 진입 하게 되면 알아서 unsubscribe()된다.)
  • 메모리의 누수를 막기 위해서는 Rx의 LifeCycle을 Activity나 Fragment의 LifeCycle에 맞추어 동작하게 해주면 된다. 하지만 어떻게? 해야 하는가 하는 고민이 생긴다.
  • RxJava에는 CompositeSubscription이라는 클래스를 제공 한다. 이 클래스는 생성된 Subscription인스턴스를 하나로 관리 해주는 클래스 이다.
  • 다른 방법이 또 있다면, Subscriber클래스를 상속한 클래스를 만들고 WeakReference로 래핑 해서 사용 하는 것이다. (참고)
  • CompositeSubscription클래스의 remove()메소드를 보면, Removes a Subscription from this CompositeSubscription, and unsubscribes the Subscription.이라고 되어 있다. 이 CompositeSubscriptionadd()Subscriptionremove()메소드를 콜하면 CompositeSubscripnt에서 제거 되면 동시에 unsubscribe된다고 명시 되어 있다.
  • CompositeSubscriptionremove()메소드를 활용하여 이를 Activity나 Fragment의 라이프 사이클에 연동 해서 사용 하면 된다.
  • Activity나 Fragment등의 onCreate()메소드 에서는 멤버변수로 존재 하는 CompositeSubscription인스턴스를 생성 하는 기능이 들어 간다.
  • 어떠한 작업을 위해서 subscribe()를 하게 되면 Subscription인스턴스를 변수로 정의 한 다음 CompositeSubscriptionadd()해 준다.
  • Activity나 Fragment등의 onDestroy()메소등에서는 생성된 인스턴스로 존재 하는 CompositeSubscription인스턴스를 unsubscribe()한다. Activity나 Fragment에서 생성되어지고 add()된 모든 Rx의 subscribe들은 이제 unubcribe()될 것 이다.

 


2. MVP 패턴에서의 CompositeSubscription

  • (1)의 방법에서는 Activity나 Fragment에 바로 Subscription을 생성하고 멤버변수로 CompositeSubscription을 생성하여 add(), unsubscribe()하는 것을 알 수 있다.
  • 하지만, MVP패턴에서는 Subscription을 실제로 생성하고 비동기 작업을 요청 하는곳이 Activity나 Fragment가 아닌 Presenter에서 하게 된다.
  • Presenter에 CompositeSubscription을 멤버로 두고 관리하게 하는건 무리가 없을것이다. 하지만 Activity나 Fragment의 Lifecycle에 맞추어 Subscription을 관리 하려 하는 목적에 어긋난다.
  • 단점이 있다면, Prsenter에서 Subscriber를 생성해서 Model에 던지는데 이때마다 addSubscriber()를 개발자가 명시적으로 호출 해서 add해야 해 줘야 한다. 만약에 개발자가 실수로 이 부분을 빼먹으면 Memory leak이 발생 할 수 있는 것이다. Model에서 처리 하는것도 방법이겠지만 Activity나 Fragment의 life cycle과 동기화 시키기 좀 까다롭다. (Observer 패턴을 응용하면 괜찮을 거 같다.)
  • 해결 방법은 다음과 같다.

 
– Presenter의 부모 클래스를 만들고 CompositeSubscription의 멤버변수를 추가 한다.
– 부모 클래스의 생성자에서는 CompositeSubscription의 인스턴스를 생성 한다.
– 부모 클래스에는 만들게 될 Subscriber의 인스턴스를 add()하는 메소드와 lifecycle의 onDestroy()에 맞춰 unsubscribe()하는 메소드인 destroy()메소드를 추가 한다.
– 앞으로 만들게 되는 모든 Presenter들은 부모 Presenter를 상속해서 만든다.
– 그리고 Activity나 Fragment를 상속한 부모 클래스들을 또 만들고, onCreate()메소드 군 에서는 presenter의 인스턴스를 생성 한다.
– 또한 onDestroy()에서는 presenter의 destroy()메소드를 꼭 호출 하여 생성된 모든 Subscriptionunsubscribe()하게 해 준다.


3. RxLifeCycle

  • 다 귀찮다면 그냥 Trello에서 개발 한 RxLifecycle을 사용 하면 된다.
Continue Reading

TIL | LegoLibrary 프로젝트 이슈

LegoLibrary 프로젝트 이슈

1. API 비밀 키 관리

  • LegoLibrary의 경우 Naver API를 사용하기 위한 공개 키로 사용되는 ID와, 비밀키 한쌍을 가지고 있다.
  • 문제는 이 한쌍의 키 들은 외부에 공개 되면 안되는 ‘비밀키’를 갖고 있는 것 이다. gitHub에 소스를 오픈하기 위해선 이러한 키 들을 가릴 필요가 있다.
  • 우선 프로젝트의 앱내부({project_name}/app/src/)gradle.properties를 수정 한다. 만약 이 파일이 없다면 새로 만든다. 그리고 이 파일 내부에 키를 작성 할 것이다. 예로 들면 다음 과 같다.

  • 이제 추가한 키 값을 앱의 build.gradle에서 BuildConfigs를 통해서 이용할 수 있게 할 것이다. {project_name}/app/src/build.gradle 파일을 열고 다음과 같이 수정 하자. (몰론 gradle.properties에서 작성한 API키 값의 키값과 일치 해야 한다.)

  • 내 프로젝트의 BuildConfig.NAVER_CLIENT_ID을 사용해보면 잘 되는것을 확인 할 수 있다.

gitHub / Today I Learned

Continue Reading

TIL | LegoLibrary 프로젝트 이슈

LegoLibrary 프로젝트 이슈

1. Retrofit

  • 기존에 사용하던 Volley보다 장점이라면 좀 더 빠르고 Restful한 API의 대응에 좋은거 같다. 하지만 내가 만든 php API는 Restful하지 못해서 문제. 단점이라면 내가 이해력이 딸려서 아직 제대로 장점을 더 확장해서 사용하지 못하는거 같다.
  • GSON의 파싱 문제. 이건 내가 잘못짠 서버 API의 문제라고 생각된다. 결국 ResponseBody를 직접 파싱하여 사용 하고 있지만 나중에 이 부분들도 다 수정 해야 겠다.
  • Retrofit의 Adapter클래스를 singleton으로 만들어서 사용했었는데 다른 서버 API를 사용하기 위해서 baseUrl과 API가 명시된 Interface의 class를 대응하기가 복잡 했음.
  • 그래서 일단 Adapter클래스는 그대로 두고 Builder클래스를 만들어서 static메소드를 두고 default paramter가 세팅된 인스턴스를 만들도록 설정.
  • 나중에 Builder패턴으로 구성해야 할거 같음..

기본적으로 세팅된 인스턴스를 만들어주는 static 메소드를 가진 Builder클래스.


예제로 만들어본 Adapter클래스. 여기에서 API의 Interface와 baseUrl만 바뀐다.


2. Realm

  • RealmObject를 상속한 data bean객체의 생성자에서 데이터를 초기화 해 주는 init()메소드를 콜 하고 있었는데 이 때문에 Realm에서 io.realm.ProxyState.getRealm$realm()' on a null object reference예외가 발생.
  • 그래서 해결 방법을 찾다 보니 구버전의 문서 에서 RealmObject를 상속하는 클래스에서는 비어있는 public생성자가 필요 한데 그 생성자의 내부 내용은 비어있어야 한다 라는 제한조건이 걸려 있었던 것. 참고
  • 생각지도 못한 제한 사항이라 일단 수정 하였음.
  • 그리고 Application을 상속한 클래스의 onCreate()메소드에서 Realm의 설정을 하도록 추가 하였음.

  • Fragment의 라이프 사이클에 맞추어서 onActivityCreated()에서 Realm인스턴스를 생성 하고 RealmChangeListner를 등록 할 수 있게 했음.
  • 그리고 onPause()onStop(), onResume()등의 메소드를 통해서 Realm의 라이프사이클을 관리 할 수 있도록 부모 Fragment를 만들고 상속받아서 사용 하게 설정 함.

 

gitHub / Today I Learned

Continue Reading
1 2 3 18