Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
e8d4f53
Retain instance during navigation based on individual navigation events
kejunxia Nov 26, 2015
4ea6c54
Unit test to guarantee nested injeceted instance are reference counte…
kejunxia Nov 28, 2015
d3b4dad
Ui test to cover navigation with complex injection
kejunxia Nov 29, 2015
c157d19
Investigating back nav injection issue
kejunxia Nov 29, 2015
a3402c1
Refactor navigation controller
kejunxia Nov 30, 2015
750519d
rename ui test methods to be included into test suite
kejunxia Nov 30, 2015
d8a8a41
Remove invalid test
kejunxia Nov 30, 2015
1d88984
Rename navigate back method
kejunxia Dec 1, 2015
fc140cd
Remove method navigator.go
kejunxia Dec 1, 2015
1606de3
Add reference and dereference methods
kejunxia Dec 1, 2015
3973709
Adding prepared instances for navigation
kejunxia Dec 1, 2015
728debd
Use navigator for each navigation to hold and delay releasing of cont…
kejunxia Dec 2, 2015
d985983
Update documents
kejunxia Dec 2, 2015
e802399
Fix issue that graph.reference() doesn't increment nested instances' …
kejunxia Dec 3, 2015
fa82752
Don't release fragment in forward navigation
kejunxia Dec 3, 2015
bfafc96
Fix testing to align with the change in MvcActivity for device kills …
kejunxia Dec 4, 2015
826f375
Add documents for new navigation related classes
kejunxia Dec 5, 2015
09e338f
Remove unused code
kejunxia Dec 5, 2015
f1edec6
New interface to wrap preparation logic for navigation
kejunxia Dec 5, 2015
c313ab8
Rename navigator.destroy
kejunxia Dec 5, 2015
a32f12c
Bump up library version
kejunxia Dec 5, 2015
fa19774
Remove unused code and destroy pending navigator when activity exits
kejunxia Dec 6, 2015
60de1f7
Add convenient method to hold injected instance until navigation is s…
kejunxia Dec 6, 2015
bf34e54
update documents
kejunxia Dec 6, 2015
3a2190d
Unit tests for new navigation methods
kejunxia Dec 6, 2015
fe78d04
More unit tests for MvcGraph and navigation controller
kejunxia Dec 7, 2015
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions ChangeLog.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
Version: 1.5.0
Add reference/dereference method to MvcGraph
Enhanced navigation controller:
* allow config controller easier
* allow call back after navigation is settled
Fix issue that controllers configured by navigationController is not released correctly

