
roboguice.inject.ContextScope Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of roboguice Show documentation
Show all versions of roboguice Show documentation
A framework for using Google Guice dependency injection in Android.
/*
* Copyright 2009 Michael Burton
*
* 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 roboguice.inject;
import java.lang.ref.WeakReference;
import java.util.HashMap;
import java.util.Map;
import java.util.Stack;
import roboguice.util.RoboContext;
import com.google.inject.Key;
import com.google.inject.Provider;
import com.google.inject.Scope;
import android.app.Application;
import android.content.Context;
import android.content.ContextWrapper;
/**
* Scopes the injector based on the current context.
*
* Any usage of this class must call #enter(Context) before performing any operations with the
* injector, and do so within a synchronized block on the ContextScope.class, eg:
*
* synchronized(ContextScope.class) {
* scope.enter(context);
*
* // do something, eg.
* // injector.injectMembers(this);
* }
*
* If you're using ContextScopedRoboInjector (which is the RoboGuice default), this is done for you automatically.
*
* If you're trying to use a Provider, you must either use ContextScopedProvider instead, or do your own synchronization
* and scope.enter() call.
*
* @see ContextScopedRoboInjector
* @author Mike Burton
*/
public class ContextScope implements Scope {
protected ThreadLocal>> contextThreadLocal = new ThreadLocal>>();
protected Map,Object> applicationScopedObjects = new HashMap, Object>();
protected Application application;
public ContextScope(Application application) {
this.application = application;
enter(application);
}
/**
* You MUST perform any injector operations inside a synchronized(ContextScope.class) block that starts with
* scope.enter(context) if working in a multithreaded environment
*
* @see ContextScope
* @see ContextScopedRoboInjector
* @see ContextScopedProvider
* @param context the context to enter
*/
public void enter(Context context) {
// BUG synchronizing on ContextScope.class may be overly conservative
synchronized (ContextScope.class) {
final Stack> stack = getContextStack();
final Map,Object> map = getScopedObjectMap(context);
// Mark this thread as for this context
stack.push(new WeakReference(context));
// Add the context to the scope for key Context, Activity, etc.
Class> c = context.getClass();
do {
map.put(Key.get(c), context);
c = c.getSuperclass();
} while( c!=Object.class );
}
}
public void exit(Context context) {
synchronized (ContextScope.class) {
final Stack> stack = getContextStack();
final Context c = stack.pop().get();
if( c!=null && c!=context )
throw new IllegalArgumentException(String.format("Scope for %s must be opened before it can be closed",context));
}
}
public Provider scope(final Key key, final Provider unscoped) {
return new Provider() {
public T get() {
synchronized (ContextScope.class) {
final Stack> stack = getContextStack();
final Context context = stack.peek().get(); // The context should never be finalized as long as the provider is still in memory
final Map, Object> objectsForScope = getScopedObjectMap(context);
if( objectsForScope==null )
return null; // May want to consider throwing an exception here (if provider is used after onDestroy())
@SuppressWarnings({"unchecked"}) T current = (T) objectsForScope.get(key);
if (current==null && !objectsForScope.containsKey(key)) {
current = unscoped.get();
objectsForScope.put(key, current);
}
return current;
}
}
};
}
public Stack> getContextStack() {
Stack> stack = contextThreadLocal.get();
if( stack==null ) {
stack = new Stack>();
contextThreadLocal.set(stack);
}
return stack;
}
protected Map,Object> getScopedObjectMap(final Context origContext) {
Context context = origContext;
while( !(context instanceof RoboContext) && !(context instanceof Application) && context instanceof ContextWrapper )
context = ((ContextWrapper)context).getBaseContext();
// Special case for application so that users don't have to manually set up application subclasses
if( context instanceof Application )
return applicationScopedObjects;
if( !(context instanceof RoboContext) )
throw new IllegalArgumentException(String.format("%s does not appear to be a RoboGuice context (instanceof RoboContext)",origContext));
return ((RoboContext)context).getScopedObjectMap();
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy