Skip to content

Commit

Permalink
Make ControllerFactory an interface
Browse files Browse the repository at this point in the history
  • Loading branch information
AngusMorton committed Mar 10, 2019
1 parent 9d7445e commit 2fd7b55
Show file tree
Hide file tree
Showing 7 changed files with 64 additions and 79 deletions.
39 changes: 22 additions & 17 deletions conductor/src/main/java/com/bluelinelabs/conductor/Controller.java
Original file line number Diff line number Diff line change
Expand Up @@ -44,13 +44,13 @@
*/
public abstract class Controller {

static final String KEY_CLASS_NAME = "Controller.className";
private static final String KEY_CLASS_NAME = "Controller.className";
private static final String KEY_VIEW_STATE = "Controller.viewState";
private static final String KEY_CHILD_ROUTERS = "Controller.childRouters";
private static final String KEY_SAVED_STATE = "Controller.savedState";
private static final String KEY_INSTANCE_ID = "Controller.instanceId";
private static final String KEY_TARGET_INSTANCE_ID = "Controller.target.instanceId";
static final String KEY_ARGS = "Controller.args";
private static final String KEY_ARGS = "Controller.args";
private static final String KEY_NEEDS_ATTACH = "Controller.needsAttach";
private static final String KEY_REQUESTED_PERMISSIONS = "Controller.requestedPermissions";
private static final String KEY_OVERRIDDEN_PUSH_HANDLER = "Controller.overriddenPushHandler";
Expand Down Expand Up @@ -92,32 +92,34 @@ public abstract class Controller {
private boolean isPerformingExitTransition;
private boolean isContextAvailable;

static volatile ControllerFactory FACTORY = new ControllerFactory.DefaultControllerFactory();
static volatile ControllerFactory FACTORY = DefaultControllerFactory.INSTANCE;

@NonNull
static Controller newInstance(@NonNull Bundle bundle) {
final String className = bundle.getString(KEY_CLASS_NAME);
//noinspection ConstantConditions
Class cls = ClassUtils.classForName(className, false);
Constructor[] constructors = cls.getConstructors();
Constructor bundleConstructor = getBundleConstructor(constructors);

Bundle args = bundle.getBundle(KEY_ARGS);
if (args != null) {
args.setClassLoader(cls.getClassLoader());
}

Controller controller;
try {
if (bundleConstructor != null) {
controller = (Controller)bundleConstructor.newInstance(args);
} else {
//noinspection ConstantConditions
controller = (Controller)getDefaultConstructor(constructors).newInstance();

// Restore the args that existed before the last process death
if (args != null) {
controller.args.putAll(args);
controller = FACTORY.create(className, args);
if (controller == null) {
Constructor[] constructors = cls.getConstructors();
Constructor bundleConstructor = getBundleConstructor(constructors);
if (bundleConstructor != null) {
controller = (Controller) bundleConstructor.newInstance(args);
} else {
//noinspection ConstantConditions
controller = (Controller) getDefaultConstructor(constructors).newInstance();

// Restore the args that existed before the last process death
if (args != null) {
controller.args.putAll(args);
}
}
}
} catch (Exception e) {
Expand Down Expand Up @@ -1321,9 +1323,12 @@ final void setParentController(@Nullable Controller controller) {
}

private void ensureRequiredConstructor() {
if (FACTORY != DefaultControllerFactory.INSTANCE) {
// We assume you know what you're doing if you've installed a ControllerFactory
return;
}
Constructor[] constructors = getClass().getConstructors();
if (getBundleConstructor(constructors) == null && getDefaultConstructor(constructors) == null
&& FACTORY instanceof ControllerFactory.DefaultControllerFactory) {
if (getBundleConstructor(constructors) == null && getDefaultConstructor(constructors) == null) {
throw new RuntimeException(getClass() + " does not have a constructor that takes a Bundle argument or a default constructor. Controllers must have one of these in order to restore their states.");
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,42 +1,10 @@
package com.bluelinelabs.conductor;

import android.os.Bundle;

import com.bluelinelabs.conductor.internal.ClassUtils;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import static com.bluelinelabs.conductor.Controller.KEY_ARGS;
import static com.bluelinelabs.conductor.Controller.KEY_CLASS_NAME;

public abstract class ControllerFactory {

@NonNull final Controller create(@NonNull Bundle bundle) {
final String className = bundle.getString(KEY_CLASS_NAME);
//noinspection ConstantConditions
Class cls = ClassUtils.classForName(className, false);
Bundle args = bundle.getBundle(KEY_ARGS);
if (args != null) {
args.setClassLoader(cls.getClassLoader());
}

final Controller result = create(className, args);
if (result == null) {
return Controller.newInstance(bundle);
} else {
return result;
}
}

public interface ControllerFactory {
@Nullable
public abstract Controller create(@NonNull String controllerName, @NonNull Bundle args);

static final class DefaultControllerFactory extends ControllerFactory {
@Nullable
@Override
public Controller create(@NonNull String controllerName, @NonNull Bundle args) {
return null;
}
}
Controller create(@NonNull String controllerName, @Nullable Bundle args);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.bluelinelabs.conductor;

import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

final class DefaultControllerFactory implements ControllerFactory {

static final DefaultControllerFactory INSTANCE = new DefaultControllerFactory();

@Nullable
@Override
public final Controller create(@NonNull String controllerName, @Nullable Bundle args) {
return null;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ private RouterTransaction(@NonNull Controller controller) {
}

RouterTransaction(@NonNull Bundle bundle) {
controller = Controller.FACTORY.create(bundle.getBundle(KEY_VIEW_CONTROLLER_BUNDLE));
controller = Controller.newInstance(bundle.getBundle(KEY_VIEW_CONTROLLER_BUNDLE));
pushControllerChangeHandler = ControllerChangeHandler.fromBundle(bundle.getBundle(KEY_PUSH_TRANSITION));
popControllerChangeHandler = ControllerChangeHandler.fromBundle(bundle.getBundle(KEY_POP_TRANSITION));
tag = bundle.getString(KEY_TAG);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,36 +1,17 @@
package com.bluelinelabs.conductor;

import android.content.Context;
import android.os.Bundle;
import android.view.View;
import android.view.ViewGroup;

import com.bluelinelabs.conductor.Controller.LifecycleListener;
import com.bluelinelabs.conductor.Controller.RetainViewMode;
import com.bluelinelabs.conductor.changehandler.SimpleSwapChangeHandler;
import com.bluelinelabs.conductor.util.ActivityProxy;
import com.bluelinelabs.conductor.util.CallState;
import com.bluelinelabs.conductor.util.ChangeHandlerHistory;
import com.bluelinelabs.conductor.util.MockChangeHandler;
import com.bluelinelabs.conductor.util.MockChangeHandler.ChangeHandlerListener;
import com.bluelinelabs.conductor.util.TestController;
import com.bluelinelabs.conductor.util.TestControllerFactory;
import com.bluelinelabs.conductor.util.TestDependenciesController;
import com.bluelinelabs.conductor.util.ViewUtils;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.annotation.Config;

import androidx.annotation.NonNull;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;

@RunWith(RobolectricTestRunner.class)
@Config(manifest = Config.NONE)
Expand All @@ -39,7 +20,6 @@ public class ControllerFactoryTests {
private Router router;

private ActivityProxy activityProxy;
private CallState currentCallState;

public void createActivityController(Bundle savedInstanceState, boolean includeStartAndResume) {
activityProxy = new ActivityProxy().create(savedInstanceState);
Expand All @@ -57,7 +37,6 @@ public void createActivityController(Bundle savedInstanceState, boolean includeS
public void setup() {
Conductor.setControllerFactory(new TestControllerFactory());
createActivityController(null, true);
currentCallState = new CallState(false);
}

@Test
Expand All @@ -67,6 +46,9 @@ public void testControllerWithDependenciesRecreated() {
.tag("root"));
activityProxy.getActivity().isChangingConfigurations = true;

assertEquals(false, controller.wasCreatedByFactory);
assertEquals(false, controller.wasInstanceStateRestored);

Bundle bundle = new Bundle();
activityProxy.saveInstanceState(bundle);
activityProxy.pause();
Expand All @@ -75,6 +57,7 @@ public void testControllerWithDependenciesRecreated() {

createActivityController(bundle, false);
controller = (TestDependenciesController)router.getControllerWithTag("root");
assertEquals(true, controller.wasCreatedInFactory);
assertEquals(true, controller.wasCreatedByFactory);
assertEquals(true, controller.wasInstanceStateRestored);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

public class TestControllerFactory extends ControllerFactory {
public class TestControllerFactory implements ControllerFactory {
@Nullable
@Override
public Controller create(@NonNull String controllerName, @NonNull Bundle args) {
public Controller create(@NonNull String controllerName, @Nullable Bundle args) {
if (controllerName.equals(TestDependenciesController.class.getName())) {
return new TestDependenciesController(true);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.bluelinelabs.conductor.util;

import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
Expand All @@ -10,16 +11,28 @@

public class TestDependenciesController extends Controller {

public final Boolean wasCreatedInFactory;
private static final String INSTANCE_STATE = "INSTANCE_STATE";
public final Boolean wasCreatedByFactory;
public Boolean wasInstanceStateRestored = false;

public TestDependenciesController(Boolean wasCreatedInFactory) {
public TestDependenciesController(Boolean wasCreatedByFactory) {
super();
this.wasCreatedInFactory = wasCreatedInFactory;
this.wasCreatedByFactory = wasCreatedByFactory;
}

@NonNull
@Override
protected View onCreateView(@NonNull LayoutInflater inflater, @NonNull ViewGroup container) {
return new AttachFakingFrameLayout(inflater.getContext());
}

@Override protected void onSaveInstanceState(@NonNull Bundle outState) {
super.onSaveInstanceState(outState);
outState.putBoolean(INSTANCE_STATE, true);
}

@Override protected void onRestoreInstanceState(@NonNull Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
wasInstanceStateRestored = savedInstanceState.getBoolean(INSTANCE_STATE);
}
}

0 comments on commit 2fd7b55

Please sign in to comment.