rgladwell
-
03:43:16 pm on January 19, 2011 |
The Problem: Adapters cannot be injected into Activities because the BaseAdapter constructor requires a Context be passed to it.
The Solution: Create a new Guice @InjectAdapter annotation and TypeListener that dynamically creates an adapter on injection, passing the inject Activity to the adapter’s constructor.
So, our activity code might look something like this:
public class SampleActivity extends GuiceListActivity { @Inject List<Integer> items; @InjectAdapter @Override public void setListAdapter(ListAdapter adapter) { super.setListAdapter(adapter); } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Log.i(TAG, "searching for local profiles"); setContentView(R.layout.main); } }
Out module might then have the following code:
bindListener(Matchers.any(), new AdapterTypeListener(binder())); bind(ListAdapter.class).to(LocalProfilesAdapter.class);
Where AdapterTypeListener is defined as follows:
public <T> void hear(TypeLiteral<T> typeLiteral, TypeEncounter<T> typeEncounter) { Class<T> type = typeLiteral.getRawType(); for (Field field : type.getDeclaredFields()) { if (Adapter.class.isAssignableFrom(field.getType()) && field.isAnnotationPresent(InjectAdapter.class)) { typeEncounter.register(new AdapterMembersInjector<T>(field)); } } for (Method method : type.getDeclaredMethods()) { if(method.isAnnotationPresent(InjectAdapter.class)) { typeEncounter.register(new AdapterMembersInjector<T>(method)); } } }
Last we could define AdapterMembersInjector as follows:
public class AdapterMembersInjector<T> implements MembersInjector<T> { private Field field; private Method setter; TypeEncounter<T> typeEncounter; AdapterMembersInjector(Field field, TypeEncounter<T> typeEncounter) { this.field = field; field.setAccessible(true); } AdapterMembersInjector(Method setter, TypeEncounter<T> typeEncounter) { this.setter = setter; setter.setAccessible(true); } public void injectMembers(T activity) { Adapter adapter; if(field != null) { try { field.set(activity, adapter); } catch (IllegalAccessException e) { throw new RuntimeException(e); } } else if(setter != null) { try { setter.invoke(activity, adapter); } catch (IllegalArgumentException e) { throw new RuntimeException(e); } catch (IllegalAccessException e) { throw new RuntimeException(e); } catch (InvocationTargetException e) { throw new RuntimeException(e); } } } }
The problem is how do we create a reference to Adapter in the above MembersInjector, with all the correct dependencies including the Activity context injected into it’s constructor?
Tweets that mention Proposal: Adapter injector for #Roboguice « Ricardo's Blog -- Topsy.com 4:20 pm on January 19, 2011 | # |
[…] This post was mentioned on Twitter by Ricardo Gladwell. Ricardo Gladwell said: Proposal: Adapter injector for #Roboguice: The Problem: Adapters cannot be injected into Activities because the … http://bit.ly/fkYUay […]
noah 6:10 pm on January 19, 2011 | # |
RoboGuice can inject Context. Just add @Inject to the adapter constructor.
rgladwell 6:16 pm on January 19, 2011 | # |
Lol whoops I didn’t know that.makes this while article redundant. Thanks for the tip!