diff --git a/README.md b/README.md index 821adfbf..b673634b 100644 --- a/README.md +++ b/README.md @@ -172,7 +172,6 @@ public class HelloWorldPresenter extends TiPresenter { public static final TiConfiguration PRESENTER_CONFIG = new TiConfiguration.Builder() .setRetainPresenterEnabled(true) - .setUseStaticSaviorToRetain(true) .setCallOnMainThreadInterceptorEnabled(true) .setDistinctUntilChangedInterceptorEnabled(true) .build(); diff --git a/plugin/src/main/java/net/grandcentrix/thirtyinch/plugin/TiActivityPlugin.java b/plugin/src/main/java/net/grandcentrix/thirtyinch/plugin/TiActivityPlugin.java index 142cdf29..29e569f4 100644 --- a/plugin/src/main/java/net/grandcentrix/thirtyinch/plugin/TiActivityPlugin.java +++ b/plugin/src/main/java/net/grandcentrix/thirtyinch/plugin/TiActivityPlugin.java @@ -32,7 +32,6 @@ import net.grandcentrix.thirtyinch.internal.TiPresenterProvider; import net.grandcentrix.thirtyinch.internal.TiViewProvider; import net.grandcentrix.thirtyinch.internal.UiThreadExecutor; -import net.grandcentrix.thirtyinch.util.AndroidDeveloperOptions; import net.grandcentrix.thirtyinch.util.AnnotationUtil; import android.app.Activity; @@ -77,7 +76,7 @@ public class TiActivityPlugin

, V extends TiView> extend */ public TiActivityPlugin(@NonNull final TiPresenterProvider

presenterProvider) { mDelegate = new TiActivityDelegate<>(this, this, presenterProvider, this, - PresenterSavior.INSTANCE); + PresenterSavior.getInstance()); } @NonNull @@ -116,17 +115,6 @@ public final P getPresenter() { return mDelegate.getPresenter(); } - @SuppressWarnings("unchecked") - @Nullable - @Override - public final P getRetainedPresenter() { - final Object nci = getLastNonConfigurationInstance(NCI_KEY_PRESENTER); - if (nci != null) { - return (P) nci; - } - return null; - } - @Override public final Executor getUiThreadExecutor() { return mUiThreadExecutor; @@ -152,8 +140,8 @@ public final boolean isActivityFinishing() { } @Override - public final boolean isDontKeepActivitiesEnabled() { - return AndroidDeveloperOptions.isDontKeepActivitiesEnabled(getActivity()); + public Activity getHostingActivity() { + return getActivity(); } @CallSuper diff --git a/plugin/src/main/java/net/grandcentrix/thirtyinch/plugin/TiFragmentPlugin.java b/plugin/src/main/java/net/grandcentrix/thirtyinch/plugin/TiFragmentPlugin.java index 5deec439..28e90687 100644 --- a/plugin/src/main/java/net/grandcentrix/thirtyinch/plugin/TiFragmentPlugin.java +++ b/plugin/src/main/java/net/grandcentrix/thirtyinch/plugin/TiFragmentPlugin.java @@ -32,13 +32,14 @@ import net.grandcentrix.thirtyinch.internal.TiPresenterProvider; import net.grandcentrix.thirtyinch.internal.TiViewProvider; import net.grandcentrix.thirtyinch.internal.UiThreadExecutor; -import net.grandcentrix.thirtyinch.util.AndroidDeveloperOptions; import net.grandcentrix.thirtyinch.util.AnnotationUtil; +import android.app.Activity; import android.os.Bundle; import android.support.annotation.CallSuper; import android.support.annotation.NonNull; import android.support.annotation.Nullable; +import android.support.v4.app.BackstackReader; import android.support.v4.app.Fragment; import android.view.LayoutInflater; import android.view.View; @@ -78,7 +79,7 @@ public class TiFragmentPlugin

, V extends TiView> extend */ public TiFragmentPlugin(@NonNull final TiPresenterProvider

presenterProvider) { mDelegate = new TiFragmentDelegate<>(this, this, presenterProvider, this, - PresenterSavior.INSTANCE); + PresenterSavior.getInstance()); } @NonNull @@ -87,12 +88,17 @@ public final Removable addBindViewInterceptor(@NonNull final BindViewInterceptor return mDelegate.addBindViewInterceptor(interceptor); } + @Override + public Activity getHostingActivity() { + return getFragment().getActivity(); + } + /** * @return the cached result of {@link BindViewInterceptor#intercept(TiView)} */ @Nullable @Override - public final V getInterceptedViewOf(@NonNull final BindViewInterceptor interceptor) { + public final V getInterceptedViewOf(@NonNull final BindViewInterceptor interceptor) { return mDelegate.getInterceptedViewOf(interceptor); } @@ -131,11 +137,6 @@ public final void invalidateView() { mDelegate.invalidateView(); } - @Override - public final boolean isDontKeepActivitiesEnabled() { - return AndroidDeveloperOptions.isDontKeepActivitiesEnabled(getFragment().getActivity()); - } - @Override public final boolean isFragmentAdded() { return getFragment().isAdded(); @@ -146,6 +147,11 @@ public final boolean isFragmentDetached() { return getFragment().isDetached(); } + @Override + public boolean isFragmentRemoving() { + return getFragment().isRemoving(); + } + @Override public final boolean isHostingActivityChangingConfigurations() { return getFragment().getActivity().isChangingConfigurations(); @@ -156,6 +162,11 @@ public final boolean isHostingActivityFinishing() { return getFragment().getActivity().isFinishing(); } + @Override + public boolean isFragmentInBackstack() { + return BackstackReader.isInBackStack(getFragment()); + } + @CallSuper @Override public void onCreate(final Bundle savedInstanceState) { @@ -236,11 +247,6 @@ public V provideView() { } } - @Override - public final void setFragmentRetainInstance(final boolean retain) { - getFragment().setRetainInstance(retain); - } - @Override public String toString() { String presenter = mDelegate.getPresenter() == null ? "null" : diff --git a/sample/src/main/AndroidManifest.xml b/sample/src/main/AndroidManifest.xml index 37fda4c0..0f75b76a 100644 --- a/sample/src/main/AndroidManifest.xml +++ b/sample/src/main/AndroidManifest.xml @@ -16,6 +16,10 @@ + + + + diff --git a/sample/src/main/java/net/grandcentrix/thirtyinch/sample/HelloWorldActivity.java b/sample/src/main/java/net/grandcentrix/thirtyinch/sample/HelloWorldActivity.java index 0566822d..5e62f821 100644 --- a/sample/src/main/java/net/grandcentrix/thirtyinch/sample/HelloWorldActivity.java +++ b/sample/src/main/java/net/grandcentrix/thirtyinch/sample/HelloWorldActivity.java @@ -19,9 +19,14 @@ import com.jakewharton.rxbinding.view.RxView; import net.grandcentrix.thirtyinch.TiActivity; +import net.grandcentrix.thirtyinch.sample.fragmentlifecycle.FragmentLifecycleActivity; +import net.grandcentrix.thirtyinch.sample.fragmentlifecycle.viewpager.LifecycleViewPagerActivity; +import android.content.Intent; import android.os.Bundle; import android.support.annotation.NonNull; +import android.view.Menu; +import android.view.MenuItem; import android.view.View; import android.widget.Button; import android.widget.TextView; @@ -42,6 +47,25 @@ public Observable onButtonClicked() { return RxView.clicks(mButton); } + @Override + public boolean onCreateOptionsMenu(final Menu menu) { + getMenuInflater().inflate(R.menu.menu_hello_world, menu); + return true; + } + + @Override + public boolean onOptionsItemSelected(final MenuItem item) { + switch (item.getItemId()) { + case R.id.start_fragment_lifecycle_test: + startActivity(new Intent(this, FragmentLifecycleActivity.class)); + return true; + case R.id.start_viewpager_test: + startActivity(new Intent(this, LifecycleViewPagerActivity.class)); + return true; + } + return false; + } + @NonNull @Override public HelloWorldPresenter providePresenter() { @@ -80,4 +104,5 @@ public void onClick(final View v) { } }); } + } diff --git a/sample/src/main/java/net/grandcentrix/thirtyinch/sample/fragmentlifecycle/FragmentLifecycleActivity.java b/sample/src/main/java/net/grandcentrix/thirtyinch/sample/fragmentlifecycle/FragmentLifecycleActivity.java new file mode 100644 index 00000000..96833a87 --- /dev/null +++ b/sample/src/main/java/net/grandcentrix/thirtyinch/sample/fragmentlifecycle/FragmentLifecycleActivity.java @@ -0,0 +1,183 @@ +package net.grandcentrix.thirtyinch.sample.fragmentlifecycle; + +import net.grandcentrix.thirtyinch.sample.R; +import net.grandcentrix.thirtyinch.sample.util.AndroidDeveloperOptions; + +import android.os.Bundle; +import android.support.v4.app.Fragment; +import android.support.v4.app.FragmentManager; +import android.support.v4.app.FragmentTransaction; +import android.support.v7.app.AppCompatActivity; +import android.support.v7.widget.SwitchCompat; +import android.util.Log; +import android.view.View; +import android.widget.TextView; +import android.widget.Toast; + +import java.util.concurrent.TimeUnit; + +import rx.Observable; + +public class FragmentLifecycleActivity extends AppCompatActivity { + + static int fragmentLifecycleActivityInstanceCount = -1; + + private final String TAG = this.getClass().getSimpleName() + + "@" + Integer.toHexString(this.hashCode()); + + private SwitchCompat mSwitchAddToBackStack; + + private SwitchCompat mSwitchRetainPresenterInstance; + + public void addFragmentA(View view) { + final TestFragmentA fragment = new TestFragmentA(); + Log.v(TAG, "adding FragmentA"); + addFragment(fragment); + } + + public void addFragmentB(View view) { + final TestFragmentB fragment = new TestFragmentB(); + Log.v(TAG, "adding FragmentB"); + addFragment(fragment); + } + + public void detachFragmentAndAddAgain(View view) { + final Fragment fragment = getSupportFragmentManager() + .findFragmentById(R.id.fragment_placeholder); + if (fragment != null) { + //remove fragment + Log.v(TAG, "// When the Fragment is removed."); + getSupportFragmentManager().beginTransaction().remove(fragment).commitNow(); + + Log.v(TAG, "// When the Fragment get added again to the Activity."); + //add after delay again. Don't use the same transaction + Observable.just(null).delay(1, TimeUnit.SECONDS) + .subscribe(o -> addFragment(fragment)); + } else { + Toast.makeText(this, "no fragment found", Toast.LENGTH_SHORT).show(); + } + } + + @Override + public void finish() { + super.finish(); + Log.v(TAG, "// When the Activity gets finished"); + } + + public void finishActivity(View view) { + Log.v(TAG, "finishing Activity"); + finish(); + } + + @Override + public void onBackPressed() { + Log.v(TAG, "// When the back button gets pressed"); + final FragmentManager fragmentManager = getSupportFragmentManager(); + if (fragmentManager.getBackStackEntryCount() > 0) { + Log.v(TAG, "// When the top most fragment gets popped"); + fragmentManager.popBackStack(); + } else { + super.onBackPressed(); + } + } + + public void recreateActivity(View view) { + Log.v(TAG, "// And when the Activity is changing its configurations."); + recreate(); + } + + public void removeFragmentA(View view) { + final Fragment fragment = getSupportFragmentManager() + .findFragmentById(R.id.fragment_placeholder); + if (fragment instanceof TestFragmentA) { + Log.v(TAG, "remove FragmentA"); + getSupportFragmentManager().beginTransaction() + .remove(fragment) + .commitNow(); + } + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + if (savedInstanceState == null) { + //started for the first time, reset all counters + fragmentLifecycleActivityInstanceCount = -1; + TestFragment.testFragmentInstanceCount = -1; + } + + fragmentLifecycleActivityInstanceCount++; + setContentView(R.layout.activity_fragment_lifecycle); + FragmentManager.enableDebugLogging(true); + Log.v(TAG, "onCreate of " + this); + + mSwitchAddToBackStack = (SwitchCompat) findViewById(R.id.switch_add_back_stack); + mSwitchRetainPresenterInstance = (SwitchCompat) findViewById( + R.id.switch_retain_presenter_instance); + final TextView textDontKeepActivities = (TextView) findViewById( + R.id.text_dont_keep_activities); + textDontKeepActivities.setText( + isDontKeepActivities() ? R.string.dont_keep_activities_enabled + : R.string.dont_keep_activities_disabled); + + Log.v(TAG, "// A new Activity gets created by the Android Framework."); + Log.v(TAG, "final HostingActivity hostingActivity" + fragmentLifecycleActivityInstanceCount + + " = new HostingActivity();"); + } + + @Override + protected void onDestroy() { + super.onDestroy(); + + Log.v(TAG, "onDestroy"); + + Log.v(TAG, "// hostingActivity" + fragmentLifecycleActivityInstanceCount + + " got destroyed."); + } + + @Override + protected void onPause() { + super.onPause(); + Log.d(TAG, "onPause()"); + } + + @Override + protected void onSaveInstanceState(final Bundle outState) { + super.onSaveInstanceState(outState); + Log.d(TAG, "onSaveInstanceState(Bundle)"); + } + + private void addFragment(final Fragment fragment) { + final FragmentManager fragmentManager = getSupportFragmentManager(); + final FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction(); + boolean retain = isRetainPresenterInstance(); + if (retain) { + Log.v(TAG, "retaining presenter"); + } + final Bundle bundle = new Bundle(); + bundle.putBoolean(TestFragment.RETAIN_PRESENTER, retain); + fragment.setArguments(bundle); + + fragmentTransaction.replace(R.id.fragment_placeholder, fragment); + if (isAddToBackStack()) { + Log.v(TAG, "adding transaction to the back stack"); + fragmentTransaction.addToBackStack(null); + } + final int backStackId = fragmentTransaction.commit(); + if (backStackId >= 0) { + Log.v(TAG, "Back stack ID: " + String.valueOf(backStackId)); + } + } + + private boolean isAddToBackStack() { + return mSwitchAddToBackStack.isChecked(); + } + + private boolean isDontKeepActivities() { + return AndroidDeveloperOptions.isDontKeepActivitiesEnabled(this); + } + + private boolean isRetainPresenterInstance() { + return mSwitchRetainPresenterInstance.isChecked(); + } +} diff --git a/sample/src/main/java/net/grandcentrix/thirtyinch/sample/fragmentlifecycle/TestFragment.java b/sample/src/main/java/net/grandcentrix/thirtyinch/sample/fragmentlifecycle/TestFragment.java new file mode 100644 index 00000000..23975a44 --- /dev/null +++ b/sample/src/main/java/net/grandcentrix/thirtyinch/sample/fragmentlifecycle/TestFragment.java @@ -0,0 +1,398 @@ +package net.grandcentrix.thirtyinch.sample.fragmentlifecycle; + +import net.grandcentrix.thirtyinch.TiConfiguration; +import net.grandcentrix.thirtyinch.TiFragment; +import net.grandcentrix.thirtyinch.sample.R; + +import android.content.Context; +import android.content.Intent; +import android.content.res.Configuration; +import android.os.Bundle; +import android.support.annotation.LayoutRes; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.v4.app.BackstackReader; +import android.support.v4.app.Fragment; +import android.support.v4.app.FragmentActivity; +import android.util.AttributeSet; +import android.util.Log; +import android.view.ContextMenu; +import android.view.LayoutInflater; +import android.view.Menu; +import android.view.MenuInflater; +import android.view.MenuItem; +import android.view.View; +import android.view.ViewGroup; +import android.view.animation.Animation; +import android.widget.TextView; + +import java.util.UUID; + +import rx.subjects.PublishSubject; + +import static net.grandcentrix.thirtyinch.sample.fragmentlifecycle.FragmentLifecycleActivity.fragmentLifecycleActivityInstanceCount; + +public abstract class TestFragment + extends TiFragment + implements TestPresenter.TestView { + + public static final String RETAIN_PRESENTER = "retain"; + + static int testFragmentInstanceCount = -1; + + private final String TAG = this.getClass().getSimpleName() + + "@" + Integer.toHexString(this.hashCode()); + + private int instanceNum = Integer.MIN_VALUE; + + private PublishSubject mAddedState = PublishSubject.create(); + + private PublishSubject mDetachedState = PublishSubject.create(); + + private PublishSubject mInBackstackState = PublishSubject.create(); + + private PublishSubject mIsActivityChangingConfigState = PublishSubject.create(); + + private PublishSubject mIsActivityFinishingState = PublishSubject.create(); + + private PublishSubject mRemovingState = PublishSubject.create(); + + private String mUuid; + + public TestFragment() { + Log.v(TAG, this + " constructor called"); + + testFragmentInstanceCount++; + instanceNum = testFragmentInstanceCount; + } + + @Override + public void onActivityCreated(@Nullable final Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); + Log.v(TAG, "onActivityCreated"); + } + + @Override + public void onActivityResult(final int requestCode, final int resultCode, final Intent data) { + super.onActivityResult(requestCode, resultCode, data); + Log.v(TAG, "onActivityResult"); + } + + @Override + public void onAttach(final Context context) { + mAddedState.startWith(false).distinctUntilChanged().skip(1).subscribe(added -> { + Log.d(TAG, "fragment" + instanceNum + ".setAdded(" + added + ")"); + }); + mDetachedState.startWith(false).distinctUntilChanged().skip(1).subscribe(detached -> { + Log.d(TAG, "fragment" + instanceNum + ".setDetached(" + detached + ")"); + }); + mRemovingState.startWith(false).distinctUntilChanged().skip(1).subscribe(removing -> { + Log.d(TAG, "fragment" + instanceNum + ".setRemoving(" + removing + ")"); + }); + mInBackstackState.startWith(false).distinctUntilChanged().skip(1).subscribe(inBackstack -> { + Log.d(TAG, + "fragment" + instanceNum + ".setInBackstack(" + inBackstack + ")"); + }); + + mIsActivityChangingConfigState.startWith(false).distinctUntilChanged().skip(1) + .subscribe(changing -> { + Log.d(TAG, + "hostingActivity" + fragmentLifecycleActivityInstanceCount + "" + + ".setChangingConfiguration(" + changing + ");"); + }); + mIsActivityFinishingState.startWith(false).distinctUntilChanged().skip(1) + .subscribe(finishing -> { + Log.d(TAG, + "hostingActivity" + fragmentLifecycleActivityInstanceCount + "" + + ".setFinishing(" + finishing + ");"); + }); + + printState(); + super.onAttach(context); + Log.v(TAG, "onAttach(" + context + ")"); + printState(); + } + + @Override + public void onAttachFragment(final Fragment childFragment) { + super.onAttachFragment(childFragment); + printState(); + Log.v(TAG, "onAttachFragment"); + } + + @Override + public void onConfigurationChanged(final Configuration newConfig) { + super.onConfigurationChanged(newConfig); + Log.v(TAG, "onConfigurationChanged"); + } + + @Override + public boolean onContextItemSelected(final MenuItem item) { + Log.v(TAG, "onContextItemSelected"); + return super.onContextItemSelected(item); + } + + @Override + public void onCreate(@Nullable final Bundle savedInstanceState) { + printState(); + super.onCreate(savedInstanceState); + Log.v(TAG, "onCreate(" + savedInstanceState + ")"); + printState(); + if (savedInstanceState != null) { + mUuid = savedInstanceState.getString("uuid"); + Log.v(TAG, "RESTORED " + mUuid); + } + if (mUuid == null) { + mUuid = UUID.randomUUID().toString(); + Log.v(TAG, "CREATED " + mUuid); + } + + if (savedInstanceState == null) { + Log.d(TAG, "fragment" + instanceNum + ".onCreate(null);"); + } else { + Log.d(TAG, "fragment" + instanceNum + + ".onCreate(savedInstanceState);"); + } + } + + @Override + public Animation onCreateAnimation(final int transit, final boolean enter, final int nextAnim) { + Log.v(TAG, "onCreateAnimation"); + return super.onCreateAnimation(transit, enter, nextAnim); + } + + @Override + public void onCreateContextMenu(final ContextMenu menu, final View v, + final ContextMenu.ContextMenuInfo menuInfo) { + super.onCreateContextMenu(menu, v, menuInfo); + Log.v(TAG, "onCreateContextMenu"); + } + + @Override + public void onCreateOptionsMenu(final Menu menu, final MenuInflater inflater) { + super.onCreateOptionsMenu(menu, inflater); + Log.v(TAG, "onCreateOptionsMenu"); + } + + @Nullable + @Override + public View onCreateView(final LayoutInflater inflater, @Nullable final ViewGroup container, + @Nullable final Bundle savedInstanceState) { + super.onCreateView(inflater, container, savedInstanceState); + printState(); + Log.v(TAG, + "onCreateView() called with: inflater = [" + inflater + "], container = [" + + container + "], savedInstanceState = [" + savedInstanceState + "]"); + if (savedInstanceState == null) { + Log.d(TAG, "fragment" + instanceNum + + ".onCreateView(inflater, null, null);"); + } else { + Log.d(TAG, "fragment" + instanceNum + + ".onCreateView(inflater, null, savedInstanceState);"); + } + + return inflater.inflate(getLayoutResId(), container, false); + } + + @Override + public void onDestroy() { + printState(); + super.onDestroy(); + Log.v(TAG, "onDestroy"); + Log.d(TAG, "fragment" + instanceNum + ".onDestroy();"); + printState(); + Log.v("FragmentManager", "DESTROYED " + mUuid); + } + + @Override + public void onDestroyOptionsMenu() { + super.onDestroyOptionsMenu(); + Log.v(TAG, "onDestroyOptionsMenu"); + } + + @Override + public void onDestroyView() { + printState(); + super.onDestroyView(); + Log.v(TAG, "onDestroyView"); + printState(); + + Log.d(TAG, "fragment" + instanceNum + ".onDestroyView();"); + } + + @Override + public void onDetach() { + super.onDetach(); + printState(); + Log.v(TAG, "onDetach"); + printState(); + + mAddedState.onCompleted(); + mDetachedState.onCompleted(); + mRemovingState.onCompleted(); + mIsActivityChangingConfigState.onCompleted(); + mIsActivityFinishingState.onCompleted(); + } + + @Override + public void onHiddenChanged(final boolean hidden) { + super.onHiddenChanged(hidden); + Log.v(TAG, "onHiddenChanged"); + } + + @Override + public void onInflate(final Context context, final AttributeSet attrs, + final Bundle savedInstanceState) { + super.onInflate(context, attrs, savedInstanceState); + Log.v(TAG, "onInflate"); + } + + @Override + public void onLowMemory() { + super.onLowMemory(); + Log.v(TAG, "onLowMemory"); + printState(); + } + + @Override + public void onMultiWindowModeChanged(final boolean isInMultiWindowMode) { + super.onMultiWindowModeChanged(isInMultiWindowMode); + Log.v(TAG, "onMultiWindowModeChanged"); + printState(); + } + + @Override + public boolean onOptionsItemSelected(final MenuItem item) { + Log.v(TAG, "onOptionsItemSelected"); + return super.onOptionsItemSelected(item); + } + + @Override + public void onOptionsMenuClosed(final Menu menu) { + super.onOptionsMenuClosed(menu); + Log.v(TAG, "onOptionsMenuClosed"); + } + + @Override + public void onPause() { + printState(); + super.onPause(); + Log.v(TAG, "onPause()"); + printState(); + } + + @Override + public void onPictureInPictureModeChanged(final boolean isInPictureInPictureMode) { + super.onPictureInPictureModeChanged(isInPictureInPictureMode); + Log.v(TAG, "onPictureInPictureModeChanged"); + printState(); + } + + @Override + public void onPrepareOptionsMenu(final Menu menu) { + super.onPrepareOptionsMenu(menu); + Log.v(TAG, "onPrepareOptionsMenu"); + } + + @Override + public void onRequestPermissionsResult(final int requestCode, + @NonNull final String[] permissions, + @NonNull final int[] grantResults) { + super.onRequestPermissionsResult(requestCode, permissions, grantResults); + Log.v(TAG, "onRequestPermissionsResult"); + printState(); + } + + @Override + public void onResume() { + printState(); + super.onResume(); + Log.v(TAG, "onResume"); + printState(); + } + + @Override + public void onSaveInstanceState(final Bundle outState) { + super.onSaveInstanceState(outState); + printState(); + + outState.putString("uuid", mUuid); + + Log.d(TAG, "fragment" + instanceNum + ".onSaveInstanceState(outState);"); + printState(); + } + + @Override + public void onStart() { + printState(); + super.onStart(); + Log.d(TAG, "fragment" + instanceNum + ".onStart();"); + printState(); + } + + @Override + public void onStop() { + printState(); + super.onStop(); + Log.d(TAG, "fragment" + instanceNum + ".onStop();"); + printState(); + } + + @Override + public void onViewCreated(final View view, @Nullable final Bundle savedInstanceState) { + printState(); + super.onViewCreated(view, savedInstanceState); + Log.v(TAG, "onViewCreated"); + printState(); + + final TextView fragmentTag = (TextView) view.findViewById(R.id.sample_text); + fragmentTag.setText(TAG); + } + + @Override + public void onViewStateRestored(@Nullable final Bundle savedInstanceState) { + super.onViewStateRestored(savedInstanceState); + Log.v(TAG, "onViewStateRestored"); + } + + @NonNull + @Override + public TestPresenter providePresenter() { + boolean retain = false; + if (getArguments() != null) { + retain = getArguments().getBoolean(RETAIN_PRESENTER, false); + } + + final TiConfiguration config = new TiConfiguration.Builder() + .setRetainPresenterEnabled(retain) + .build(); + + final TestPresenter presenter = new TestPresenter(config, getClass().getSimpleName()); + Log.d(TAG, "created " + presenter); + Log.v(TAG, "retain presenter " + retain + ", " + presenter); + + return presenter; + } + + @Override + protected void finalize() throws Throwable { + super.finalize(); + Log.v(TAG, "GCed " + this + ", uuid: " + this.mUuid); + } + + @LayoutRes + abstract int getLayoutResId(); + + private void printState() { + mAddedState.onNext(isAdded()); + mDetachedState.onNext(isDetached()); + mRemovingState.onNext(isRemoving()); + mInBackstackState.onNext(BackstackReader.isInBackStack(this)); + + final FragmentActivity activity = getActivity(); + if (activity != null) { + mIsActivityFinishingState.onNext(activity.isFinishing()); + mIsActivityChangingConfigState.onNext(activity.isChangingConfigurations()); + } + } +} diff --git a/sample/src/main/java/net/grandcentrix/thirtyinch/sample/fragmentlifecycle/TestFragmentA.java b/sample/src/main/java/net/grandcentrix/thirtyinch/sample/fragmentlifecycle/TestFragmentA.java new file mode 100644 index 00000000..2027fcfa --- /dev/null +++ b/sample/src/main/java/net/grandcentrix/thirtyinch/sample/fragmentlifecycle/TestFragmentA.java @@ -0,0 +1,11 @@ +package net.grandcentrix.thirtyinch.sample.fragmentlifecycle; + +import net.grandcentrix.thirtyinch.sample.R; + +public class TestFragmentA extends TestFragment { + + @Override + int getLayoutResId() { + return R.layout.fragment_a_test; + } +} diff --git a/sample/src/main/java/net/grandcentrix/thirtyinch/sample/fragmentlifecycle/TestFragmentB.java b/sample/src/main/java/net/grandcentrix/thirtyinch/sample/fragmentlifecycle/TestFragmentB.java new file mode 100644 index 00000000..91dcef92 --- /dev/null +++ b/sample/src/main/java/net/grandcentrix/thirtyinch/sample/fragmentlifecycle/TestFragmentB.java @@ -0,0 +1,11 @@ +package net.grandcentrix.thirtyinch.sample.fragmentlifecycle; + +import net.grandcentrix.thirtyinch.sample.R; + +public class TestFragmentB extends TestFragment { + + @Override + int getLayoutResId() { + return R.layout.fragment_b_test; + } +} diff --git a/thirtyinch/src/main/java/net/grandcentrix/thirtyinch/internal/PresenterNonConfigurationInstance.java b/sample/src/main/java/net/grandcentrix/thirtyinch/sample/fragmentlifecycle/TestPresenter.java similarity index 53% rename from thirtyinch/src/main/java/net/grandcentrix/thirtyinch/internal/PresenterNonConfigurationInstance.java rename to sample/src/main/java/net/grandcentrix/thirtyinch/sample/fragmentlifecycle/TestPresenter.java index a9d2bdaa..bd86b2ca 100644 --- a/thirtyinch/src/main/java/net/grandcentrix/thirtyinch/internal/PresenterNonConfigurationInstance.java +++ b/sample/src/main/java/net/grandcentrix/thirtyinch/sample/fragmentlifecycle/TestPresenter.java @@ -13,27 +13,33 @@ * limitations under the License. */ -package net.grandcentrix.thirtyinch.internal; +package net.grandcentrix.thirtyinch.sample.fragmentlifecycle; + +import net.grandcentrix.thirtyinch.TiConfiguration; import net.grandcentrix.thirtyinch.TiPresenter; +import net.grandcentrix.thirtyinch.TiView; + +public class TestPresenter extends TiPresenter { -public class PresenterNonConfigurationInstance

{ + public interface TestView extends TiView { - private Object OtherNonConfigurationInstance; + } - private P mPresenter; + private final String mName; - public PresenterNonConfigurationInstance(final P presenter, - final Object otherNonConfigurationInstance) { - mPresenter = presenter; - OtherNonConfigurationInstance = otherNonConfigurationInstance; + public TestPresenter(final String name) { + mName = name; } - public Object getOtherNonConfigurationInstance() { - return OtherNonConfigurationInstance; + public TestPresenter(final TiConfiguration config, final String name) { + super(config); + + mName = name; } - public P getPresenter() { - return mPresenter; + @Override + public String toString() { + return mName + "#" + super.toString(); } } diff --git a/sample/src/main/java/net/grandcentrix/thirtyinch/sample/fragmentlifecycle/viewpager/LifecycleViewPagerActivity.java b/sample/src/main/java/net/grandcentrix/thirtyinch/sample/fragmentlifecycle/viewpager/LifecycleViewPagerActivity.java new file mode 100644 index 00000000..6e24b44a --- /dev/null +++ b/sample/src/main/java/net/grandcentrix/thirtyinch/sample/fragmentlifecycle/viewpager/LifecycleViewPagerActivity.java @@ -0,0 +1,20 @@ +package net.grandcentrix.thirtyinch.sample.fragmentlifecycle.viewpager; + +import android.os.Bundle; +import android.support.annotation.Nullable; +import android.support.v4.view.ViewPager; +import android.support.v7.app.AppCompatActivity; +import android.view.View; + +public class LifecycleViewPagerActivity extends AppCompatActivity { + + @Override + public void onCreate(@Nullable final Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + final ViewPager viewPager = new ViewPager(this); + viewPager.setId(View.generateViewId()); + setContentView(viewPager); + + viewPager.setAdapter(new PagerAdapter(getSupportFragmentManager())); + } +} diff --git a/sample/src/main/java/net/grandcentrix/thirtyinch/sample/fragmentlifecycle/viewpager/PagerAdapter.java b/sample/src/main/java/net/grandcentrix/thirtyinch/sample/fragmentlifecycle/viewpager/PagerAdapter.java new file mode 100644 index 00000000..cc8c4e59 --- /dev/null +++ b/sample/src/main/java/net/grandcentrix/thirtyinch/sample/fragmentlifecycle/viewpager/PagerAdapter.java @@ -0,0 +1,24 @@ +package net.grandcentrix.thirtyinch.sample.fragmentlifecycle.viewpager; + +import net.grandcentrix.thirtyinch.sample.fragmentlifecycle.TestFragmentA; + +import android.support.v4.app.Fragment; +import android.support.v4.app.FragmentManager; +import android.support.v4.app.FragmentPagerAdapter; + +class PagerAdapter extends FragmentPagerAdapter { + + public PagerAdapter(final FragmentManager fm) { + super(fm); + } + + @Override + public int getCount() { + return 4; + } + + @Override + public Fragment getItem(final int position) { + return new TestFragmentA(); + } +} diff --git a/thirtyinch/src/main/java/net/grandcentrix/thirtyinch/util/AndroidDeveloperOptions.java b/sample/src/main/java/net/grandcentrix/thirtyinch/sample/util/AndroidDeveloperOptions.java similarity index 96% rename from thirtyinch/src/main/java/net/grandcentrix/thirtyinch/util/AndroidDeveloperOptions.java rename to sample/src/main/java/net/grandcentrix/thirtyinch/sample/util/AndroidDeveloperOptions.java index e1667836..072b8a31 100644 --- a/thirtyinch/src/main/java/net/grandcentrix/thirtyinch/util/AndroidDeveloperOptions.java +++ b/sample/src/main/java/net/grandcentrix/thirtyinch/sample/util/AndroidDeveloperOptions.java @@ -13,7 +13,7 @@ * limitations under the License. */ -package net.grandcentrix.thirtyinch.util; +package net.grandcentrix.thirtyinch.sample.util; import android.content.Context; import android.os.Build; diff --git a/sample/src/main/res/layout/activity_fragment_lifecycle.xml b/sample/src/main/res/layout/activity_fragment_lifecycle.xml new file mode 100644 index 00000000..5e3c598a --- /dev/null +++ b/sample/src/main/res/layout/activity_fragment_lifecycle.xml @@ -0,0 +1,105 @@ + + + + + + + + + + + + + + + +