Compare commits

...

20 Commits

Author SHA1 Message Date
Eric Kuck 8a70c09fea Big lifecycle update + a few bug fixes 2016-04-04 17:03:43 -05:00
Eric Kuck 343e8c92e5 Merge pull request #9 from ravidsrk/patch-1
Added code syntax highlighting to Readme
2016-04-01 06:49:14 -05:00
Ravindra Kumar 332788ee01 Added code syntax highlighting to Readme 2016-04-01 00:51:53 -04:00
Eric Kuck acf77101a7 Merge pull request #4 from sockeqwe/patch-1
Conductor class final; added private Constructor
2016-03-31 18:29:21 -05:00
Hannes Dorfmann cba372966d Conductor class final; added private Constructor 2016-04-01 00:32:04 +02:00
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
Eric Kuck d5e54f33a0 Fixed issue with screen rotation 2016-03-22 14:42:31 -05:00
Eric Kuck 58d1f37db0 Test fix 2016-03-21 22:35:51 -05:00
Eric Kuck 7c175e4ce5 Fixed where the Controller's view is set internally 2016-03-21 22:30:56 -05:00
Eric Kuck 328b8a0873 Readme update 2016-03-21 11:55:46 -05:00
Eric Kuck db446279bb Added some basic lint checks 2016-03-21 11:30:13 -05:00
Eric Kuck 80042ea71d Minor demo app refactor 2016-03-20 00:04:22 -05:00
43 changed files with 580 additions and 251 deletions
+8 -8
View File
@@ -1,4 +1,4 @@
[![Travis Build](https://travis-ci.org/bluelinelabs/Conductor.svg)](https://travis-ci.org/bluelinelabs/Conductor)
[![Travis Build](https://travis-ci.org/bluelinelabs/Conductor.svg)](https://travis-ci.org/bluelinelabs/Conductor) [![Android Arsenal](https://img.shields.io/badge/Android%20Arsenal-Conductor-brightgreen.svg?style=flat)](http://android-arsenal.com/details/1/3361)
# Conductor
@@ -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.2'
compile 'com.bluelinelabs:conductor:1.1.0'
// If you want the components that go along with
// Android's support libraries (currently just a PagerAdapter):
compile 'com.bluelinelabs:conductor-support:1.0.2'
compile 'com.bluelinelabs:conductor-support:1.1.0'
// If you want RxJava/RxAndroid lifecycle support:
compile 'com.bluelinelabs:conductor-rxlifecycle:1.0.2'
compile 'com.bluelinelabs:conductor-rxlifecycle:1.1.0'
```
## Components to Know
@@ -43,7 +43,7 @@ __ControllerTransaction__ | Transactions are used to define data about adding Co
### Minimal Activity implementation
```
```java
public class MainActivity extends Activity {
private Router mRouter;
@@ -74,12 +74,12 @@ public class MainActivity extends Activity {
### Minimal Controller implementation
```
```java
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
+20
View File
@@ -0,0 +1,20 @@
apply plugin: 'java'
configurations {
lintChecks
}
dependencies {
compile rootProject.ext.lintapi
compile rootProject.ext.lintchecks
lintChecks files(jar)
}
jar {
manifest {
attributes('Lint-Registry': 'com.bluelinelabs.conductor.lint.IssueRegistry')
}
}
apply from: rootProject.file('dependencies.gradle')
@@ -0,0 +1,100 @@
package com.bluelinelabs.conductor.lint;
import com.android.annotations.NonNull;
import com.android.tools.lint.client.api.JavaParser.ResolvedClass;
import com.android.tools.lint.detector.api.Category;
import com.android.tools.lint.detector.api.Detector;
import com.android.tools.lint.detector.api.Implementation;
import com.android.tools.lint.detector.api.Issue;
import com.android.tools.lint.detector.api.JavaContext;
import com.android.tools.lint.detector.api.Scope;
import com.android.tools.lint.detector.api.Severity;
import com.android.tools.lint.detector.api.Speed;
import java.lang.reflect.Modifier;
import java.util.Collections;
import java.util.List;
import lombok.ast.ClassDeclaration;
import lombok.ast.ConstructorDeclaration;
import lombok.ast.Node;
import lombok.ast.NormalTypeBody;
import lombok.ast.StrictListAccessor;
import lombok.ast.TypeMember;
import lombok.ast.VariableDefinition;
public final class ControllerChangeHandlerIssueDetector extends Detector implements Detector.JavaScanner, Detector.ClassScanner {
public static final Issue ISSUE =
Issue.create("ValidControllerChangeHandler", "ControllerChangeHandler not instantiatable",
"Non-abstract ControllerChangeHandler instances must have a default constructor for the"
+ " system to re-create them in the case of the process being killed.",
Category.CORRECTNESS, 6, Severity.FATAL,
new Implementation(ControllerChangeHandlerIssueDetector.class, Scope.JAVA_FILE_SCOPE));
public ControllerChangeHandlerIssueDetector() { }
@NonNull
@Override
public Speed getSpeed() {
return Speed.FAST;
}
@Override
public List<String> applicableSuperClasses() {
return Collections.singletonList("com.bluelinelabs.conductor.ControllerChangeHandler");
}
@Override
public void checkClass(@NonNull JavaContext context, ClassDeclaration node,
@NonNull Node declarationOrAnonymous, @NonNull ResolvedClass cls) {
if (node == null) {
return;
}
final int flags = node.astModifiers().getEffectiveModifierFlags();
if ((flags & Modifier.ABSTRACT) != 0) {
return;
}
if ((flags & Modifier.PUBLIC) == 0) {
String message = String.format("This ControllerChangeHandler class should be public (%1$s)", cls.getName());
context.report(ISSUE, node, context.getLocation(node.astName()), message);
return;
}
if (cls.getContainingClass() != null && (flags & Modifier.STATIC) == 0) {
String message = String.format("This ControllerChangeHandler inner class should be static (%1$s)", cls.getName());
context.report(ISSUE, node, context.getLocation(node.astName()), message);
return;
}
boolean hasConstructor = false;
boolean hasDefaultConstructor = false;
NormalTypeBody body = node.astBody();
if (body != null) {
for (TypeMember member : body.astMembers()) {
if (member instanceof ConstructorDeclaration) {
hasConstructor = true;
ConstructorDeclaration constructor = (ConstructorDeclaration)member;
if (constructor.astModifiers().isPublic()) {
StrictListAccessor<VariableDefinition, ConstructorDeclaration> params = constructor.astParameters();
if (params.isEmpty()) {
hasDefaultConstructor = true;
break;
}
}
}
}
}
if (hasConstructor && !hasDefaultConstructor) {
String message = String.format(
"This ControllerChangeHandler needs to have a public default constructor (`%1$s`)",
cls.getName());
context.report(ISSUE, node, context.getLocation(node.astName()), message);
}
}
}
@@ -0,0 +1,108 @@
package com.bluelinelabs.conductor.lint;
import com.android.SdkConstants;
import com.android.annotations.NonNull;
import com.android.tools.lint.client.api.JavaParser.ResolvedClass;
import com.android.tools.lint.detector.api.Category;
import com.android.tools.lint.detector.api.Detector;
import com.android.tools.lint.detector.api.Implementation;
import com.android.tools.lint.detector.api.Issue;
import com.android.tools.lint.detector.api.JavaContext;
import com.android.tools.lint.detector.api.Scope;
import com.android.tools.lint.detector.api.Severity;
import com.android.tools.lint.detector.api.Speed;
import java.lang.reflect.Modifier;
import java.util.Collections;
import java.util.List;
import lombok.ast.ClassDeclaration;
import lombok.ast.ConstructorDeclaration;
import lombok.ast.Node;
import lombok.ast.NormalTypeBody;
import lombok.ast.StrictListAccessor;
import lombok.ast.TypeMember;
import lombok.ast.VariableDefinition;
public final class ControllerIssueDetector extends Detector implements Detector.JavaScanner, Detector.ClassScanner {
public static final Issue ISSUE =
Issue.create("ValidController", "Controller not instantiatable",
"Non-abstract Controller instances must have a default or single-argument constructor"
+ " that takes a Bundle in order for the system to re-create them in the"
+ " case of the process being killed.", Category.CORRECTNESS, 6, Severity.FATAL,
new Implementation(ControllerIssueDetector.class, Scope.JAVA_FILE_SCOPE));
public ControllerIssueDetector() { }
@NonNull
@Override
public Speed getSpeed() {
return Speed.FAST;
}
@Override
public List<String> applicableSuperClasses() {
return Collections.singletonList("com.bluelinelabs.conductor.Controller");
}
@Override
public void checkClass(@NonNull JavaContext context, ClassDeclaration node,
@NonNull Node declarationOrAnonymous, @NonNull ResolvedClass cls) {
if (node == null) {
return;
}
final int flags = node.astModifiers().getEffectiveModifierFlags();
if ((flags & Modifier.ABSTRACT) != 0) {
return;
}
if ((flags & Modifier.PUBLIC) == 0) {
String message = String.format("This Controller class should be public (%1$s)", cls.getName());
context.report(ISSUE, node, context.getLocation(node.astName()), message);
return;
}
if (cls.getContainingClass() != null && (flags & Modifier.STATIC) == 0) {
String message = String.format("This Controller inner class should be static (%1$s)", cls.getName());
context.report(ISSUE, node, context.getLocation(node.astName()), message);
return;
}
boolean hasConstructor = false;
boolean hasDefaultConstructor = false;
boolean hasBundleConstructor = false;
NormalTypeBody body = node.astBody();
if (body != null) {
for (TypeMember member : body.astMembers()) {
if (member instanceof ConstructorDeclaration) {
hasConstructor = true;
ConstructorDeclaration constructor = (ConstructorDeclaration)member;
if (constructor.astModifiers().isPublic()) {
StrictListAccessor<VariableDefinition, ConstructorDeclaration> params = constructor.astParameters();
if (params.isEmpty()) {
hasDefaultConstructor = true;
break;
} else if (params.size() == 1 &&
(params.first().astTypeReference().getTypeName().equals(SdkConstants.CLASS_BUNDLE)) ||
params.first().astTypeReference().getTypeName().equals("Bundle")) {
hasBundleConstructor = true;
break;
}
}
}
}
}
if (hasConstructor && !hasDefaultConstructor && !hasBundleConstructor) {
String message = String.format(
"This Controller needs to have either a public default constructor or a" +
" public single-argument constructor that takes a Bundle. (`%1$s`)",
cls.getName());
context.report(ISSUE, node, context.getLocation(node.astName()), message);
}
}
}
@@ -0,0 +1,14 @@
package com.bluelinelabs.conductor.lint;
import com.android.tools.lint.detector.api.Issue;
import java.util.Arrays;
import java.util.List;
public final class IssueRegistry extends com.android.tools.lint.client.api.IssueRegistry {
@Override public List<Issue> getIssues() {
return Arrays.asList(
ControllerIssueDetector.ISSUE,
ControllerChangeHandlerIssueDetector.ISSUE);
}
}
@@ -3,10 +3,10 @@ package com.bluelinelabs.conductor.rxlifecycle;
public enum ControllerEvent {
CREATE,
CREATE_VIEW,
ATTACH,
BIND_VIEW,
DETACH,
UNBIND_VIEW,
DESTROY_VIEW,
DESTROY
}
@@ -21,8 +21,8 @@ public class ControllerLifecycleSubjectHelper {
controller.addLifecycleListener(new LifecycleListener() {
@Override
public void preBindView(@NonNull Controller controller, @NonNull View view) {
subject.onNext(ControllerEvent.BIND_VIEW);
public void preCreateView(@NonNull Controller controller) {
subject.onNext(ControllerEvent.CREATE_VIEW);
}
@Override
@@ -31,13 +31,13 @@ public class ControllerLifecycleSubjectHelper {
}
@Override
public void preUnbindView(@NonNull Controller controller, @NonNull View view) {
subject.onNext(ControllerEvent.UNBIND_VIEW);
public void preDetach(@NonNull Controller controller, @NonNull View view) {
subject.onNext(ControllerEvent.DETACH);
}
@Override
public void preDetach(@NonNull Controller controller, @NonNull View view) {
subject.onNext(ControllerEvent.DETACH);
public void preDestroyView(@NonNull Controller controller, @NonNull View view) {
subject.onNext(ControllerEvent.DESTROY_VIEW);
}
@Override
@@ -33,8 +33,8 @@ public class RxControllerLifecycle {
return ControllerEvent.DESTROY;
case ATTACH:
return ControllerEvent.DETACH;
case BIND_VIEW:
return ControllerEvent.UNBIND_VIEW;
case CREATE_VIEW:
return ControllerEvent.DESTROY_VIEW;
case DETACH:
return ControllerEvent.DESTROY;
default:
+18
View File
@@ -31,11 +31,17 @@ android {
}
}
configurations {
lintChecks
}
dependencies {
testCompile rootProject.ext.junit
testCompile rootProject.ext.roboelectric
compile rootProject.ext.supportAnnotations
lintChecks project(path: ':conductor-lint', configuration: 'lintChecks')
}
unMock {
@@ -46,6 +52,18 @@ unMock {
keep "android.text.TextUtils"
}
task copyLintJar(type: Copy) {
from(configurations.lintChecks) {
rename { 'lint.jar' }
}
into 'build/intermediates/lint/'
}
project.afterEvaluate {
def compileLintTask = project.tasks.find { it.name == 'compileLint' }
compileLintTask.dependsOn(copyLintJar)
}
ext.artifactId = 'conductor'
apply from: rootProject.file('dependencies.gradle')
@@ -67,16 +67,18 @@ 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) {
public void detachAndSaveInstanceState(Bundle outState) {
ArrayList<Bundle> entryBundles = new ArrayList<>(mBackStack.size());
for (RouterTransaction entry : mBackStack) {
entryBundles.add(entry.toBundle());
entryBundles.add(entry.detachAndSaveInstanceState());
}
outState.putParcelableArrayList(KEY_ENTRIES, entryBundles);
@@ -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--;
}
}
@@ -31,8 +31,8 @@ public class ChildControllerTransaction extends ControllerTransaction {
}
@Override
public Bundle toBundle() {
Bundle bundle = super.toBundle();
public Bundle detachAndSaveInstanceState() {
Bundle bundle = super.detachAndSaveInstanceState();
bundle.putInt(KEY_CONTAINER_ID, containerId);
bundle.putBoolean(KEY_ADD_TO_LOCAL_BACKSTACK, addToLocalBackstack);
return bundle;
@@ -10,8 +10,10 @@ import com.bluelinelabs.conductor.internal.LifecycleHandler;
/**
* Point of initial interaction with Conductor. Used to attach a {@link Router} to your Activity.
*/
public class Conductor {
public final class Conductor {
private Conductor(){}
/**
* Conductor will create a {@link Router} that has been initialized for your Activity and containing ViewGroup.
* If an existing {@link Router} is already associated with this Activity/ViewGroup pair, either in memory
@@ -108,7 +108,8 @@ public abstract class Controller {
/**
* Called when the controller is ready to display its view. A valid view must be returned. The standard body
* for this method will be {@code return inflater.inflate(R.layout.my_layout, container, false);}
* for this method will be {@code return inflater.inflate(R.layout.my_layout, container, false);}, plus
* any binding code.
*
* @param inflater The LayoutInflater that should be used to inflate views
* @param container The parent view that this Controller's view will eventually be attached to.
@@ -116,7 +117,7 @@ public abstract class Controller {
* so that valid LayoutParams can be used during inflation.
*/
@NonNull
protected abstract View inflateView(@NonNull LayoutInflater inflater, @NonNull ViewGroup container);
protected abstract View onCreateView(@NonNull LayoutInflater inflater, @NonNull ViewGroup container);
/**
* Returns the {@link Router} object that can be used for pushing or popping other Controllers
@@ -201,14 +202,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;
}
/**
@@ -269,22 +272,14 @@ public abstract class Controller {
/**
* Optional target for this Controller. One reason this could be used is to send results back to the Controller
* that started this one. Target Controllers are retained across instances.
*
* @param target The Controller that is the target of this one.
*/
public final void setTargetController(Controller target) {
mTargetInstanceId = target != null ? target.getInstanceId() : null;
onTargetControllerSet(target);
}
/**
* This method will be called when {@link #setTargetController(Controller)} is called. It is recommended
* that started this one. Target Controllers are retained across instances. It is recommended
* that Controllers enforce that their target Controller conform to a specific Interface.
*
* @param target The Controller that is the target of this one.
*/
public void onTargetControllerSet(Controller target) { }
public void setTargetController(Controller target) {
mTargetInstanceId = target != null ? target.getInstanceId() : null;
}
/**
* Returns the target Controller that was set with the {@link #setTargetController(Controller)} method
@@ -295,21 +290,13 @@ public abstract class Controller {
return mTargetInstanceId != null ? mRouter.getControllerWithInstanceId(mTargetInstanceId) : null;
}
/**
* Called when this Controller's View is inflated. This should overridden to bind the View
* to variables, either using findViewById or something like Butterknife.
*
* @param view The View to which this Controller should be bound.
*/
protected void onBindView(@NonNull final View view) { }
/**
* Called when this Controller's View is being destroyed. This should overridden to unbind the View
* from any local variables.
*
* @param view The View to which this Controller should be bound.
*/
protected void onUnbindView(View view) { }
protected void onDestroyView(View view) { }
/**
* Called when this Controller begins the process of being swapped in or out of the host view.
@@ -541,6 +528,10 @@ public abstract class Controller {
mOverriddenPopHandler = overriddenPopHandler;
}
final void prepareForActivityPause() {
mNeedsAttach = mNeedsAttach || mAttached;
}
final boolean getNeedsAttach() {
return mNeedsAttach;
}
@@ -622,7 +613,7 @@ public abstract class Controller {
if (isChangingConfigurations) {
removeViewReference();
} else {
destroy();
destroy(true);
}
for (ChildControllerTransaction child : mChildControllers) {
@@ -637,7 +628,6 @@ public abstract class Controller {
mAttached = true;
mNeedsAttach = false;
mView = view;
for (ChildControllerTransaction child : mChildControllers) {
attachChildController(child, new SimpleSwapChangeHandler());
@@ -656,8 +646,6 @@ public abstract class Controller {
lifecycleListener.preDetach(this, view);
}
saveViewState(view);
mAttached = false;
onDetach(view);
@@ -680,16 +668,20 @@ public abstract class Controller {
private void removeViewReference() {
if (mView != null) {
for (LifecycleListener lifecycleListener : mLifecycleListeners) {
lifecycleListener.preUnbindView(this, mView);
if (!mIsBeingDestroyed) {
saveViewState(mView);
}
onUnbindView(mView);
for (LifecycleListener lifecycleListener : mLifecycleListeners) {
lifecycleListener.preDestroyView(this, mView);
}
onDestroyView(mView);
mView = null;
for (LifecycleListener lifecycleListener : mLifecycleListeners) {
lifecycleListener.postUnbindView(this);
lifecycleListener.postDestroyView(this);
}
}
@@ -700,13 +692,32 @@ public abstract class Controller {
final View inflate(@NonNull ViewGroup parent) {
if (mView == null) {
View view = inflateView(LayoutInflater.from(parent.getContext()), parent);
bindView(view);
restoreViewState(view);
return view;
} else {
return mView;
for (LifecycleListener lifecycleListener : mLifecycleListeners) {
lifecycleListener.preCreateView(this);
}
mView = onCreateView(LayoutInflater.from(parent.getContext()), parent);
restoreViewState(mView);
mView.addOnAttachStateChangeListener(new OnAttachStateChangeListener() {
@Override
public void onViewAttachedToWindow(View v) {
attach(v);
}
@Override
public void onViewDetachedFromWindow(View v) {
detach(v);
}
});
for (LifecycleListener lifecycleListener : mLifecycleListeners) {
lifecycleListener.postCreateView(this, mView);
}
}
return mView;
}
final void performDestroy() {
@@ -726,14 +737,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);
}
}
@@ -768,9 +785,9 @@ public abstract class Controller {
}
}
final Bundle saveInstanceState() {
final Bundle detachAndSaveInstanceState() {
if (mAttached && mView != null) {
saveViewState(mView);
detach(mView);
}
Bundle outState = new Bundle();
@@ -791,7 +808,7 @@ public abstract class Controller {
ArrayList<Bundle> childBundles = new ArrayList<>();
for (ChildControllerTransaction childController : mChildControllers) {
childBundles.add(childController.toBundle());
childBundles.add(childController.detachAndSaveInstanceState());
}
outState.putParcelableArrayList(KEY_CHILDREN, childBundles);
@@ -845,30 +862,6 @@ public abstract class Controller {
}
}
private void bindView(@NonNull final View view) {
for (LifecycleListener lifecycleListener : mLifecycleListeners) {
lifecycleListener.preBindView(this, view);
}
onBindView(view);
view.addOnAttachStateChangeListener(new OnAttachStateChangeListener() {
@Override
public void onViewAttachedToWindow(View v) {
attach(view);
}
@Override
public void onViewDetachedFromWindow(View v) {
detach(view);
}
});
for (LifecycleListener lifecycleListener : mLifecycleListeners) {
lifecycleListener.postBindView(this, view);
}
}
private void ensureRequiredConstructor() {
Constructor[] constructors = getClass().getConstructors();
if (getBundleConstructor(constructors) == null && getDefaultConstructor(constructors) == null) {
@@ -908,18 +901,18 @@ public abstract class Controller {
public void onChangeStart(@NonNull Controller controller, @NonNull ControllerChangeHandler changeHandler, @NonNull ControllerChangeType changeType) { }
public void onChangeEnd(@NonNull Controller controller, @NonNull ControllerChangeHandler changeHandler, @NonNull ControllerChangeType changeType) { }
public void preBindView(@NonNull Controller controller, @NonNull View view) { }
public void postBindView(@NonNull Controller controller, @NonNull View view) { }
public void preCreateView(@NonNull Controller controller) { }
public void postCreateView(@NonNull Controller controller, @NonNull View view) { }
public void preAttach(@NonNull Controller controller, @NonNull View view) { }
public void postAttach(@NonNull Controller controller, @NonNull View view) { }
public void preUnbindView(@NonNull Controller controller, @NonNull View view) { }
public void postUnbindView(@NonNull Controller controller) { }
public void preDetach(@NonNull Controller controller, @NonNull View view) { }
public void postDetach(@NonNull Controller controller, @NonNull View view) { }
public void preDestroyView(@NonNull Controller controller, @NonNull View view) { }
public void postDestroyView(@NonNull Controller controller) { }
public void preDestroy(@NonNull Controller controller) { }
public void postDestroy(@NonNull Controller controller) { }
@@ -77,10 +77,10 @@ public class ControllerTransaction {
/**
* Used to serialize this transaction into a Bundle
*/
public Bundle toBundle() {
public Bundle detachAndSaveInstanceState() {
Bundle bundle = new Bundle();
bundle.putBundle(KEY_VIEW_CONTROLLER_BUNDLE, controller.saveInstanceState());
bundle.putBundle(KEY_VIEW_CONTROLLER_BUNDLE, controller.detachAndSaveInstanceState());
if (mPushControllerChangeHandler != null) {
bundle.putBundle(KEY_PUSH_TRANSITION, mPushControllerChangeHandler.toBundle());
@@ -4,8 +4,10 @@ import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.view.View;
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 +28,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 +105,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 +143,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 +202,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,19 +235,33 @@ 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) {
mContainer.removeAllViews();
mBackStack.popAll();
public void setRoot(@NonNull Controller controller, String tag, ControllerChangeHandler changeHandler) {
RouterTransaction currentTop = mBackStack.peek();
if (currentTop != null && currentTop.controller.getView() != null) {
final View fromView = currentTop.controller.getView();
final int childCount = mContainer.getChildCount();
for (int i = 0; i < childCount; i++) {
final View child = mContainer.getChildAt(i);
if (child != fromView) {
mContainer.removeView(child);
}
}
}
trackDestroyingControllers(mBackStack.popAll());
RouterTransaction transaction = RouterTransaction.builder(controller)
.tag(tag)
.pushChangeHandler(new SimpleSwapChangeHandler())
.pushChangeHandler(changeHandler != null ? changeHandler : new SimpleSwapChangeHandler())
.popChangeHandler(new SimpleSwapChangeHandler())
.build();
pushToBackstack(transaction);
performControllerChange(transaction, null, true);
performControllerChange(transaction, currentTop, true);
}
/**
@@ -335,18 +372,27 @@ public class Router {
}
public final void onActivitySaveInstanceState(Activity activity, Bundle outState) {
mBackStack.saveInstanceState(outState);
for (RouterTransaction transaction : mBackStack) {
transaction.controller.prepareForActivityPause();
}
mBackStack.detachAndSaveInstanceState(outState);
}
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) {
@@ -356,6 +402,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) {
@@ -430,4 +477,23 @@ public class Router {
mBackStack.push(entry);
}
private void trackDestroyingController(RouterTransaction transaction) {
if (!transaction.controller.isDestroyed()) {
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();
}
}
@@ -17,7 +17,7 @@ public class ControllerChangeHandlerTests {
.pushChangeHandler(horizontalChangeHandler)
.popChangeHandler(fadeChangeHandler)
.build();
RouterTransaction restoredTransaction = new RouterTransaction(transaction.toBundle());
RouterTransaction restoredTransaction = new RouterTransaction(transaction.detachAndSaveInstanceState());
ControllerChangeHandler restoredHorizontal = restoredTransaction.getPushControllerChangeHandler();
ControllerChangeHandler restoredFade = restoredTransaction.getPopControllerChangeHandler();
@@ -29,9 +29,9 @@ public class ControllerTests {
private int mChangeStartCalls;
private int mChangeEndCalls;
private int mBindViewCalls;
private int mCreateViewCalls;
private int mAttachCalls;
private int mUnbindViewCalls;
private int mDestroyViewCalls;
private int mDetachCalls;
private int mDestroyCalls;
@@ -44,9 +44,9 @@ public class ControllerTests {
mChangeStartCalls = 0;
mChangeEndCalls = 0;
mBindViewCalls = 0;
mCreateViewCalls = 0;
mAttachCalls = 0;
mUnbindViewCalls = 0;
mDestroyViewCalls = 0;
mDestroyCalls = 0;
mDestroyCalls = 0;
}
@@ -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);
}
@@ -180,7 +179,7 @@ public class ControllerTests {
controller.setRetainViewMode(RetainViewMode.RELEASE_DETACH);
Assert.assertNull(controller.getView());
View view = controller.inflate(new FrameLayout(mRouter.getActivity()));
Assert.assertNull(controller.getView());
Assert.assertNotNull(controller.getView());
ViewUtils.setAttached(view, true);
Assert.assertNotNull(controller.getView());
ViewUtils.setAttached(view, false);
@@ -189,7 +188,7 @@ public class ControllerTests {
// Test View getting retained w/ RETAIN_DETACH
controller.setRetainViewMode(RetainViewMode.RETAIN_DETACH);
view = controller.inflate(new FrameLayout(mRouter.getActivity()));
Assert.assertNull(controller.getView());
Assert.assertNotNull(controller.getView());
ViewUtils.setAttached(view, true);
Assert.assertNotNull(controller.getView());
ViewUtils.setAttached(view, false);
@@ -229,9 +228,9 @@ public class ControllerTests {
private void assertCalls(int changeStart, int changeEnd, int bindView, int attach, int unbindView, int detach, int destroy) {
Assert.assertEquals(changeStart, mChangeStartCalls);
Assert.assertEquals(changeEnd, mChangeEndCalls);
Assert.assertEquals(bindView, mBindViewCalls);
Assert.assertEquals(bindView, mCreateViewCalls);
Assert.assertEquals(attach, mAttachCalls);
Assert.assertEquals(unbindView, mUnbindViewCalls);
Assert.assertEquals(unbindView, mDestroyViewCalls);
Assert.assertEquals(detach, mDetachCalls);
Assert.assertEquals(destroy, mDestroyCalls);
}
@@ -249,8 +248,8 @@ public class ControllerTests {
}
@Override
public void postBindView(@NonNull Controller controller, @NonNull View view) {
mBindViewCalls++;
public void postCreateView(@NonNull Controller controller, @NonNull View view) {
mCreateViewCalls++;
}
@Override
@@ -259,8 +258,8 @@ public class ControllerTests {
}
@Override
public void postUnbindView(@NonNull Controller controller) {
mUnbindViewCalls++;
public void postDestroyView(@NonNull Controller controller) {
mDestroyViewCalls++;
}
@Override
@@ -279,7 +278,7 @@ public class ControllerTests {
void performChange(@NonNull ViewGroup container, View from, View to, boolean isPush, @NonNull ControllerChangeCompletedListener changeListener);
}
static class ChangeHandler extends ControllerChangeHandler {
public static class ChangeHandler extends ControllerChangeHandler {
private ChangeHandlerListener mListener;
@@ -20,7 +20,7 @@ public class ControllerTransactionTests {
.tag("Test Tag")
.build();
Bundle bundle = transaction.toBundle();
Bundle bundle = transaction.detachAndSaveInstanceState();
RouterTransaction restoredTransaction = new RouterTransaction(bundle);
@@ -39,7 +39,7 @@ public class ControllerTransactionTests {
.tag("Test Tag")
.build();
Bundle bundle = transaction.toBundle();
Bundle bundle = transaction.detachAndSaveInstanceState();
ChildControllerTransaction restoredTransaction = new ChildControllerTransaction(bundle);
@@ -15,7 +15,7 @@ public class TestController extends Controller {
@NonNull
@Override
protected View inflateView(@NonNull LayoutInflater inflater, @NonNull ViewGroup container) {
protected View onCreateView(@NonNull LayoutInflater inflater, @NonNull ViewGroup container) {
View view = new FrameLayout(inflater.getContext());
view.setId(VIEW_ID);
return view;
+3
View File
@@ -45,6 +45,9 @@ dependencies {
compile 'com.bluelinelabs:conductor-support:' + rootProject.ext.publishedVersionName
compile 'com.bluelinelabs:conductor-rxlifecycle:' + rootProject.ext.publishedVersionName
// compile project(':conductor-support')
// compile project(':conductor-rxlifecycle')
debugCompile rootProject.ext.leakCanary
releaseCompile rootProject.ext.leakCanaryNoOp
testCompile rootProject.ext.leakCanaryNoOp
+5 -2
View File
@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest
xmlns:tools="http://schemas.android.com/tools"
package="com.bluelinelabs.conductor.demo"
xmlns:android="http://schemas.android.com/apk/res/android">
@@ -7,11 +8,13 @@
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<application
android:name="com.bluelinelabs.conductor.demo.App"
android:name="com.bluelinelabs.conductor.demo.DemoApplication"
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme">
android:theme="@style/AppTheme"
android:fullBackupContent="true"
tools:ignore="GoogleAppIndexingWarning">
<activity
android:name="com.bluelinelabs.conductor.demo.MainActivity"
@@ -5,7 +5,7 @@ import android.app.Application;
import com.squareup.leakcanary.LeakCanary;
import com.squareup.leakcanary.RefWatcher;
public class App extends Application {
public class DemoApplication extends Application {
public static RefWatcher refWatcher;
@@ -8,7 +8,7 @@ import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import com.bluelinelabs.conductor.demo.BundleBuilder;
import com.bluelinelabs.conductor.demo.util.BundleBuilder;
import com.bluelinelabs.conductor.demo.R;
import com.bluelinelabs.conductor.demo.controllers.base.RefWatchingController;
@@ -41,8 +41,8 @@ public class ChildController extends RefWatchingController {
}
@Override
protected void onBindView(@NonNull View view) {
super.onBindView(view);
protected void onViewBound(@NonNull View view) {
super.onViewBound(view);
mTvTitle.setText(getArgs().getString(KEY_TITLE));
@@ -36,9 +36,7 @@ public class DragDismissController extends RefWatchingController {
}
@Override
protected void onBindView(@NonNull View view) {
super.onBindView(view);
protected void onViewBound(@NonNull View view) {
((ElasticDragDismissFrameLayout)view).addListener(mDragDismissListener);
mTvLoremIpsum.setText("Lorem ipsum dolor sit amet, volutpat lacus egestas integer vitae, tempus potenti posuere dolore, elit cras ut vulputate pede eros. Pharetra curabitur, cum ultrices nisi nulla, non a est diamlorem in pede. Feugiat vivamus id, leo massa, pede ligula libero wisi, posuere nec interdum risus. Mauris eros. Scelerisque etiam dignissim, sem odio magna posuere libero in. Eget non posuere, rutrum nunc ut, ipsum ornare, vestibulum nisl turpis, urna interdum. Arcu mi velit. Sem dolor amet sed hymenaeos tempor. Cras felis.\n" +
@@ -48,9 +46,10 @@ public class DragDismissController extends RefWatchingController {
}
@Override
protected void onUnbindView(View view) {
super.onUnbindView(view);
protected void onDestroyView(View view) {
super.onDestroyView(view);
((ElasticDragDismissFrameLayout)view).removeListener(mDragDismissListener);
}
}
@@ -52,8 +52,8 @@ public class HomeController extends RefWatchingController {
}
@Override
protected void onBindView(@NonNull View view) {
super.onBindView(view);
protected void onViewBound(@NonNull View view) {
super.onViewBound(view);
mRecyclerView.setHasFixedSize(true);
mRecyclerView.setLayoutManager(new LinearLayoutManager(view.getContext()));
@@ -9,7 +9,7 @@ import android.widget.TextView;
import com.bluelinelabs.conductor.RouterTransaction;
import com.bluelinelabs.conductor.changehandler.HorizontalChangeHandler;
import com.bluelinelabs.conductor.demo.BundleBuilder;
import com.bluelinelabs.conductor.demo.util.BundleBuilder;
import com.bluelinelabs.conductor.demo.R;
import com.bluelinelabs.conductor.demo.controllers.base.RefWatchingController;
import com.bluelinelabs.conductor.demo.util.ColorUtil;
@@ -45,8 +45,8 @@ public class NavigationDemoController extends RefWatchingController {
}
@Override
protected void onBindView(@NonNull View view) {
super.onBindView(view);
protected void onViewBound(@NonNull View view) {
super.onViewBound(view);
view.setBackgroundColor(ColorUtil.getMaterialColor(getResources(), mIndex));
mTvTitle.setText(getResources().getString(R.string.navigation_title, mIndex));
@@ -22,8 +22,8 @@ public class OverlayController extends RefWatchingController {
}
@Override
public void onBindView(@NonNull View view) {
super.onBindView(view);
public void onViewBound(@NonNull View view) {
super.onViewBound(view);
mTextView.setText("I'm an Overlay");
}
@@ -42,8 +42,8 @@ public class PagerController extends RefWatchingController {
}
@Override
protected void onBindView(@NonNull View view) {
super.onBindView(view);
protected void onViewBound(@NonNull View view) {
super.onViewBound(view);
mViewPager.setAdapter(mPagerAdapter);
}
@@ -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,15 +35,38 @@ public class ParentController extends RefWatchingController {
}
private void addChild(final int index) {
int frameId = getResources().getIdentifier("child_content_" + (index + 1), "id", getActivity().getPackageName());
String tag = Integer.toString(index);
ChildController childController = new ChildController("Child Controller #" + index, ColorUtil.getMaterialColor(getResources(), index), false);
addChildController(ChildControllerTransaction.builder(childController, frameId)
.pushChangeHandler(new FadeChangeHandler())
.popChangeHandler(new FadeChangeHandler())
.build());
if (getChildController(tag) == null) {
int frameId = getResources().getIdentifier("child_content_" + (index + 1), "id", getActivity().getPackageName());
childController.addLifecycleListener(new LifecycleListener() {
ChildController childController = new ChildController("Child Controller #" + index, ColorUtil.getMaterialColor(getResources(), index), false);
addChildController(ChildControllerTransaction.builder(childController, frameId)
.pushChangeHandler(new FadeChangeHandler())
.popChangeHandler(new FadeChangeHandler())
.tag(tag)
.build());
}
}
private void removeChild(int index) {
removeChildController(getChildControllers().get(index));
}
@Override
public boolean handleBack() {
if (getChildControllers().size() == NUMBER_OF_CHILDREN && !mFinishing) {
mFinishing = true;
removeChild(getChildControllers().size() - 1);
}
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) {
@@ -59,19 +80,7 @@ public class ParentController extends RefWatchingController {
}
}
});
}
private void removeChild(int index) {
List<Controller> childControllers = getChildControllers();
removeChildController(childControllers.get(index));
}
@Override
public boolean handleBack() {
if (getChildControllers().size() == NUMBER_OF_CHILDREN && !mFinishing) {
mFinishing = true;
removeChild(getChildControllers().size() - 1);
}
return true;
super.addChildController(transaction);
}
}
@@ -48,10 +48,8 @@ public class RxLifecycleController extends RefWatchingController {
}
@Override
public void onBindView(@NonNull View view) {
super.onBindView(view);
Log.i(TAG, "onBindView() called");
public void onViewBound(@NonNull View view) {
Log.i(TAG, "onCreateView() called");
mTvTitle.setText(getResources().getString(R.string.rxlifecycle_title, TAG));
@@ -59,14 +57,14 @@ public class RxLifecycleController extends RefWatchingController {
.doOnUnsubscribe(new Action0() {
@Override
public void call() {
Log.i(TAG, "Unsubscribing from onBindView()");
Log.i(TAG, "Unsubscribing from onCreateView)");
}
})
.compose(this.<Long>bindUntilEvent(ControllerEvent.UNBIND_VIEW))
.compose(this.<Long>bindUntilEvent(ControllerEvent.DESTROY_VIEW))
.subscribe(new Action1<Long>() {
@Override
public void call(Long num) {
Log.i(TAG, "Started in onBindView(), running until onUnbindView(): " + num);
Log.i(TAG, "Started in onCreateView(), running until onDestroyView(): " + num);
}
});
}
@@ -94,10 +92,10 @@ public class RxLifecycleController extends RefWatchingController {
}
@Override
protected void onUnbindView(View view) {
super.onUnbindView(view);
protected void onDestroyView(View view) {
super.onDestroyView(view);
Log.i(TAG, "onUnbindView() called");
Log.i(TAG, "onDestroyView() called");
}
@Override
@@ -123,7 +121,7 @@ public class RxLifecycleController extends RefWatchingController {
@OnClick(R.id.btn_next_release_view) void onNextWithReleaseClicked() {
setRetainViewMode(RetainViewMode.RELEASE_DETACH);
getRouter().pushController(RouterTransaction.builder(new TextController("Logcat should now report that the observables from onAttach() and onBindView() have been unsubscribed from, while the constructor observable is still running."))
getRouter().pushController(RouterTransaction.builder(new TextController("Logcat should now report that the observables from onAttach() and onViewBound() have been unsubscribed from, while the constructor observable is still running."))
.pushChangeHandler(new HorizontalChangeHandler())
.popChangeHandler(new HorizontalChangeHandler())
.build()
@@ -133,7 +131,7 @@ public class RxLifecycleController extends RefWatchingController {
@OnClick(R.id.btn_next_retain_view) void onNextWithRetainClicked() {
setRetainViewMode(RetainViewMode.RETAIN_DETACH);
getRouter().pushController(RouterTransaction.builder(new TextController("Logcat should now report that the observables from onAttach() has been unsubscribed from, while the constructor and onBindView() observables are still running."))
getRouter().pushController(RouterTransaction.builder(new TextController("Logcat should now report that the observables from onAttach() has been unsubscribed from, while the constructor and onViewBound() observables are still running."))
.pushChangeHandler(new HorizontalChangeHandler())
.popChangeHandler(new HorizontalChangeHandler())
.build()
@@ -70,8 +70,8 @@ public class TargetDisplayController extends RefWatchingController implements Ta
}
@Override
protected void onBindView(@NonNull View view) {
super.onBindView(view);
protected void onViewBound(@NonNull View view) {
super.onViewBound(view);
setTextView();
setImageView();
}
@@ -21,10 +21,15 @@ public class TargetTitleEntryController extends RefWatchingController {
@Bind(R.id.edit_text) EditText mEditText;
public <T extends Controller & TargetTitleEntryControllerListener> TargetTitleEntryController(T targetController) {
super.setTargetController(targetController);
}
public TargetTitleEntryController() { }
public TargetTitleEntryController(Controller targetController) {
setTargetController(targetController);
@Override
public void setTargetController(Controller target) {
throw new RuntimeException(getClass().getSimpleName() + "s can only have their target set through the constructor.");
}
@NonNull
@@ -33,15 +38,6 @@ public class TargetTitleEntryController extends RefWatchingController {
return inflater.inflate(R.layout.controller_target_title_entry, container, false);
}
@Override
public void onTargetControllerSet(Controller target) {
super.onTargetControllerSet(target);
if (!(target instanceof TargetTitleEntryControllerListener)) {
throw new RuntimeException(getClass().getSimpleName() + " target Controllers must implement the " + TargetTitleEntryControllerListener.class.getSimpleName() + " interface.");
}
}
@OnClick(R.id.btn_use_title) void optionPicked() {
Controller targetController = getTargetController();
if (targetController != null) {
@@ -7,7 +7,7 @@ import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import com.bluelinelabs.conductor.demo.BundleBuilder;
import com.bluelinelabs.conductor.demo.util.BundleBuilder;
import com.bluelinelabs.conductor.demo.R;
import com.bluelinelabs.conductor.demo.controllers.base.RefWatchingController;
@@ -37,8 +37,8 @@ public class TextController extends RefWatchingController {
}
@Override
public void onBindView(@NonNull View view) {
super.onBindView(view);
public void onViewBound(@NonNull View view) {
super.onViewBound(view);
mTextView.setText(getArgs().getString(KEY_TEXT));
}
@@ -19,7 +19,7 @@ import com.bluelinelabs.conductor.changehandler.CircularRevealChangeHandler;
import com.bluelinelabs.conductor.changehandler.FadeChangeHandler;
import com.bluelinelabs.conductor.changehandler.HorizontalChangeHandler;
import com.bluelinelabs.conductor.changehandler.VerticalChangeHandler;
import com.bluelinelabs.conductor.demo.BundleBuilder;
import com.bluelinelabs.conductor.demo.util.BundleBuilder;
import com.bluelinelabs.conductor.demo.R;
import com.bluelinelabs.conductor.demo.changehandler.ArcFadeMoveChangeHandlerCompat;
import com.bluelinelabs.conductor.demo.changehandler.FlipChangeHandler;
@@ -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,9 +73,15 @@ public class TransitionDemoController extends RefWatchingController {
mTransitionDemo = TransitionDemo.fromIndex(args.getInt(KEY_INDEX));
}
@NonNull
@Override
protected void onBindView(@NonNull View view) {
super.onBindView(view);
protected View inflateView(@NonNull LayoutInflater inflater, @NonNull ViewGroup container) {
return inflater.inflate(mTransitionDemo.layoutId, container, false);
}
@Override
protected void onViewBound(@NonNull View view) {
super.onViewBound(view);
View bgView = ButterKnife.findById(view, R.id.bg_view);
if (mTransitionDemo.colorId != 0 && bgView != null) {
@@ -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();
}
}
@@ -2,7 +2,9 @@ package com.bluelinelabs.conductor.demo.controllers.base;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import com.bluelinelabs.conductor.rxlifecycle.RxController;
@@ -15,16 +17,23 @@ public abstract class ButterKnifeController extends RxController {
super(args);
}
protected abstract View inflateView(@NonNull LayoutInflater inflater, @NonNull ViewGroup container);
@NonNull
@Override
protected void onBindView(@NonNull View view) {
super.onBindView(view);
protected View onCreateView(@NonNull LayoutInflater inflater, @NonNull ViewGroup container) {
View view = inflateView(inflater, container);
ButterKnife.bind(this, view);
onViewBound(view);
return view;
}
protected void onViewBound(@NonNull View view) { }
@Override
protected void onUnbindView(View view) {
super.onUnbindView(view);
protected void onDestroyView(View view) {
super.onDestroyView(view);
ButterKnife.unbind(this);
}
}
}
@@ -1,10 +1,8 @@
package com.bluelinelabs.conductor.demo.controllers.base;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.view.View;
import com.bluelinelabs.conductor.demo.App;
import com.bluelinelabs.conductor.demo.DemoApplication;
public abstract class RefWatchingController extends ButterKnifeController {
@@ -13,21 +11,10 @@ public abstract class RefWatchingController extends ButterKnifeController {
super(args);
}
@Override
protected void onDetach(@NonNull View view) {
super.onDetach(view);
if (isDestroyed()) {
App.refWatcher.watch(view);
}
}
@Override
public void onDestroy() {
if (getView() != null) {
App.refWatcher.watch(getView());
}
App.refWatcher.watch(this);
super.onDestroy();
DemoApplication.refWatcher.watch(this);
}
}
@@ -1,4 +1,4 @@
package com.bluelinelabs.conductor.demo;
package com.bluelinelabs.conductor.demo.util;
import android.os.Bundle;
import android.os.Parcelable;
+6 -3
View File
@@ -5,8 +5,8 @@ ext {
buildToolsVersion = '23.0.2'
versionCode = 1
versionName = '1.0.2'
publishedVersionName = '1.0.2'
versionName = '1.1.0'
publishedVersionName = '1.1.0'
supportV4 = 'com.android.support:support-v4:23.1.1'
supportDesign = 'com.android.support:design:23.1.1'
@@ -24,4 +24,7 @@ ext {
junit = 'junit:junit:4.11'
roboelectric = 'org.robolectric:robolectric:3.0'
}
lintapi = 'com.android.tools.lint:lint-api:24.5.0'
lintchecks = 'com.android.tools.lint:lint-checks:24.5.0'
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 98 KiB

After

Width:  |  Height:  |  Size: 103 KiB

+5 -1
View File
@@ -1 +1,5 @@
include ':conductor', ':conductor-support', ':conductor-rxlifecycle', ':demo'
include ':conductor'
include':conductor-support'
include':conductor-rxlifecycle'
include':conductor-lint'
include':demo'