@InjectView with Adapter

1,716 views
Skip to first unread message

thevery

unread,
Jan 25, 2011, 4:05:41 PM1/25/11
to roboguice
Is it possible to use @InjectView within adapter? Or maybe even with
using convertView/viewHolder/itemViewType?

Michael Burton

unread,
Jan 25, 2011, 4:21:49 PM1/25/11
to robo...@googlegroups.com
Hi Thevery,

Are you talking about android.widget.Adapter? Not at the moment. The problem is that most adapters use new() to create new views, which means that Guice isn't constructing the view instances, which means that it doesn't have an opportunity to do injection.

It might be an interesting experiment to come up with an adapter pattern that integrated with Guice, but no one has tried it yet to my knowledge.

Cheers,
Mike

--
http://about.me/michaelburton


On Jan 25, 2011, at 4:05 PM, thevery wrote:

> Is it possible to use @InjectView within adapter? Or maybe even with
> using convertView/viewHolder/itemViewType?
>

> --
> You received this message because you are subscribed to the Google Groups "roboguice" group.
> To post to this group, send email to robo...@googlegroups.com.
> To unsubscribe from this group, send email to roboguice+...@googlegroups.com.
> For more options, visit this group at http://groups.google.com/group/roboguice?hl=en.
>

Donn Felker

unread,
Jan 25, 2011, 4:26:59 PM1/25/11
to robo...@googlegroups.com
Something else to keep in mind ...

The ListView also recycles views through the "convertView" object to save on object initialization and view inflation. If an implementation did arise, it would want to take care of that. We'd almost need a RoboAdapter of some sense (unless there already is and I've looked over it).



Donn Felker
Author of Android App Dev for Dummies & Intro to Android Development (tekpub.com)
Microsoft ASPInsider, MCTS, MCP, CSM, ITIL
http://blog.donnfelker.com
http://twitter.com/donnfelker

Ildar Karimov

unread,
Jan 25, 2011, 4:39:32 PM1/25/11
to robo...@googlegroups.com
Yes, I'm talikng about android.widget.Adapter, more specifically about
BaseAdapter.
At least in this case you inflate views manually in getView (or reuse
convertView), so RoboBaseAdapter should be possible and will be very
useful especially with integrated convertView/viewHolder and probably
even itemViewType.

2011/1/26 Michael Burton <mi...@niskala.org>:

Manfred Moser

unread,
Jan 25, 2011, 5:03:36 PM1/25/11
to robo...@googlegroups.com
It would be cool to have a RoboBaseAdapter and some of the others available. We would have to design it that it either already implements or at least allows one to implement the pattern recommended by Romain Guy at the list view performance talk (see 2010 google io recordings).

Donn Felker

unread,
Jan 25, 2011, 5:58:16 PM1/25/11
to robo...@googlegroups.com
Manfred,

That was exactly what I was referencing when I spoke of converting views. :) Great minds think alike.


Donn Felker
Author of Android App Dev for Dummies & Intro to Android Development (tekpub.com)
Microsoft ASPInsider, MCTS, MCP, CSM, ITIL
http://blog.donnfelker.com
http://twitter.com/donnfelker


Ildar Karimov

unread,
Jan 25, 2011, 7:12:05 PM1/25/11
to robo...@googlegroups.com
Let's sum up: @InjectView is not available within BaseAdapter, but
would be possible with some RoboBaseAdapter.
I'm interested in contributing this feature, but unfortunately I don't
know where should I start - could someone please give some directions
in creating Robo* classes (BaseAdapter with caching/etc is not a
problem for me)

2011/1/26 Donn Felker <do...@donnfelker.com>:

Michael Burton

unread,
Jan 26, 2011, 12:15:41 PM1/26/11
to robo...@googlegroups.com
A RoboBaseAdapter would be nice. CursorAdapter has a "newView" method which is responsible for creating new views. Perhaps using a similar pattern here would work well.

One obvious disadvantage with a RoboBaseAdapter is that it won't work with existing adapter classes. :( Perhaps we could supplement it with a provider or factory that any adapter could use to create a new injected view.

Adam has some experience with AssistedInject and adapters which may be relevant here. https://groups.google.com/d/msg/roboguice/Wtxd8YVQ9_A/pDs4-6_EZWwJ

--
http://about.me/michaelburton

Ildar Karimov

unread,
Jan 29, 2011, 8:12:42 PM1/29/11
to robo...@googlegroups.com
First (very early draft) version of RoboBaseAdapter here:
https://gist.github.com/802359

Some simple implementation here:
https://gist.github.com/802366

In activity you should use something like
buttonList.setAdapter(new RoboBaseAdapterButton(this,
R.layout.list_item_button, Arrays.asList("button1",
"button2", "button3")));

