Hi Mark,
I've been trying to combine the use of cwac-endless (cwace) and cwac-
thumbnail (cwact). Here's some feedback & question about that.
In my own code I was using SoftReferences, but like as mentioned <a
href="
http://blog.jteam.nl/2009/09/17/exploring-the-world-of-android-
part-2/">here</a> by you: it does work, but SoftReferences seem to get
garbage collected really fast (too fast?), so scrolling up & down fast
still becomes notably "choppy"; not in an unusable way, but still ...
it could be better. Thus I went on a quest for the ultimate solution,
and that's how I ended up here :)
Immediately one question pops up: it seems you don't use SoftReference
anymore in your code (or I can't search :). The nice thing about
SoftReference is that it should prevent an OutOfMemory exception
because it cleans up before that should happen (see <a href="http://
developer.android.com/reference/java/lang/ref/
SoftReference.html">here</a>).
How safe is your solution regarding OOM exceptions? I see you use a
maxSize with LRU algorithm, but those don't prevent an OOM.
So I tried the ThumbnailDemo first. That behaved quite strange: when
you start it for the very first time, you have to enter your twitter
username + password. But there are no buttons or whatsoever! So I just
waited but nothing happened, the username+password screen just stayed
on! Hitting the back button didn't do anything either (or it seemed).
Then after a while it did seem to do something & the username+password
screen disappeared & I saw a fine smooth scrolling list of tweets. It
would be nice if the Demo would be a bit more intuitive, like with a
"Login" button or something & then automatically show/go back to the
tweets page.
So then it was time for me to integrate cwace and cwact into my own
not-so-smooth-scrolling ListView + Adapter. Note that I already
implemented the optimization tips like using convertView &
ViewWrapper.
First I put in cwace, pretty smooth. Tricky part for me was that I
still wanted to show some text when nothing is found by the background
task. In rebindPendingView() I was replacing the progress-image part
via View.VISIBILE), but still the text wouldn't show! I figured out
that the reason for that is because the listadapter is empty (nothing
added in appendInBackground()). So now I manually add a dummy item to
that listadapter such that at least 1 entry is in there; and indeed
after doing that the "nothing found" text will be shown.
Maybe for a next version you can add a View as return to
rebindPendingView() indicating that that one should be shown in any
case? Hmm, not sure if that is the cleanest solution...
I constructed the adapters like this in my ListActivity:
List<MyData> myData = new ArrayList<MyData>();
MyAdapter myAdapter = new MyAdapter( myData, ... );
MyAdapterEndless myAdapterEndless = new MyAdapterEndless
( myAdapter, ... );
setListAdapter( myAdapterEndless );
Next: adding cwact to the above was quite tricky. I first tried this
in my ListActivity:
List<MyData> myData = new ArrayList<MyData>();
MyAdapter myAdapter = new MyAdapter( myData, ... );
MyAdapterEndless myAdapterEndless = new MyAdapterEndless
( myAdapter, ... );
ThumbnailAdapter thumbnailAdapter = new ThumbnailAdapter( this,
myAdapterEndless, cache, imageIDs );
setListAdapter( myAdapterEndless );
That *almost* immediately worked. What didn't work:
- The image in the first entry (the pendingView) was never put in. I
found out why: in rebindPendingView() I replaced all Views correctly,
but ThumbnailAdapter.getView() never gets called anymore for that
(pendingview) position. Makes sense: ThumbnailAdapter doesn't know
anything about EndlessAdapter's "internal" updates like
rebindPendingView. Am I right?
- One time when I was scrolling down I got a nullpointer exception in
rebindPendingView(). The 'convertView' parameter was null! Couldn't
reproduce this one anymore, but quite odd I'd say. Any idea how this
could have happened? How could the pending-view have turned null in
the mean time?
In the end what did work (after a lot of trial and error):
List<MyData> myData = new ArrayList<MyData>();
MyAdapter myAdapter = new MyAdapter( myData, ... );
ThumbnailAdapter thumbnailAdapter = new ThumbnailAdapter( this,
myAdapter, cache, imageIDs );
MyAdapterEndless myAdapterEndless = new MyAdapterEndless
( myAdapter, ... );
setListAdapter( myAdapterEndless );
(note that I swapped thumbnailadapter and endlessadapter)
Additionally, in rebindPendingView() I added an explicit call to
thumbnailAdapter.getView(), so it would try to get the image for the
replaced entry too.
My big question is: did I do it the right way in the end, or is there
a better way? I've got the feeling it can be done cleaner, but I can
also see that the cwace's-pendingView-trick can confuse wrapping
adapters...
Oh, and a few other feedback things:
- Why didn't you make the ThumbnailDemo more like the other demos,
where the demo class extends the adapter being demoed?
- In ThumbnailAdapter.java, the comment for getView() seems a copy &
paste from EndlessAdapter?
- I see you log errors via Log.e(...). It would be handy to provide a
flag one can set to turn on/off this kind of logging (based on <a
href="
http://groups.google.com/group/android-developers/browse_thread/
thread/afc9ef79afa4ec4b?pli=1">this recommendation</a>)
- It would be great if you could put a picture on your site how cwact
works together with all the other packages you're providing.
Regards,
Marco