Compare commits

..

9 Commits

Author SHA1 Message Date
Eric Kuck fff9f76e8a Version bump 2016-03-31 14:12:23 -05:00
Eric Kuck bcc8f47856 Fixed tests to work with corrected lifecycle 2016-03-30 18:35:52 -05:00
Eric Kuck 61d68a9c6c Tweaks to ensure lifecycle callback chain remains intact when the activity is destroyed unexpectedly 2016-03-30 18:32:05 -05:00
Eric Kuck 5e7258973e Tweaks to ensure lifecycle callback chain remains intact when the activity is destroyed unexpectedly 2016-03-30 18:30:23 -05:00
Eric Kuck 194696e9cb Added a method for animating setting the root controller 2016-03-30 12:43:13 -05:00
Eric Kuck 5130909efc Fixed readme's controller implementation 2016-03-28 22:30:43 -05:00
Eric Kuck 7874c4f72d Typo fix 2016-03-26 19:21:42 -05:00
Eric Kuck 8399868a63 Minor lifecycle bug fixes 2016-03-26 19:19:02 -05:00
Eric Kuck 3e97e7f8a8 Minor demo app cleanup 2016-03-23 09:27:36 -05:00
11 changed files with 121 additions and 66 deletions
+5 -5
View File
@@ -20,14 +20,14 @@ Conductor is architecture-agnostic and does not try to force any design decision
## Installation
```gradle
compile 'com.bluelinelabs:conductor:1.0.4'
compile 'com.bluelinelabs:conductor:1.0.5'
// If you want the components that go along with
// Android's support libraries (currently just a PagerAdapter):
compile 'com.bluelinelabs:conductor-support:1.0.4'
compile 'com.bluelinelabs:conductor-support:1.0.5'
// If you want RxJava/RxAndroid lifecycle support:
compile 'com.bluelinelabs:conductor-rxlifecycle:1.0.4'
compile 'com.bluelinelabs:conductor-rxlifecycle:1.0.5'
```
## Components to Know
@@ -78,8 +78,8 @@ public class MainActivity extends Activity {
public class HomeController extends Controller {
@Override
protected int layoutId() {
return R.layout.controller_overlay;
protected View inflateView(@NonNull LayoutInflater inflater, @NonNull ViewGroup container) {
return inflater.inflate(R.layout.controller_home, container, false);
}
@Override
@@ -67,10 +67,12 @@ class Backstack implements Iterable<RouterTransaction> {
mBackStack.push(transaction);
}
public void popAll() {
public List<RouterTransaction> popAll() {
List<RouterTransaction> list = new ArrayList<>();
while (!isEmpty()) {
pop();
list.add(pop());
}
return list;
}
public void saveInstanceState(Bundle outState) {
@@ -43,11 +43,12 @@ public class ChangeHandlerFrameLayout extends FrameLayout implements ControllerC
@Override
public void onChangeStarted(Controller to, Controller from, boolean isPush, ViewGroup container, ControllerChangeHandler handler) {
mInProgressTransactionCount++;
mInProgressTransactionCount++;
}
@Override
public void onChangeCompleted(Controller to, Controller from, boolean isPush, ViewGroup container, ControllerChangeHandler handler) {
mInProgressTransactionCount--;
}
}
@@ -201,14 +201,16 @@ public abstract class Controller {
* Returns the Resources from the host Activity
*/
public final Resources getResources() {
return getActivity().getResources();
Activity activity = getActivity();
return activity != null ? activity.getResources() : null;
}
/**
* Returns the Application Context derived from the host Activity
*/
public final Context getApplicationContext() {
return getActivity().getApplicationContext();
Activity activity = getActivity();
return activity != null ? activity.getApplicationContext() : null;
}
/**
@@ -626,7 +628,7 @@ public abstract class Controller {
if (isChangingConfigurations) {
removeViewReference();
} else {
destroy();
destroy(true);
}
for (ChildControllerTransaction child : mChildControllers) {
@@ -729,14 +731,20 @@ public abstract class Controller {
}
final void destroy() {
destroy(false);
}
final void destroy(boolean removeViews) {
mIsBeingDestroyed = true;
for (ChildControllerTransaction child : mChildControllers) {
child.controller.destroy();
child.controller.destroy(removeViews);
}
if (!mAttached) {
removeViewReference();
} else if (removeViews) {
detach(mView);
}
}
@@ -6,6 +6,7 @@ import android.os.Bundle;
import android.support.annotation.NonNull;
import android.view.ViewGroup;
import com.bluelinelabs.conductor.Controller.LifecycleListener;
import com.bluelinelabs.conductor.ControllerChangeHandler.ControllerChangeListener;
import com.bluelinelabs.conductor.changehandler.SimpleSwapChangeHandler;
import com.bluelinelabs.conductor.internal.LifecycleHandler;
@@ -26,12 +27,13 @@ public class Router {
private LifecycleHandler mLifecycleHandler;
private ViewGroup mContainer;
private final List<ControllerChangeListener> mChangeListeners = new ArrayList<>();
private final List<Controller> mDestroyingControllers = new ArrayList<>();
/**
* Returns this Router's host Activity
*/
public Activity getActivity() {
return mLifecycleHandler.getLifecycleActivity();
return mLifecycleHandler != null ? mLifecycleHandler.getLifecycleActivity() : null;
}
/**
@@ -102,7 +104,7 @@ public class Router {
boolean poppingTopController = topController.controller == controller;
if (poppingTopController) {
mBackStack.pop();
trackDestroyingController(mBackStack.pop());
} else {
for (RouterTransaction transaction : mBackStack) {
if (transaction.controller == controller) {
@@ -140,7 +142,7 @@ public class Router {
public void replaceTopController(@NonNull RouterTransaction transaction) {
RouterTransaction topTransaction = mBackStack.peek();
if (!mBackStack.isEmpty()) {
mBackStack.pop();
trackDestroyingController(mBackStack.pop());
}
pushToBackstack(transaction);
@@ -199,12 +201,32 @@ public class Router {
}
/**
* Sets the root {@link Controller}. If any {@link Controller} are currently in the backstack, they will be removed.
* Sets the root {@link Controller}. If any {@link Controller}s are currently in the backstack, they will be removed.
*
* @param controller The new root {@link Controller}
*/
public void setRoot(@NonNull Controller controller) {
setRoot(controller, null);
setRoot(controller, null, null);
}
/**
* Sets the root {@link Controller}. If any {@link Controller}s are currently in the backstack, they will be removed.
*
* @param controller The new root {@link Controller}
* @param tag The tag to use for this {@link Controller}
*/
public void setRoot(@NonNull Controller controller, String tag) {
setRoot(controller, tag, null);
}
/**
* Sets the root {@link Controller}. If any {@link Controller}s are currently in the backstack, they will be removed.
*
* @param controller The new root {@link Controller}
* @param changeHandler The {@link ControllerChangeHandler} to use for setting the root
*/
public void setRoot(@NonNull Controller controller, ControllerChangeHandler changeHandler) {
setRoot(controller, null, changeHandler);
}
/**
@@ -212,14 +234,15 @@ public class Router {
*
* @param controller The new root {@link Controller}
* @param tag The tag to use for this {@link Controller}
* @param changeHandler The {@link ControllerChangeHandler} to use for setting the root
*/
public void setRoot(@NonNull Controller controller, String tag) {
public void setRoot(@NonNull Controller controller, String tag, ControllerChangeHandler changeHandler) {
mContainer.removeAllViews();
mBackStack.popAll();
trackDestroyingControllers(mBackStack.popAll());
RouterTransaction transaction = RouterTransaction.builder(controller)
.tag(tag)
.pushChangeHandler(new SimpleSwapChangeHandler())
.pushChangeHandler(changeHandler != null ? changeHandler : new SimpleSwapChangeHandler())
.popChangeHandler(new SimpleSwapChangeHandler())
.build();
@@ -346,13 +369,18 @@ public class Router {
public final void onActivityDestroyed(Activity activity) {
mContainer.setOnHierarchyChangeListener(null);
mLifecycleHandler = null;
mContainer = null;
mChangeListeners.clear();
for (RouterTransaction transaction : mBackStack) {
transaction.controller.activityDestroyed(activity.isChangingConfigurations());
}
for (Controller controller : mDestroyingControllers) {
controller.activityDestroyed(activity.isChangingConfigurations());
}
mLifecycleHandler = null;
mContainer = null;
}
public final void onRestoreInstanceState(Bundle savedInstanceState) {
@@ -362,6 +390,7 @@ public class Router {
private void popToTransaction(@NonNull RouterTransaction transaction, ControllerChangeHandler changeHandler) {
RouterTransaction topTransaction = mBackStack.peek();
List<RouterTransaction> poppedTransactions = mBackStack.popTo(transaction);
trackDestroyingControllers(poppedTransactions);
if (poppedTransactions.size() > 0) {
if (changeHandler == null) {
@@ -436,4 +465,21 @@ public class Router {
mBackStack.push(entry);
}
private void trackDestroyingController(RouterTransaction transaction) {
mDestroyingControllers.add(transaction.controller);
transaction.controller.addLifecycleListener(new LifecycleListener() {
@Override
public void postDestroy(@NonNull Controller controller) {
mDestroyingControllers.remove(controller);
}
});
}
private void trackDestroyingControllers(List<RouterTransaction> transactions) {
for (RouterTransaction transaction : transactions) {
trackDestroyingController(transaction);
}
}
}
@@ -119,6 +119,11 @@ public abstract class AnimatorChangeHandler extends ControllerChangeHandler {
}
animator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationCancel(Animator animation) {
changeListener.onChangeCompleted();
}
@Override
public void onAnimationEnd(Animator animation) {
if (from != null && (!isPush || mRemovesFromViewOnPush)) {
@@ -3,7 +3,6 @@ package com.bluelinelabs.conductor.changehandler;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.view.View;
import android.view.View.OnAttachStateChangeListener;
import android.view.ViewGroup;
import com.bluelinelabs.conductor.ControllerChangeHandler;
@@ -44,19 +43,10 @@ public class SimpleSwapChangeHandler extends ControllerChangeHandler {
}
if (to != null && to.getParent() == null) {
to.addOnAttachStateChangeListener(new OnAttachStateChangeListener() {
@Override
public void onViewAttachedToWindow(View view) {
view.removeOnAttachStateChangeListener(this);
changeListener.onChangeCompleted();
}
@Override
public void onViewDetachedFromWindow(View v) { }
});
container.addView(to);
}
changeListener.onChangeCompleted();
}
}
@@ -94,7 +94,6 @@ public class ControllerTests {
assertCalls(1, 1, 1, 1, 0, 0, 0);
mActivityController.destroy();
ViewUtils.setAttached(controller.getView(), false);
assertCalls(1, 1, 1, 1, 1, 1, 1);
}
@@ -14,8 +14,6 @@ import com.bluelinelabs.conductor.demo.R;
import com.bluelinelabs.conductor.demo.controllers.base.RefWatchingController;
import com.bluelinelabs.conductor.demo.util.ColorUtil;
import java.util.List;
public class ParentController extends RefWatchingController {
private static final int NUMBER_OF_CHILDREN = 5;
@@ -37,7 +35,7 @@ public class ParentController extends RefWatchingController {
}
private void addChild(final int index) {
String tag = "child_tag" + index;
String tag = Integer.toString(index);
if (getChildController(tag) == null) {
int frameId = getResources().getIdentifier("child_content_" + (index + 1), "id", getActivity().getPackageName());
@@ -48,27 +46,11 @@ public class ParentController extends RefWatchingController {
.popChangeHandler(new FadeChangeHandler())
.tag(tag)
.build());
childController.addLifecycleListener(new LifecycleListener() {
@Override
public void onChangeEnd(@NonNull Controller controller, @NonNull ControllerChangeHandler changeHandler, @NonNull ControllerChangeType changeType) {
if (changeType == ControllerChangeType.PUSH_ENTER && index < NUMBER_OF_CHILDREN - 1) {
addChild(index + 1);
} else if (changeType == ControllerChangeType.POP_EXIT) {
if (index > 0) {
removeChild(index - 1);
} else {
getRouter().popController(ParentController.this);
}
}
}
});
}
}
private void removeChild(int index) {
List<Controller> childControllers = getChildControllers();
removeChildController(childControllers.get(index));
removeChildController(getChildControllers().get(index));
}
@Override
@@ -79,4 +61,26 @@ public class ParentController extends RefWatchingController {
}
return true;
}
@Override
public void addChildController(ChildControllerTransaction transaction) {
final int index = Integer.parseInt(transaction.tag);
transaction.controller.addLifecycleListener(new LifecycleListener() {
@Override
public void onChangeEnd(@NonNull Controller controller, @NonNull ControllerChangeHandler changeHandler, @NonNull ControllerChangeType changeType) {
if (changeType == ControllerChangeType.PUSH_ENTER && index < NUMBER_OF_CHILDREN - 1) {
addChild(index + 1);
} else if (changeType == ControllerChangeType.POP_EXIT) {
if (index > 0) {
removeChild(index - 1);
} else {
getRouter().popController(ParentController.this);
}
}
}
});
super.addChildController(transaction);
}
}
@@ -58,7 +58,7 @@ public class TransitionDemoController extends RefWatchingController {
@Bind(R.id.tv_title) TextView mTvTitle;
@Bind(R.id.btn_next) FloatingActionButton mBtnNext;
View mContainerView;
@Bind(R.id.transition_root) View mContainerView;
private TransitionDemo mTransitionDemo;
@@ -73,6 +73,12 @@ public class TransitionDemoController extends RefWatchingController {
mTransitionDemo = TransitionDemo.fromIndex(args.getInt(KEY_INDEX));
}
@NonNull
@Override
protected View inflateView(@NonNull LayoutInflater inflater, @NonNull ViewGroup container) {
return inflater.inflate(mTransitionDemo.layoutId, container, false);
}
@Override
protected void onBindView(@NonNull View view) {
super.onBindView(view);
@@ -92,16 +98,9 @@ public class TransitionDemoController extends RefWatchingController {
}
mBtnNext.setBackgroundTintList(ColorStateList.valueOf(ContextCompat.getColor(getActivity(), buttonColor)));
mContainerView = view;
mTvTitle.setText(mTransitionDemo.title);
}
@NonNull
@Override
protected View inflateView(@NonNull LayoutInflater inflater, @NonNull ViewGroup container) {
return inflater.inflate(mTransitionDemo.layoutId, container, false);
}
@OnClick(R.id.btn_next) void onNextClicked() {
final int nextIndex = mTransitionDemo.ordinal() + 1;
@@ -143,4 +142,5 @@ public class TransitionDemoController extends RefWatchingController {
.popChangeHandler(changeHandler)
.build();
}
}
+3 -3
View File
@@ -5,8 +5,8 @@ ext {
buildToolsVersion = '23.0.2'
versionCode = 1
versionName = '1.0.4'
publishedVersionName = '1.0.4'
versionName = '1.0.5'
publishedVersionName = '1.0.5'
supportV4 = 'com.android.support:support-v4:23.1.1'
supportDesign = 'com.android.support:design:23.1.1'
@@ -27,4 +27,4 @@ ext {
lintapi = 'com.android.tools.lint:lint-api:24.5.0'
lintchecks = 'com.android.tools.lint:lint-checks:24.5.0'
}
}