diff --git a/build.gradle b/build.gradle index e6ce526..dc6fc08 100644 --- a/build.gradle +++ b/build.gradle @@ -48,6 +48,7 @@ ext.deps = [ compiletesting : 'com.google.testing.compile:compile-testing:0.7', roboelectric : 'org.robolectric:robolectric:3.1.2', robolectric_support : 'org.robolectric:shadows-support-v4:3.1.2', + equalsverifier : 'nl.jqno.equalsverifier:equalsverifier:2.1.8' ] // Static analysis diff --git a/examples/real-world/src/main/java/com/soundcloud/lightcycle/sample/real_world/HomePresenter.java b/examples/real-world/src/main/java/com/soundcloud/lightcycle/sample/real_world/HomePresenter.java index 97fc841..4faa817 100644 --- a/examples/real-world/src/main/java/com/soundcloud/lightcycle/sample/real_world/HomePresenter.java +++ b/examples/real-world/src/main/java/com/soundcloud/lightcycle/sample/real_world/HomePresenter.java @@ -2,10 +2,6 @@ import com.soundcloud.lightcycle.ActivityLightCycleDispatcher; import com.soundcloud.lightcycle.LightCycle; -import com.soundcloud.lightcycle.LightCycles; - -import android.os.Bundle; -import android.support.annotation.Nullable; import javax.inject.Inject; @@ -18,10 +14,4 @@ class HomePresenter extends ActivityLightCycleDispatcher { this.headerPresenter = headerPresenter; this.descriptionPresenter = descriptionPresenter; } - - @Override - public void onCreate(HomeActivity activity, @Nullable Bundle bundle) { - LightCycles.bind(this); - super.onCreate(activity, bundle); - } } diff --git a/lightcycle-api/build.gradle b/lightcycle-api/build.gradle index 6138869..7fba3fd 100644 --- a/lightcycle-api/build.gradle +++ b/lightcycle-api/build.gradle @@ -5,8 +5,10 @@ checkstyle { configFile rootProject.file('checkstyle.xml') showViolations true } - dependencies { provided deps.android provided deps.support_v4 + + testCompile deps.junit + testCompile deps.equalsverifier } diff --git a/lightcycle-api/src/main/java/com/soundcloud/lightcycle/LightCycles.java b/lightcycle-api/src/main/java/com/soundcloud/lightcycle/LightCycles.java index e87afab..727b0ae 100644 --- a/lightcycle-api/src/main/java/com/soundcloud/lightcycle/LightCycles.java +++ b/lightcycle-api/src/main/java/com/soundcloud/lightcycle/LightCycles.java @@ -17,6 +17,8 @@ public final class LightCycles { private static final String ANDROID_PREFIX = "android."; private static final String JAVA_PREFIX = "java."; + + @SuppressWarnings("PMD.EmptyCatchBlock") public static void bind(LightCycleDispatcher target) { Method bindingMethod; @@ -54,204 +56,288 @@ private static Method findBinderForClass(Class cls) } public static ActivityLightCycle lift(final ActivityLightCycle lightCycle) { - return new ActivityLightCycle() { + return new LiftedActivityLightCycle<>(lightCycle); + } - @Override - public void onCreate(Target activity, Bundle bundle) { - lightCycle.onCreate(activity, bundle); - } + @TargetApi(Build.VERSION_CODES.HONEYCOMB) + public static FragmentLightCycle lift(final FragmentLightCycle lightCycle) { + return new LiftedFragmentLightCycle<>(lightCycle); + } - @Override - public void onNewIntent(Target activity, Intent intent) { - lightCycle.onNewIntent(activity, intent); - } - @Override - public void onStart(Target activity) { - lightCycle.onStart(activity); - } + public static SupportFragmentLightCycle lift(final SupportFragmentLightCycle lightCycle) { + return new LiftedSupportFragmentLightCycle<>(lightCycle); + } - @Override - public void onResume(Target activity) { - lightCycle.onResume(activity); - } + static final class LiftedActivityLightCycle implements ActivityLightCycle { - @Override - public boolean onOptionsItemSelected(Target activity, MenuItem item) { - return lightCycle.onOptionsItemSelected(activity, item); - } + private final ActivityLightCycle lightCycle; - @Override - public void onPause(Target activity) { - lightCycle.onPause(activity); - } + LiftedActivityLightCycle(ActivityLightCycle lightCycle) { + this.lightCycle = lightCycle; + } - @Override - public void onStop(Target activity) { - lightCycle.onStop(activity); - } + @Override + public void onCreate(Target activity, Bundle bundle) { + lightCycle.onCreate(activity, bundle); + } - @Override - public void onSaveInstanceState(Target activity, Bundle bundle) { - lightCycle.onSaveInstanceState(activity, bundle); - } + @Override + public void onNewIntent(Target activity, Intent intent) { + lightCycle.onNewIntent(activity, intent); + } - @Override - public void onRestoreInstanceState(Target activity, Bundle bundle) { - lightCycle.onRestoreInstanceState(activity, bundle); - } + @Override + public void onStart(Target activity) { + lightCycle.onStart(activity); + } + + @Override + public void onResume(Target activity) { + lightCycle.onResume(activity); + } + + @Override + public boolean onOptionsItemSelected(Target activity, MenuItem item) { + return lightCycle.onOptionsItemSelected(activity, item); + } + + @Override + public void onPause(Target activity) { + lightCycle.onPause(activity); + } + + @Override + public void onStop(Target activity) { + lightCycle.onStop(activity); + } - @Override - public void onDestroy(Target activity) { - lightCycle.onDestroy(activity); + @Override + public void onSaveInstanceState(Target activity, Bundle bundle) { + lightCycle.onSaveInstanceState(activity, bundle); + } + + @Override + public void onRestoreInstanceState(Target activity, Bundle bundle) { + lightCycle.onRestoreInstanceState(activity, bundle); + } + + @Override + public void onDestroy(Target activity) { + lightCycle.onDestroy(activity); + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; } - }; + if (o == null || getClass() != o.getClass()) { + return false; + } + + LiftedActivityLightCycle that = (LiftedActivityLightCycle) o; + + return lightCycle != null ? lightCycle.equals(that.lightCycle) : that.lightCycle == null; + } + + @Override + public int hashCode() { + return lightCycle != null ? lightCycle.hashCode() : 0; + } } @TargetApi(Build.VERSION_CODES.HONEYCOMB) - public static FragmentLightCycle lift(final FragmentLightCycle lightCycle) { - return new FragmentLightCycle() { + static final class LiftedFragmentLightCycle implements FragmentLightCycle { - @Override - public void onAttach(Target fragment, Activity activity) { - lightCycle.onAttach(fragment, activity); - } + private final FragmentLightCycle lightCycle; - @Override - public void onAttach(Target fragment, Context context) { - lightCycle.onAttach(fragment, context); - } + LiftedFragmentLightCycle(FragmentLightCycle lightCycle) { + this.lightCycle = lightCycle; + } - @Override - public void onCreate(Target fragment, Bundle bundle) { - lightCycle.onCreate(fragment, bundle); - } + @Override + public void onAttach(Target fragment, Activity activity) { + lightCycle.onAttach(fragment, activity); + } - @Override - public void onViewCreated(Target fragment, View view, Bundle savedInstanceState) { - lightCycle.onViewCreated(fragment, view, savedInstanceState); - } + @Override + public void onAttach(Target fragment, Context context) { + lightCycle.onAttach(fragment, context); + } - @Override - public void onActivityCreated(Target fragment, Bundle bundle) { - lightCycle.onActivityCreated(fragment, bundle); - } + @Override + public void onCreate(Target fragment, Bundle bundle) { + lightCycle.onCreate(fragment, bundle); + } - @Override - public void onStart(Target fragment) { - lightCycle.onStart(fragment); - } + @Override + public void onViewCreated(Target fragment, View view, Bundle savedInstanceState) { + lightCycle.onViewCreated(fragment, view, savedInstanceState); + } - @Override - public void onResume(Target fragment) { - lightCycle.onResume(fragment); - } + @Override + public void onActivityCreated(Target fragment, Bundle bundle) { + lightCycle.onActivityCreated(fragment, bundle); + } - @Override - public boolean onOptionsItemSelected(Target fragment, MenuItem item) { - return lightCycle.onOptionsItemSelected(fragment, item); - } + @Override + public void onStart(Target fragment) { + lightCycle.onStart(fragment); + } - @Override - public void onPause(Target fragment) { - lightCycle.onPause(fragment); - } + @Override + public void onResume(Target fragment) { + lightCycle.onResume(fragment); + } - @Override - public void onStop(Target fragment) { - lightCycle.onStop(fragment); - } + @Override + public boolean onOptionsItemSelected(Target fragment, MenuItem item) { + return lightCycle.onOptionsItemSelected(fragment, item); + } - @Override - public void onSaveInstanceState(Target fragment, Bundle bundle) { - lightCycle.onSaveInstanceState(fragment, bundle); - } + @Override + public void onPause(Target fragment) { + lightCycle.onPause(fragment); + } - @Override - public void onDestroyView(Target fragment) { - lightCycle.onDestroyView(fragment); - } + @Override + public void onStop(Target fragment) { + lightCycle.onStop(fragment); + } - @Override - public void onDestroy(Target fragment) { - lightCycle.onDestroy(fragment); - } + @Override + public void onSaveInstanceState(Target fragment, Bundle bundle) { + lightCycle.onSaveInstanceState(fragment, bundle); + } + + @Override + public void onDestroyView(Target fragment) { + lightCycle.onDestroyView(fragment); + } + + @Override + public void onDestroy(Target fragment) { + lightCycle.onDestroy(fragment); + } + + @Override + public void onDetach(Target fragment) { + lightCycle.onDetach(fragment); + } - @Override - public void onDetach(Target fragment) { - lightCycle.onDetach(fragment); + @Override + public boolean equals(Object o) { + if (this == o) { + return true; } - }; + if (o == null || getClass() != o.getClass()) { + return false; + } + + LiftedFragmentLightCycle that = (LiftedFragmentLightCycle) o; + + return lightCycle != null ? lightCycle.equals(that.lightCycle) : that.lightCycle == null; + + } + + @Override + public int hashCode() { + return lightCycle != null ? lightCycle.hashCode() : 0; + } } + static final class LiftedSupportFragmentLightCycle implements SupportFragmentLightCycle { - public static SupportFragmentLightCycle lift(final SupportFragmentLightCycle lightCycle) { - return new SupportFragmentLightCycle() { + private final SupportFragmentLightCycle lightCycle; - @Override - public void onAttach(Target fragment, Activity activity) { - lightCycle.onAttach(fragment, activity); - } + LiftedSupportFragmentLightCycle(SupportFragmentLightCycle lightCycle) { + this.lightCycle = lightCycle; + } - @Override - public void onCreate(Target fragment, Bundle bundle) { - lightCycle.onCreate(fragment, bundle); - } + @Override + public void onAttach(Target fragment, Activity activity) { + lightCycle.onAttach(fragment, activity); + } - @Override - public void onViewCreated(Target fragment, View view, Bundle savedInstanceState) { - lightCycle.onViewCreated(fragment, view, savedInstanceState); - } + @Override + public void onCreate(Target fragment, Bundle bundle) { + lightCycle.onCreate(fragment, bundle); + } - @Override - public void onActivityCreated(Target fragment, Bundle bundle) { - lightCycle.onActivityCreated(fragment, bundle); - } + @Override + public void onViewCreated(Target fragment, View view, Bundle savedInstanceState) { + lightCycle.onViewCreated(fragment, view, savedInstanceState); + } - @Override - public void onStart(Target fragment) { - lightCycle.onStart(fragment); - } + @Override + public void onActivityCreated(Target fragment, Bundle bundle) { + lightCycle.onActivityCreated(fragment, bundle); + } - @Override - public void onResume(Target fragment) { - lightCycle.onResume(fragment); - } + @Override + public void onStart(Target fragment) { + lightCycle.onStart(fragment); + } - @Override - public boolean onOptionsItemSelected(Target fragment, MenuItem item) { - return lightCycle.onOptionsItemSelected(fragment, item); - } + @Override + public void onResume(Target fragment) { + lightCycle.onResume(fragment); + } - @Override - public void onPause(Target fragment) { - lightCycle.onPause(fragment); - } + @Override + public boolean onOptionsItemSelected(Target fragment, MenuItem item) { + return lightCycle.onOptionsItemSelected(fragment, item); + } - @Override - public void onStop(Target fragment) { - lightCycle.onStop(fragment); - } + @Override + public void onPause(Target fragment) { + lightCycle.onPause(fragment); + } - @Override - public void onSaveInstanceState(Target fragment, Bundle bundle) { - lightCycle.onSaveInstanceState(fragment, bundle); - } + @Override + public void onStop(Target fragment) { + lightCycle.onStop(fragment); + } - @Override - public void onDestroyView(Target fragment) { - lightCycle.onDestroyView(fragment); - } + @Override + public void onSaveInstanceState(Target fragment, Bundle bundle) { + lightCycle.onSaveInstanceState(fragment, bundle); + } - @Override - public void onDestroy(Target fragment) { - lightCycle.onDestroy(fragment); - } + @Override + public void onDestroyView(Target fragment) { + lightCycle.onDestroyView(fragment); + } + + @Override + public void onDestroy(Target fragment) { + lightCycle.onDestroy(fragment); + } + + @Override + public void onDetach(Target fragment) { + lightCycle.onDetach(fragment); + } - @Override - public void onDetach(Target fragment) { - lightCycle.onDetach(fragment); + @Override + public boolean equals(Object o) { + if (this == o) { + return true; } - }; + if (o == null || getClass() != o.getClass()) { + return false; + } + + LiftedSupportFragmentLightCycle that = (LiftedSupportFragmentLightCycle) o; + + return lightCycle != null ? lightCycle.equals(that.lightCycle) : that.lightCycle == null; + + } + + @Override + public int hashCode() { + return lightCycle != null ? lightCycle.hashCode() : 0; + } } } diff --git a/lightcycle-api/src/test/java/com/soundcloud/lightcycle/LightCyclesTest.java b/lightcycle-api/src/test/java/com/soundcloud/lightcycle/LightCyclesTest.java new file mode 100644 index 0000000..4e5f6d4 --- /dev/null +++ b/lightcycle-api/src/test/java/com/soundcloud/lightcycle/LightCyclesTest.java @@ -0,0 +1,61 @@ +package com.soundcloud.lightcycle; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.core.IsEqual.equalTo; +import static org.hamcrest.core.IsNot.not; +import static org.hamcrest.core.IsSame.sameInstance; + +import nl.jqno.equalsverifier.EqualsVerifier; +import org.junit.Test; + +import android.app.Activity; +import android.app.Fragment; + +public class LightCyclesTest { + + @Test + public void liftedActivityLightCycleEqualsContract() { + EqualsVerifier.forClass(LightCycles.LiftedActivityLightCycle.class).verify(); + } + + @Test + public void liftedFragmentLightCycleEqualsContract() { + EqualsVerifier.forClass(LightCycles.LiftedFragmentLightCycle.class).verify(); + } + + @Test + public void liftedSupportFragmentLightCycleEqualsContract() { + EqualsVerifier.forClass(LightCycles.LiftedSupportFragmentLightCycle.class).verify(); + } + + @Test + public void liftedActivityLightCycleAreEqualsWhenTheSourceIsTheSame() { + final DefaultActivityLightCycle lightCycle = new DefaultActivityLightCycle<>(); + final ActivityLightCycle lift1 = LightCycles.lift(lightCycle); + final ActivityLightCycle lift2 = LightCycles.lift(lightCycle); + + assertThat(lift1, not(sameInstance(lift2))); + assertThat(lift1, equalTo(lift2)); + } + + @Test + public void liftedFragmentLightCycleAreEqualsWhenTheSourceIsTheSame() { + final DefaultFragmentLightCycle lightCycle = new DefaultFragmentLightCycle<>(); + final FragmentLightCycle lift1 = LightCycles.lift(lightCycle); + final FragmentLightCycle lift2 = LightCycles.lift(lightCycle); + + assertThat(lift1, not(sameInstance(lift2))); + assertThat(lift1, equalTo(lift2)); + } + + @Test + public void liftedSupportFragmentLightCycleAreEqualsWhenTheSourceIsTheSame() { + final DefaultSupportFragmentLightCycle lightCycle = new DefaultSupportFragmentLightCycle<>(); + final SupportFragmentLightCycle lift1 = LightCycles.lift(lightCycle); + final SupportFragmentLightCycle lift2 = LightCycles.lift(lightCycle); + + assertThat(lift1, not(sameInstance(lift2))); + assertThat(lift1, equalTo(lift2)); + } + +} diff --git a/lightcycle-integration-test/src/main/java/com/soundcloud/lightcycle/integration_test/SampleFragment.java b/lightcycle-integration-test/src/main/java/com/soundcloud/lightcycle/integration_test/SampleFragment.java index 2c5f728..fa2ac35 100644 --- a/lightcycle-integration-test/src/main/java/com/soundcloud/lightcycle/integration_test/SampleFragment.java +++ b/lightcycle-integration-test/src/main/java/com/soundcloud/lightcycle/integration_test/SampleFragment.java @@ -1,21 +1,36 @@ package com.soundcloud.lightcycle.integration_test; +import com.soundcloud.lightcycle.FragmentLightCycle; +import com.soundcloud.lightcycle.LightCycle; +import com.soundcloud.lightcycle.LightCycleFragment; +import com.soundcloud.lightcycle.sample.basic.R; + import android.annotation.TargetApi; +import android.app.Activity; import android.os.Build; import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import com.soundcloud.lightcycle.LightCycle; -import com.soundcloud.lightcycle.LightCycleFragment; -import com.soundcloud.lightcycle.sample.basic.R; - @TargetApi(Build.VERSION_CODES.HONEYCOMB) public class SampleFragment extends LightCycleFragment { - @LightCycle - FragmentLogger fragmentLogger = new FragmentLogger(); + @LightCycle FragmentLogger fragmentLogger = new FragmentLogger(); + int bindCount = 0; + int onAttachCount = 0; + + @Override + public void bind(FragmentLightCycle lifeCycleComponent) { + super.bind(lifeCycleComponent); + bindCount++; + } + + @Override + public void onAttach(Activity activity) { + super.onAttach(activity); + onAttachCount++; + } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { diff --git a/lightcycle-integration-test/src/main/java/com/soundcloud/lightcycle/integration_test/SampleFragmentDispatcher.java b/lightcycle-integration-test/src/main/java/com/soundcloud/lightcycle/integration_test/SampleFragmentDispatcher.java new file mode 100644 index 0000000..3803170 --- /dev/null +++ b/lightcycle-integration-test/src/main/java/com/soundcloud/lightcycle/integration_test/SampleFragmentDispatcher.java @@ -0,0 +1,20 @@ +package com.soundcloud.lightcycle.integration_test; + +import com.soundcloud.lightcycle.DefaultFragmentLightCycle; +import com.soundcloud.lightcycle.FragmentLightCycle; +import com.soundcloud.lightcycle.FragmentLightCycleDispatcher; +import com.soundcloud.lightcycle.LightCycle; + +import android.app.Fragment; + +class SampleFragmentDispatcher extends FragmentLightCycleDispatcher { + @LightCycle DefaultFragmentLightCycle lightCycle = new DefaultFragmentLightCycle<>(); + + int bindCount = 0; + + @Override + public void bind(FragmentLightCycle lightCycle) { + super.bind(lightCycle); + bindCount++; + } +} diff --git a/lightcycle-integration-test/src/main/java/com/soundcloud/lightcycle/integration_test/SampleSupportFragment.java b/lightcycle-integration-test/src/main/java/com/soundcloud/lightcycle/integration_test/SampleSupportFragment.java index beb5735..6639df7 100644 --- a/lightcycle-integration-test/src/main/java/com/soundcloud/lightcycle/integration_test/SampleSupportFragment.java +++ b/lightcycle-integration-test/src/main/java/com/soundcloud/lightcycle/integration_test/SampleSupportFragment.java @@ -1,18 +1,34 @@ package com.soundcloud.lightcycle.integration_test; +import com.soundcloud.lightcycle.LightCycle; +import com.soundcloud.lightcycle.LightCycleSupportFragment; +import com.soundcloud.lightcycle.SupportFragmentLightCycle; +import com.soundcloud.lightcycle.sample.basic.R; + +import android.app.Activity; import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import com.soundcloud.lightcycle.LightCycle; -import com.soundcloud.lightcycle.LightCycleSupportFragment; -import com.soundcloud.lightcycle.sample.basic.R; - public class SampleSupportFragment extends LightCycleSupportFragment { @LightCycle SupportFragmentLogger supportFragmentLogger = new SupportFragmentLogger(); + public int onAttachCount; + public int bindCount; + + @Override + public void onAttach(Activity activity) { + super.onAttach(activity); + onAttachCount++; + } + + @Override + public void bind(SupportFragmentLightCycle lifeCycleComponent) { + super.bind(lifeCycleComponent); + bindCount++; + } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { diff --git a/lightcycle-integration-test/src/main/java/com/soundcloud/lightcycle/integration_test/SampleSupportFragmentDispatcher.java b/lightcycle-integration-test/src/main/java/com/soundcloud/lightcycle/integration_test/SampleSupportFragmentDispatcher.java new file mode 100644 index 0000000..e2a416d --- /dev/null +++ b/lightcycle-integration-test/src/main/java/com/soundcloud/lightcycle/integration_test/SampleSupportFragmentDispatcher.java @@ -0,0 +1,20 @@ +package com.soundcloud.lightcycle.integration_test; + +import com.soundcloud.lightcycle.DefaultSupportFragmentLightCycle; +import com.soundcloud.lightcycle.LightCycle; +import com.soundcloud.lightcycle.SupportFragmentLightCycle; +import com.soundcloud.lightcycle.SupportFragmentLightCycleDispatcher; + +import android.support.v4.app.Fragment; + +class SampleSupportFragmentDispatcher extends SupportFragmentLightCycleDispatcher { + @LightCycle DefaultSupportFragmentLightCycle lightCycle = new DefaultSupportFragmentLightCycle<>(); + + int bindCount = 0; + + @Override + public void bind(SupportFragmentLightCycle lightCycle) { + super.bind(lightCycle); + bindCount++; + } +} diff --git a/lightcycle-integration-test/src/test/java/com/soundcloud/lightcycle/integration_test/FragmentLoggerTest.java b/lightcycle-integration-test/src/test/java/com/soundcloud/lightcycle/integration_test/FragmentLoggerTest.java index 10c8049..04597c4 100644 --- a/lightcycle-integration-test/src/test/java/com/soundcloud/lightcycle/integration_test/FragmentLoggerTest.java +++ b/lightcycle-integration-test/src/test/java/com/soundcloud/lightcycle/integration_test/FragmentLoggerTest.java @@ -1,22 +1,22 @@ package com.soundcloud.lightcycle.integration_test; -import android.os.Bundle; +import static com.google.common.truth.Truth.assertThat; import com.google.common.truth.BooleanSubject; import com.soundcloud.lightcycle.integration_test.callback.FragmentLifecycleCallback; import com.soundcloud.lightcycle.sample.basic.BuildConfig; - import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.RobolectricTestRunner; import org.robolectric.annotation.Config; import org.robolectric.util.FragmentController; +import utils.FragmentTestHelper; + +import android.os.Bundle; import java.util.Arrays; import java.util.List; -import static com.google.common.truth.Truth.assertThat; - @RunWith(RobolectricTestRunner.class) @Config(constants = BuildConfig.class, sdk = 22) public class FragmentLoggerTest { @@ -130,6 +130,18 @@ public void onDestroy() { ); } + @Test + public void bindFragmentOnlyOnceWhenReAttched() { + FragmentTestHelper + .from(sampleFragment) + .addFragment() + .removeFragment() + .addFragment(); + + assertThat(sampleFragment.onAttachCount).is(2); + assertThat(sampleFragment.bindCount).is(1); + } + private void assertLifecycleCallbackCallIsCorrect(List callbacks) { for (FragmentLifecycleCallback fragmentLifecycleCallback : FragmentLifecycleCallback.values()) { BooleanSubject subject = assertThat(fragmentLogger.isFragmentLifecycleCallbackCalled(fragmentLifecycleCallback)); @@ -140,4 +152,4 @@ private void assertLifecycleCallbackCallIsCorrect(List callbacks) { for (FragmentLifecycleCallback fragmentLifecycleCallback : FragmentLifecycleCallback.values()) { BooleanSubject subject = assertThat(supportFragmentLogger.isFragmentLifecycleCallbackCalled(fragmentLifecycleCallback)); @@ -118,4 +130,4 @@ private void assertLifecycleCallbackCallIsCorrect(List implements LightCycleDispatcher>, FragmentLightCycle { + private final Set> fragmentLightCycles; + private final LightCycleBinderHelper binderHelper; public FragmentLightCycleDispatcher() { this.fragmentLightCycles = new HashSet<>(); + this.binderHelper = new LightCycleBinderHelper(this); } @Override @@ -32,7 +36,7 @@ public void bind(FragmentLightCycle lightCycle) { @Override public void onAttach(T fragment, Activity activity) { - LightCycles.bind(this); + binderHelper.bindIfNecessary(); for (FragmentLightCycle component : fragmentLightCycles) { component.onAttach(fragment, activity); } @@ -40,7 +44,7 @@ public void onAttach(T fragment, Activity activity) { @Override public void onAttach(T fragment, Context context) { - LightCycles.bind(this); + binderHelper.bindIfNecessary(); for (FragmentLightCycle component : fragmentLightCycles) { component.onAttach(fragment, context); } diff --git a/lightcycle-lib/src/main/java/com/soundcloud/lightcycle/LightCycleFragment.java b/lightcycle-lib/src/main/java/com/soundcloud/lightcycle/LightCycleFragment.java index 0120d00..24dfda6 100644 --- a/lightcycle-lib/src/main/java/com/soundcloud/lightcycle/LightCycleFragment.java +++ b/lightcycle-lib/src/main/java/com/soundcloud/lightcycle/LightCycleFragment.java @@ -1,5 +1,8 @@ package com.soundcloud.lightcycle; +import com.soundcloud.lightcycle.util.LightCycleBinderHelper; +import com.soundcloud.lightcycle.util.Preconditions; + import android.annotation.TargetApi; import android.app.Activity; import android.app.Fragment; @@ -9,16 +12,15 @@ import android.view.MenuItem; import android.view.View; -import com.soundcloud.lightcycle.util.Preconditions; - @TargetApi(Build.VERSION_CODES.HONEYCOMB) public abstract class LightCycleFragment extends Fragment implements LightCycleDispatcher> { private final FragmentLightCycleDispatcher lifeCycleDispatcher; - private boolean bound; + private final LightCycleBinderHelper binderHelper; public LightCycleFragment() { - lifeCycleDispatcher = new FragmentLightCycleDispatcher<>(); + this.lifeCycleDispatcher = new FragmentLightCycleDispatcher<>(); + this.binderHelper = new LightCycleBinderHelper(this); } @Override @@ -31,7 +33,7 @@ public void bind(FragmentLightCycle lifeCycleComponent) { @TargetApi(23) public void onAttach(Context context) { super.onAttach(context); - bindIfNecessary(); + binderHelper.bindIfNecessary(); lifeCycleDispatcher.onAttach(fragment(), context); } @@ -43,17 +45,10 @@ public void onAttach(Context context) { @SuppressWarnings("deprecation") public void onAttach(Activity activity) { super.onAttach(activity); - bindIfNecessary(); + binderHelper.bindIfNecessary(); lifeCycleDispatcher.onAttach(fragment(), activity); } - private void bindIfNecessary() { - if (!bound) { - LightCycles.bind(this); - bound = true; - } - } - @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); diff --git a/lightcycle-lib/src/main/java/com/soundcloud/lightcycle/LightCyclePreferenceFragmentCompat.java b/lightcycle-lib/src/main/java/com/soundcloud/lightcycle/LightCyclePreferenceFragmentCompat.java index 88e7c01..fc7c90b 100644 --- a/lightcycle-lib/src/main/java/com/soundcloud/lightcycle/LightCyclePreferenceFragmentCompat.java +++ b/lightcycle-lib/src/main/java/com/soundcloud/lightcycle/LightCyclePreferenceFragmentCompat.java @@ -1,5 +1,8 @@ package com.soundcloud.lightcycle; +import com.soundcloud.lightcycle.util.LightCycleBinderHelper; +import com.soundcloud.lightcycle.util.Preconditions; + import android.app.Activity; import android.os.Bundle; import android.support.v4.app.Fragment; @@ -7,16 +10,15 @@ import android.view.MenuItem; import android.view.View; -import com.soundcloud.lightcycle.util.Preconditions; - public abstract class LightCyclePreferenceFragmentCompat extends PreferenceFragmentCompat implements LightCycleDispatcher> { private final SupportFragmentLightCycleDispatcher lifeCycleDispatcher; - private boolean bound; + private final LightCycleBinderHelper binderHelper; public LightCyclePreferenceFragmentCompat() { - lifeCycleDispatcher = new SupportFragmentLightCycleDispatcher<>(); + this.lifeCycleDispatcher = new SupportFragmentLightCycleDispatcher<>(); + this.binderHelper = new LightCycleBinderHelper(this); } @Override @@ -28,17 +30,10 @@ public void bind(SupportFragmentLightCycle lifeCycleComponent) { @Override public void onAttach(Activity activity) { super.onAttach(activity); - bindIfNecessary(); + binderHelper.bindIfNecessary(); lifeCycleDispatcher.onAttach(fragment(), activity); } - private void bindIfNecessary() { - if (!bound) { - LightCycles.bind(this); - bound = true; - } - } - @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); diff --git a/lightcycle-lib/src/main/java/com/soundcloud/lightcycle/LightCycleSupportDialogFragment.java b/lightcycle-lib/src/main/java/com/soundcloud/lightcycle/LightCycleSupportDialogFragment.java index c5ef2b8..24e4bbb 100644 --- a/lightcycle-lib/src/main/java/com/soundcloud/lightcycle/LightCycleSupportDialogFragment.java +++ b/lightcycle-lib/src/main/java/com/soundcloud/lightcycle/LightCycleSupportDialogFragment.java @@ -1,5 +1,8 @@ package com.soundcloud.lightcycle; +import com.soundcloud.lightcycle.util.LightCycleBinderHelper; +import com.soundcloud.lightcycle.util.Preconditions; + import android.app.Activity; import android.os.Bundle; import android.support.v4.app.DialogFragment; @@ -7,16 +10,15 @@ import android.view.MenuItem; import android.view.View; -import com.soundcloud.lightcycle.util.Preconditions; - public abstract class LightCycleSupportDialogFragment extends DialogFragment implements LightCycleDispatcher> { private final SupportFragmentLightCycleDispatcher lifeCycleDispatcher; - private boolean bound; + private final LightCycleBinderHelper binderHelper; public LightCycleSupportDialogFragment() { - lifeCycleDispatcher = new SupportFragmentLightCycleDispatcher<>(); + this.lifeCycleDispatcher = new SupportFragmentLightCycleDispatcher<>(); + this.binderHelper = new LightCycleBinderHelper(this); } @Override @@ -28,17 +30,10 @@ public void bind(SupportFragmentLightCycle lifeCycleComponent) { @Override public void onAttach(Activity activity) { super.onAttach(activity); - bindIfNecessary(); + binderHelper.bindIfNecessary(); lifeCycleDispatcher.onAttach(fragment(), activity); } - private void bindIfNecessary() { - if (!bound) { - LightCycles.bind(this); - bound = true; - } - } - @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); diff --git a/lightcycle-lib/src/main/java/com/soundcloud/lightcycle/LightCycleSupportFragment.java b/lightcycle-lib/src/main/java/com/soundcloud/lightcycle/LightCycleSupportFragment.java index d4acd40..811f8f1 100644 --- a/lightcycle-lib/src/main/java/com/soundcloud/lightcycle/LightCycleSupportFragment.java +++ b/lightcycle-lib/src/main/java/com/soundcloud/lightcycle/LightCycleSupportFragment.java @@ -1,20 +1,22 @@ package com.soundcloud.lightcycle; +import com.soundcloud.lightcycle.util.LightCycleBinderHelper; +import com.soundcloud.lightcycle.util.Preconditions; + import android.app.Activity; import android.os.Bundle; import android.support.v4.app.Fragment; import android.view.MenuItem; import android.view.View; -import com.soundcloud.lightcycle.util.Preconditions; - public abstract class LightCycleSupportFragment extends Fragment implements LightCycleDispatcher> { private final SupportFragmentLightCycleDispatcher lifeCycleDispatcher; - private boolean bound; + private final LightCycleBinderHelper binderHelper; public LightCycleSupportFragment() { - lifeCycleDispatcher = new SupportFragmentLightCycleDispatcher<>(); + this.lifeCycleDispatcher = new SupportFragmentLightCycleDispatcher<>(); + this.binderHelper = new LightCycleBinderHelper(this); } @Override @@ -26,17 +28,10 @@ public void bind(SupportFragmentLightCycle lifeCycleComponent) { @Override public void onAttach(Activity activity) { super.onAttach(activity); - bindIfNecessary(); + binderHelper.bindIfNecessary(); lifeCycleDispatcher.onAttach(fragment(), activity); } - private void bindIfNecessary() { - if (!bound) { - LightCycles.bind(this); - bound = true; - } - } - @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); diff --git a/lightcycle-lib/src/main/java/com/soundcloud/lightcycle/SupportFragmentLightCycleDispatcher.java b/lightcycle-lib/src/main/java/com/soundcloud/lightcycle/SupportFragmentLightCycleDispatcher.java index 815a604..ea59817 100644 --- a/lightcycle-lib/src/main/java/com/soundcloud/lightcycle/SupportFragmentLightCycleDispatcher.java +++ b/lightcycle-lib/src/main/java/com/soundcloud/lightcycle/SupportFragmentLightCycleDispatcher.java @@ -1,5 +1,6 @@ package com.soundcloud.lightcycle; +import com.soundcloud.lightcycle.util.LightCycleBinderHelper; import com.soundcloud.lightcycle.util.Preconditions; import android.app.Activity; @@ -14,10 +15,13 @@ public class SupportFragmentLightCycleDispatcher implements LightCycleDispatcher>, SupportFragmentLightCycle { + private final Set> fragmentLightCycles; + private final LightCycleBinderHelper binderHelper; public SupportFragmentLightCycleDispatcher() { this.fragmentLightCycles = new HashSet<>(); + this.binderHelper = new LightCycleBinderHelper(this); } @Override @@ -28,7 +32,7 @@ public void bind(SupportFragmentLightCycle lightCycle) { @Override public void onAttach(T fragment, Activity activity) { - LightCycles.bind(this); + binderHelper.bindIfNecessary(); for (SupportFragmentLightCycle component : fragmentLightCycles) { component.onAttach(fragment, activity); } diff --git a/lightcycle-lib/src/main/java/com/soundcloud/lightcycle/util/LightCycleBinderHelper.java b/lightcycle-lib/src/main/java/com/soundcloud/lightcycle/util/LightCycleBinderHelper.java new file mode 100644 index 0000000..d3d3bad --- /dev/null +++ b/lightcycle-lib/src/main/java/com/soundcloud/lightcycle/util/LightCycleBinderHelper.java @@ -0,0 +1,21 @@ +package com.soundcloud.lightcycle.util; + +import com.soundcloud.lightcycle.LightCycleDispatcher; +import com.soundcloud.lightcycle.LightCycles; + +public class LightCycleBinderHelper { + + private final LightCycleDispatcher dispatcher; + private boolean isBound = false; + + public LightCycleBinderHelper(LightCycleDispatcher dispatcher) { + this.dispatcher = dispatcher; + } + + public void bindIfNecessary() { + if (!isBound) { + LightCycles.bind(dispatcher); + isBound = true; + } + } +}