Version: 1.4.1
* Able to initialize the controller state referenced by next navigating fragment and retain the state until the navigation is fully performed when the navigation is requested directly via NavigationController in MvcGraph.use method.
* Cached instances will be dereferenced and disposed when the instance is referenced by the fields with same variable name in both super and current class.
Expand Down
4 changes: 2 additions & 2 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -73,8 +73,8 @@ ext {
gitUrl = 'https://github.com/kejunxia/AndroidMvc.git' // Git repository URL
version = [
major: 1,
minor: 4,
patch : 1
minor: 5,
patch : 0
]
libGroup = 'com.shipdream'
libVersion = "${version.major}.${version.minor}.${version.patch}"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/*
* Copyright 2015 Kejun Xia
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.shipdream.lib.android.mvc;

/**
* Object has callback on construction
*/
public interface Constructable {
/**
* Execute onConstruct logic of given object
*/
void onConstruct();
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@

package com.shipdream.lib.android.mvc;

/**
* Object has callback on disposal
*/
public interface Disposable {
/**
* Execute onDisposed logic of given object
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,11 @@

package com.shipdream.lib.android.mvc;

import com.shipdream.lib.android.mvc.controller.NavigationController;
import com.shipdream.lib.android.mvc.controller.internal.AsyncTask;
import com.shipdream.lib.android.mvc.controller.internal.BaseControllerImpl;
import com.shipdream.lib.android.mvc.controller.internal.Navigator;
import com.shipdream.lib.android.mvc.controller.internal.Preparer;
import com.shipdream.lib.android.mvc.event.bus.EventBus;
import com.shipdream.lib.android.mvc.event.bus.annotation.EventBusC2C;
import com.shipdream.lib.android.mvc.event.bus.annotation.EventBusC2V;
Expand Down Expand Up @@ -79,7 +82,6 @@
* <p/>
*/
public class MvcGraph {
List<Provider> cachedInstancesBeforeNavigation = new ArrayList<>();
private Logger logger = LoggerFactory.getLogger(getClass());
ScopeCache singletonScopeCache;
DefaultProviderFinder defaultProviderFinder;
Expand Down Expand Up @@ -182,12 +184,36 @@ public void clearOnProviderFreedListeners() {
graph.clearOnProviderFreedListeners();
}

/**
* Reference an injectable object and retain it. Use
* {@link #dereference(Object, Class, Annotation)} to dereference it when it's not used
* any more.
* @param type the type of the object
* @param qualifier the qualifier
* @return
*/
public <T> T reference(Class<T> type, Annotation qualifier)
throws ProviderMissingException, ProvideException, CircularDependenciesException {
return graph.reference(type, qualifier, Inject.class);
}

/**
* Dereference an injectable object. When it's not referenced by anything else after this
* dereferencing, release its cached instance if possible.
* @param type the type of the object
* @param qualifier the qualifier
*/
public <T> void dereference(T instance, Class<T> type, Annotation qualifier)
throws ProviderMissingException {
graph.dereference(instance, type, qualifier, Inject.class);
}

/**
* Same as {@link #use(Class, Annotation, Consumer)} except using un-qualified injectable type.
* @param type The type of the injectable instance
* @param consumer Consume to use the instance
*/
public <T> void use(Class<T> type, Consumer<T> consumer) {
public <T> void use(final Class<T> type, final Consumer<T> consumer) {
try {
graph.use(type, Inject.class, consumer);
} catch (PokeException e) {
Expand All @@ -202,6 +228,7 @@ public <T> void use(Class<T> type, Consumer<T> consumer) {
* it doesn't hold the instance like the field marked by {@link Inject} that will retain the
* reference of the instance until {@link #release(Object)} is called. However, in the
* scope of {@link Consumer#consume(Object)} the instance will be held.
*
* <p>For example,</p>
* <pre>
interface Os {
Expand Down Expand Up @@ -292,12 +319,20 @@ public void consume(Os instance) {

mvcGraph.release(device); //OsReferenceCount = 0
* </pre>
*
* <p><b>Note that, if navigation is involved in {@link Consumer#consume(Object)}, though the
* instance injected is still held until consume method returns, the injected instance may
* loose its state when the next fragment is loaded. This is because Android doesn't load
* fragment immediately by fragment manager, instead navigation will be done in the future main
* loop. Therefore, if the state of an injected instance needs to be carried to the next fragment
* navigated to, use {@link NavigationController#navigate(Object)}.{@link Navigator#with(Class, Annotation, Preparer)}</b></p>
*
* @param type The type of the injectable instance
* @param qualifier Qualifier for the injectable instance
* @param consumer Consume to use the instance
* @throws MvcGraphException throw when there are exceptions during the consumption of the instance
*/
public <T> void use(Class<T> type, Annotation qualifier, Consumer<T> consumer) {
public <T> void use(final Class<T> type, final Annotation qualifier, final Consumer<T> consumer) {
try {
graph.use(type, qualifier, Inject.class, consumer);
} catch (PokeException e) {
Expand All @@ -314,11 +349,7 @@ public <T> void use(Class<T> type, Annotation qualifier, Consumer<T> consumer) {
public void inject(Object target) {
try {
graph.inject(target, Inject.class);
} catch (ProvideException e) {
throw new MvcGraphException(e.getMessage(), e);
} catch (ProviderMissingException e) {
throw new MvcGraphException(e.getMessage(), e);
} catch (CircularDependenciesException e) {
} catch (PokeException e) {
throw new MvcGraphException(e.getMessage(), e);
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package com.shipdream.lib.android.mvc;

public class MvcGraphException extends RuntimeException {
MvcGraphException(String message, Throwable cause) {
public MvcGraphException(String message, Throwable cause) {
super(message, cause);
}
}
Original file line number Diff line number Diff line change
@@ -1,43 +1,17 @@
package com.shipdream.lib.android.mvc;

import com.shipdream.lib.android.mvc.controller.NavigationController;
import com.shipdream.lib.poke.Provider;
import com.shipdream.lib.poke.ScopeCache;

import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

/**
* Helper class to work with MvcGraph. Internal use only. Don't use it in your app.
*/
public class __MvcGraphHelper {
/**
* Internal use. Don't call it in app directly.
*/
public static void retainCachedObjectsBeforeNavigation(MvcGraph mvcGraph) {
mvcGraph.cachedInstancesBeforeNavigation.clear();
//Retain all cached items before navigation.
Collection<ScopeCache.CachedItem> cachedItems = mvcGraph.singletonScopeCache.getCachedItems();
for (ScopeCache.CachedItem cachedItem : cachedItems) {
Provider provider = cachedItem.getProvider();
if (provider != null) {
mvcGraph.cachedInstancesBeforeNavigation.add(provider);
provider.retain();
}
}
}

/**
* Internal use. Don't call it in app directly.
*/
public static void releaseCachedItemsAfterNavigation(MvcGraph mvcGraph) {
//Release all cached items after the fragment navigated to is ready to show.
for (Provider provider : mvcGraph.cachedInstancesBeforeNavigation) {
if (provider != null) {
provider.release();
}
}
mvcGraph.cachedInstancesBeforeNavigation.clear();
}

/**
* Internal use. Gets all cached items this cache still manages
* @return The collection of cached times
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
package com.shipdream.lib.android.mvc.controller;

/**
*
* Base controller interface.
*/
public interface BaseController<MODEL> {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

import com.shipdream.lib.android.mvc.MvcGraph;
import com.shipdream.lib.android.mvc.NavLocation;
import com.shipdream.lib.android.mvc.controller.internal.Navigator;
import com.shipdream.lib.android.mvc.event.BaseEventC2C;
import com.shipdream.lib.android.mvc.event.ValueChangeEventC2V;
import com.shipdream.lib.poke.Consumer;
Expand All @@ -26,7 +27,16 @@
* Controller to navigate among different fragments in the SAME activity.
*/
public interface NavigationController extends BaseController<NavigationController.Model> {

/**
* Initiates a {@link Navigator} to start navigation.
* @param sender Who wants to navigate
* @return A new instance of {@link Navigator}
*/
Navigator navigate(Object sender);

/**
*
* Navigate to a new location. Current location will be saved/stacked into history which can be
* popped out by {@link #navigateBack(Object, String)} or {@link #navigateTo(Object, String, String)}.
* Navigation only takes effect when the given locationId is different from the current location
Expand All @@ -46,9 +56,13 @@ public interface NavigationController extends BaseController<NavigationControlle
* and ready to show.
* </p>
*
* <p><b>Deprecated: use {@link #navigate(Object)} instead</b></p>
*
* @param sender Who wants to navigate
* @param locationId The id of the location navigate to
*
*/
@Deprecated
void navigateTo(Object sender, String locationId);

/**
Expand All @@ -73,20 +87,26 @@ public interface NavigationController extends BaseController<NavigationControlle
* and ready to show.
* </p>
*
* <p><b>Deprecated: use {@link #navigate(Object)} instead</b></p>
*
* @param sender Who wants to navigate
* @param locationId The id of the location navigate to
* @param clearTopToLocationId Null if all history locations want to be cleared otherwise, the
* id of the location the history will be exclusively cleared up to
* which will be the second last location after navigation.
*/
@Deprecated
void navigateTo(Object sender, String locationId, String clearTopToLocationId);

/**
* Navigates back. If current location is null it doesn't take any effect otherwise
* raises a {@link EventC2V.OnLocationBack} event when there is a previous location.
*
* <p><b>Deprecated: use {@link #navigate(Object)} instead</b></p>
*
* @param sender Who wants to navigate back
*/
@Deprecated
void navigateBack(Object sender);

/**
Expand All @@ -95,19 +115,39 @@ public interface NavigationController extends BaseController<NavigationControlle
* navigate to location with given locationId and clear history prior to it. Then a
* {@link EventC2V.OnLocationBack} event will be raised.
*
* <p><b>Deprecated: use {@link #navigate(Object)} instead</b></p>
*
* @param sender Who wants to navigate
* @param toLocationId Null when needs to navigate to the very first location and all history
* locations will be above it will be cleared. Otherwise, the id of the
* location where the history will be exclusively cleared up to. Then this
* location will be the second last one.
*/
@Deprecated
void navigateBack(Object sender, String toLocationId);

/**
* Event t
*/
interface EventC2V {
abstract class OnLocationChanged extends ValueChangeEventC2V<NavLocation> {
private final Navigator navigator;

public OnLocationChanged(Object sender, NavLocation lastValue, NavLocation currentValue,
Navigator navigator) {
super(sender, lastValue, currentValue);
this.navigator = navigator;
}

public Navigator getNavigator() {
return navigator;
}
}

/**
* Event to notify views navigation will move forward.
*/
class OnLocationForward extends ValueChangeEventC2V<NavLocation> {
class OnLocationForward extends OnLocationChanged {
private boolean clearHistory;
private NavLocation locationWhereHistoryClearedUpTo;

Expand All @@ -120,8 +160,9 @@ class OnLocationForward extends ValueChangeEventC2V<NavLocation> {
* @param locationWhereHistoryClearedUpTo If need to clear location, up to where
*/
public OnLocationForward(Object sender, NavLocation lastValue, NavLocation currentValue,
boolean clearHistory, NavLocation locationWhereHistoryClearedUpTo) {
super(sender, lastValue, currentValue);
boolean clearHistory, NavLocation locationWhereHistoryClearedUpTo,
Navigator navigator) {
super(sender, lastValue, currentValue, navigator);
this.clearHistory = clearHistory;
this.locationWhereHistoryClearedUpTo = locationWhereHistoryClearedUpTo;
}
Expand All @@ -147,12 +188,12 @@ public NavLocation getLocationWhereHistoryClearedUpTo() {
/**
* Event to notify views navigation will move backward.
*/
class OnLocationBack extends ValueChangeEventC2V<NavLocation> {
class OnLocationBack extends OnLocationChanged {
private boolean fastRewind;

public OnLocationBack(Object sender, NavLocation lastValue, NavLocation currentValue,
boolean fastRewind) {
super(sender, lastValue, currentValue);
boolean fastRewind, Navigator navigator) {
super(sender, lastValue, currentValue, navigator);
this.fastRewind = fastRewind;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
package com.shipdream.lib.android.mvc.controller.internal;


import com.shipdream.lib.android.mvc.Constructable;
import com.shipdream.lib.android.mvc.Disposable;
import com.shipdream.lib.android.mvc.StateKeeper;
import com.shipdream.lib.android.mvc.StateManaged;
Expand All @@ -36,10 +37,10 @@
import javax.inject.Inject;

/**
*
* Base controller implementation.
*/
public abstract class BaseControllerImpl<MODEL> implements BaseController<MODEL>,
StateManaged<MODEL>, Disposable {
StateManaged<MODEL>, Constructable, Disposable {
interface AndroidPoster {
void post(EventBus eventBusC2V, BaseEventC2V eventC2V);
}
Expand Down
Loading