Skip to content

Commit

Permalink
Merge pull request #67 from trello/dlew/navi-improvements
Browse files Browse the repository at this point in the history
Handle more test cases, simplify in navi impl
  • Loading branch information
dlew committed Dec 10, 2015
2 parents e6c77c1 + 170fb97 commit d37bb24
Show file tree
Hide file tree
Showing 5 changed files with 156 additions and 30 deletions.
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
package com.trello.rxlifecycle.navi;

import android.os.Bundle;
import com.trello.navi.Event;
import com.trello.navi.Listener;
import com.trello.navi.NaviComponent;
import com.trello.navi.rx.RxNavi;
import com.trello.rxlifecycle.ActivityEvent;
Expand All @@ -19,19 +17,10 @@ public ActivityLifecycleProviderImpl(final NaviComponent activity) {
throw new IllegalArgumentException("NaviComponent does not handle all required events");
}

activity.addListener(Event.CREATE, new Listener<Bundle>() {
@Override
public void call(Bundle bundle) {
RxNavi.observe(activity, Event.ALL)
.map(NaviLifecycleMaps.ACTIVITY_EVENT_MAP)
.filter(RxUtils.notNull())
.takeUntil(RxNavi.observe(activity, Event.DESTROY))
.subscribe(lifecycleSubject);

// Subscribing in onCreate won't emit, so we need to do this ourselves
lifecycleSubject.onNext(ActivityEvent.CREATE);
}
});
RxNavi.observe(activity, Event.ALL)
.map(NaviLifecycleMaps.ACTIVITY_EVENT_MAP)
.filter(RxUtils.notNull())
.subscribe(lifecycleSubject);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
package com.trello.rxlifecycle.navi;

import android.content.Context;
import com.trello.navi.Event;
import com.trello.navi.Listener;
import com.trello.navi.NaviComponent;
import com.trello.navi.rx.RxNavi;
import com.trello.rxlifecycle.FragmentEvent;
Expand All @@ -20,19 +18,10 @@ public FragmentLifecycleProviderImpl(final NaviComponent fragment) {
throw new IllegalArgumentException("NaviComponent does not handle all required events");
}

fragment.addListener(Event.ATTACH, new Listener<Context>() {
@Override
public void call(Context context) {
RxNavi.observe(fragment, Event.ALL)
.map(NaviLifecycleMaps.FRAGMENT_EVENT_MAP)
.filter(RxUtils.notNull())
.takeUntil(RxNavi.observe(fragment, Event.DETACH))
.subscribe(lifecycleSubject);

// Subscribing in onCreate won't emit, so we need to do this ourselves
lifecycleSubject.onNext(FragmentEvent.ATTACH);
}
});
RxNavi.observe(fragment, Event.ALL)
.map(NaviLifecycleMaps.FRAGMENT_EVENT_MAP)
.filter(RxUtils.notNull())
.subscribe(lifecycleSubject);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,11 @@
import rx.observers.TestSubscriber;
import rx.subjects.PublishSubject;

import java.lang.ref.WeakReference;
import java.util.HashSet;

import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;