Some remarks:
1) At the moment all it can do is @InjectView support inside adapter
using same technique as RoboActivity, but doesn't use ContextScope and
thus more 'coupled' with adapter and view parameters:
1.1) Unfortunately it isn't possible to use ViewMembersInjector from
ViewListener because findViewById is called explicitely on Activity
and it is not possible to call it on View, so scope can't be used
1.2) I'm not sure it is ok to 'link' directly to BaseAdapter and View
or it should be provided like AdapterScope or something like this.
1.3) 'Magic' binding preparation is done in the helper method init()
in constructor to be easier reusable of multiple constructors.
1.3.1) But in RoboGuice you guys usually duplicate initialization
calls, not separate (e.g. setContentView in RoboListActivity).
1.3.2) It is ok to get LayoutInflater explicitely (inflater =
LayoutInflater.from(context);) or I should better inject it?
1.3.3) I don't actually like very much prepareFields method call here
but it seems quite impossible to use/reuse injectMembers or
requestStaticInjection because of the same reasons as 1.1 AND because
it should be cached for multiple calls (and ContextScope
implementation is probably can't handle this correctly)
2) All binding 'magic' actually happens inside BaseAdaper.getView().
I'm not 100% sure it is the beast place but it makes usage quite
simple.
3) ViewHolder pattern is not implemented yet - I haven't found best
implementation way yet :( Probably should be dynamically created based
on @InjectView fields
4) No support for getViewTypeCount - actually this makes 3) even more
tricky - you need to have some layoutId<->ViewHolder mapping which
requires some not so easy @InjectView hacks - like creating
@InjectViewInLayout(R.id.view_buton, R.layout.layout_buton)

5) Not a question for the current implementation, but some idea:
probabaly provide some RoboArrayAdapter with BindItemToView interface
method.

P.S Please excuse me for so much question for the first time but I'm
not quite familiar with RoboGuice internals and I would appreciate if
you can comment some of my questions.

Ildar

2011/1/26 Michael Burton <mi...@niskala.org>:

Adam Tybor

unread,
Jan 29, 2011, 9:50:54 PM1/29/11
to robo...@googlegroups.com
1) Assisted Inject does work, there is a performance hit because it seems the TypeListeners are run every time a new instance is requested from the factory.  So far it hasn't bit me performance wise with all that reflection, but it is something to keep in mind.  I use assisted inject for all my long running tasks like web calls and db calls were the overhead of reflection is peanuts compared to the latency of i/o.

2) I think we should invest in using something like child injectors for these types of components.  I recently also starting looking at a RoboDialog with assisted inject and as is mentioned, the normal view listener can't be used because its bound to the activity and ContextScope.

It seems like an easy fix to refactor the ViewListener to take an abstraction like IViewFinder { View findViewById(int id) } instead of Provider<Activity>.

Adam

Adam Tybor

unread,
Jan 29, 2011, 10:19:27 PM1/29/11
to robo...@googlegroups.com
That is a real nice spike!

I am not crazy about the pattern of keeping a reference to the views within the adapter itself.  I think we should follow the view holder pattern and only inject views when they are newly created.  Check this quick fork of your gist out.


Adam

Ildar Karimov

unread,
Jan 30, 2011, 7:57:12 AM1/30/11
to robo...@googlegroups.com
Wow, nice idea - your separate ViewHolder implementation solves both
missing ViewHolder problem and perfectly ready to solve multiple
viewType problem if needed. It also gives some performance boost since
uses less reflection calls.

I'll make some multiviewType-ready implementation and post update
here. For IViewFinder abstraction I should probably wait first for
your or Michael implementation since you understand that 'magic'
better.

Ildar

2011/1/30 Adam Tybor <adam....@gmail.com>:

Michael Burton

unread,
Jan 30, 2011, 1:08:26 PM1/30/11
to robo...@googlegroups.com
That's pretty nice! One issue I see is that it doesn't appear to be doing actual injection on the view. As far as I can tell, it's only doing view injection, which is fine in this case since the view objects are coming from a layout inflater and thus aren't custom, but wouldn't work for custom View objects that rely on @Inject or @InjectResource, for example.

Seems like this shouldn't be too hard to fix, though. We could inject a static Provider<Injector> into BaseAdapter, then use it to get an injector and injector.injectMembers() on the view. This would leverage the existing ViewListener as well as perform all the other types of injection.

Mike

--
http://about.me/michaelburton

Adam Tybor

unread,
Jan 30, 2011, 1:11:18 PM1/30/11
to robo...@googlegroups.com
Thats a nice catch.

The other issue is how to handle multiple view layouts, will we require a single holder type to cover multiple layouts?  Otherwise I think we need to lose the generic.

Adam Tybor

unread,
Jan 30, 2011, 1:23:57 PM1/30/11
to robo...@googlegroups.com
But that actually brings up another interesting issue.  Scoping of the injection.  What if I have a component I want to inject in the holder that is Scoped at the lifetime of the adapter?  I wonder, as John pointed out, if we need to start thinking about child containers for some of this stuff.

It would be real nice if I could get my cursor injected for me in the holder?

public class MyHolder {
  @Inject Cursor theCursor;
  @InjectView(android.R.id.text) TextView text;
  @InjectView(android.R.id.image) CachedImageView image;

  public void bind() {
    text.load(cursor.getString(0))
    image.load(cursor.getString(1));
  }
}
    

Ildar Karimov

unread,
Jan 30, 2011, 2:00:11 PM1/30/11
to robo...@googlegroups.com
Yes, we will probably lose generic, but we can make some interesting thing like
@InjectLayout(R.layout.my_layout)
public class MyHolder<MyType> {
@InjectView(R.id.tv)
TextView tv;

void bind(MyType myType) {

}
}
with different holders for different view types

2011/1/30 Adam Tybor <adam....@gmail.com>:

Reply all
Reply to author
Forward
0 new messages