package com.tale.prettybundle; import android.app.Activity; import android.app.Fragment; import android.app.Service; import android.content.Intent; import android.os.Bundle; import android.util.Log; import java.util.LinkedHashMap; import java.util.Map; /** * Bundle "injection" utilities. Use this class to simplify binding bundle values. * Injecting bundle from your activity is as easy as: * <pre><code> * public class ExampleActivity extends Activity { * {@literal @}Extra String stringExtra1; * {@literal @}Extra String stringExtra2; * {@literal @}Override protected void onCreate(Bundle savedInstanceState) { * super.onCreate(savedInstanceState); * PrettyBundle.inject(this); * } * } * </code></pre> */ public final class PrettyBundle { public static final String INJECTOR_SUFFIX = "$$BundleInjector"; public static final String ANDROID_PREFIX = "android."; public static final String JAVA_PREFIX = "java."; private PrettyBundle() { throw new AssertionError("No instances."); } private static final String TAG = "PrettyBundle"; private static boolean debug = false; static final Map<Class<?>, Injector<Object>> INJECTORS = new LinkedHashMap<Class<?>, Injector<Object>>(); private static final Injector<Object> NOP_INJECTOR = new Injector<Object>() { @Override public void inject(Object target, Bundle extras) { } }; /** * Control whether debug logging is enabled. */ public static void setDebug(boolean debug) { PrettyBundle.debug = debug; } public static void inject(Activity activity) { if (activity == null) { return; } inject(activity, activity.getIntent().getExtras()); } public static void inject(Fragment fragment) { if (fragment == null) { return; } inject(fragment, fragment.getArguments()); } public static void inject(android.support.v4.app.Fragment fragment) { if (fragment == null) { return; } inject(fragment, fragment.getArguments()); } public static void inject(Service service, Intent intent) { if (service == null) { return; } inject(service, intent == null ? null : intent.getExtras()); } private static void inject(Object target, Bundle extras) { Class<?> targetClass = target.getClass(); try { if (debug) Log.d(TAG, "Looking up view injector for " + targetClass.getName()); Injector<Object> injector = findInjectorForClass(targetClass); if (injector != null) { injector.inject(target, extras); } } catch (RuntimeException e) { throw e; } catch (Exception e) { throw new RuntimeException("Unable to inject views for " + target, e); } } private static Injector<Object> findInjectorForClass(Class<?> cls) throws IllegalAccessException, InstantiationException { Injector<Object> injector = INJECTORS.get(cls); if (injector != null) { if (debug) Log.d(TAG, "HIT: Cached in injector map."); return injector; } String clsName = cls.getName(); if (clsName.startsWith(ANDROID_PREFIX) || clsName.startsWith(JAVA_PREFIX)) { if (debug) Log.d(TAG, "MISS: Reached framework class. Abandoning search."); return NOP_INJECTOR; } try { Class<?> injectorClass = Class.forName(clsName + INJECTOR_SUFFIX); //noinspection unchecked injector = (Injector<Object>) injectorClass.newInstance(); if (debug) Log.d(TAG, "HIT: Class loaded injection class."); } catch (ClassNotFoundException e) { if (debug) Log.d(TAG, "Not found. Trying superclass " + cls.getSuperclass().getName()); injector = findInjectorForClass(cls.getSuperclass()); } INJECTORS.put(cls, injector); return injector; } }