public class NaviActivityLifecycleTest {

Expand Down Expand Up @@ -131,4 +133,59 @@ public void testBadHandler() {
NaviComponent badHandler = new NaviEmitter(notEnoughEvents);
NaviLifecycle.createActivityLifecycleProvider(badHandler);
}

@Test
public void testPersistance() {
NaviEmitter activity = NaviEmitter.createActivityEmitter();
ActivityLifecycleProvider provider = NaviLifecycle.createActivityLifecycleProvider(activity);

TestSubscriber<ActivityEvent> testSubscriber = new TestSubscriber<>();
provider.lifecycle().subscribe(testSubscriber);

activity.onCreate(null);
activity.onStart();
activity.onResume();
activity.onPause();
activity.onStop();
activity.onDestroy();

// Verify that you can remain subscribed until the Activity is completely gone
activity.onCreate(null);

testSubscriber.assertValues(
ActivityEvent.CREATE,
ActivityEvent.START,
ActivityEvent.RESUME,
ActivityEvent.PAUSE,
ActivityEvent.STOP,
ActivityEvent.DESTROY,
ActivityEvent.CREATE
);
}

@Test
public void testLeakFree() {
NaviEmitter activity = NaviEmitter.createActivityEmitter();
ActivityLifecycleProvider provider = NaviLifecycle.createActivityLifecycleProvider(activity);
WeakReference<NaviEmitter> activityRef = new WeakReference<>(activity);
WeakReference<ActivityLifecycleProvider> providerRef = new WeakReference<>(provider);

Observable<Object> observable = PublishSubject.create().asObservable();
TestSubscriber<Object> testSubscriber = new TestSubscriber<>();
observable.compose(provider.bindUntilEvent(ActivityEvent.STOP)).subscribe(testSubscriber);

activity.onCreate(null);
activity.onStart();
activity.onResume();
activity.onPause();
activity.onStop();
activity.onDestroy();

activity = null;
provider = null;
TestUtil.cleanGarbage();

assertNull(activityRef.get());
assertNull(providerRef.get());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,11 @@
import rx.observers.TestSubscriber;
import rx.subjects.PublishSubject;

import java.lang.ref.WeakReference;
import java.util.HashSet;

import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;

public class NaviFragmentLifecycleTest {

Expand Down Expand Up @@ -181,4 +183,71 @@ public void testBadHandler() {
NaviComponent badHandler = new NaviEmitter(notEnoughEvents);
NaviLifecycle.createFragmentLifecycleProvider(badHandler);
}

@Test
public void testPersistance() {
NaviEmitter fragment = NaviEmitter.createFragmentEmitter();
FragmentLifecycleProvider provider = NaviLifecycle.createFragmentLifecycleProvider(fragment);

TestSubscriber<FragmentEvent> testSubscriber = new TestSubscriber<>();
provider.lifecycle().subscribe(testSubscriber);

fragment.onAttach(null);
fragment.onCreate(null);
fragment.onCreateView(null);
fragment.onStart();
fragment.onResume();
fragment.onPause();
fragment.onStop();
fragment.onDestroyView();
fragment.onDestroy();
fragment.onDetach();

// Verify that you can remain subscribed until the Fragment is completely gone
fragment.onAttach(null);

testSubscriber.assertValues(
FragmentEvent.ATTACH,
FragmentEvent.CREATE,
FragmentEvent.CREATE_VIEW,
FragmentEvent.START,
FragmentEvent.RESUME,
FragmentEvent.PAUSE,
FragmentEvent.STOP,
FragmentEvent.DESTROY_VIEW,
FragmentEvent.DESTROY,
FragmentEvent.DETACH,
FragmentEvent.ATTACH
);
}

@Test
public void testLeakFree() {
NaviEmitter fragment = NaviEmitter.createFragmentEmitter();
FragmentLifecycleProvider provider = NaviLifecycle.createFragmentLifecycleProvider(fragment);
WeakReference<NaviEmitter> fragmentRef = new WeakReference<>(fragment);
WeakReference<FragmentLifecycleProvider> providerRef = new WeakReference<>(provider);

Observable<Object> observable = PublishSubject.create().asObservable();
TestSubscriber<Object> testSubscriber = new TestSubscriber<>();
observable.compose(provider.bindUntilEvent(FragmentEvent.STOP)).subscribe(testSubscriber);

fragment.onAttach(null);
fragment.onCreate(null);
fragment.onCreateView(null);
fragment.onStart();
fragment.onResume();
fragment.onPause();
fragment.onStop();
fragment.onDestroyView();
fragment.onDestroy();
fragment.onDetach();

fragment = null;
provider = null;
TestUtil.cleanGarbage();

assertNull(fragmentRef.get());
assertNull(providerRef.get());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package com.trello.rxlifecycle.components;

final class TestUtil {

/**
* Used for testing whether references are cleared.
*/
static final void cleanGarbage() {
System.gc();
try {
Thread.sleep(100);
}
catch (Exception e) {
// Ignore
}
System.gc();
}

private TestUtil() {
throw new AssertionError("No instances!");
}
}

0 comments on commit d37bb24

Please sign in to comment.