Android Saga: Pull to Refresh revisited

06/27/2012 § 3 Comments


Previously on Android Saga..

“I find the solution very bizarre, but it worked out and that is what I am using right now. The only thing that still upsets me, is that the feature is not polished enough. It is still sluggish to pull, flicks once in a while, and lacks animation.”

It happens I was wrong. Yesterday I tested the app on the device – precisely a Samsung Galaxy i5500 running API Level 8 – and I was surprised when it didn’t work since all this time I was testing on an emulator running the very same API Level. I know the emulator is different from the device. This is true for the iOS simulator as well. But not THAT different.

Anyways, Johan’s implementation doesn’t work either on Samsung Galaxy i5500 running API Level 8 nor Samsung Galaxy S2 running 4.0.3 (Yes I tried a newer version to see if I was pushing to hard by using an old API version).

I got to a point where I started to think that maybe pull to refresh wasn’t the answer for Android. Actually my girlfriend asked me if I was not trying to put an iOS app into Android. And she had a good point: Android doesn’t support bouncing in the list view, so Android users are not used to pull the list hence they don’t easily discover how to pull to refresh.

Discussing this matter with some co-workers, I was presented with a list of well known Android apps (Twitter, Facebook, LinkedIn…) that actually do a very good pull to refresh. This convinced me that Android apps can be as good as iOS apps.

So I kept looking for other pull to refresh implementations. In the end, I got to Chris Banes’s library.

This time as soon as it worked on the emulator, I tried on both devices I have here and it worked pretty well. In fact, it is as good as Twitter’s pull to refresh.

Now, the interesting fact is: Chris Bane’s implementation needed 6 Java classes (and they are not tiny), 8 XML files and 2 images. His implementation is very interesting and truly had outstanding results. BUT this is TOO MUCH WORK FOR SUCH A SIMPLE FEATURE!

Knowing there are developers and developers (although this guy deserves respect since he is the only one that got a – open source – pull to refresh to properly work on Android), I tried not to think: “On iOS it would take a class for the header view and another to use it. Really.”.

Instead I googled for the Twitter APK file, downloaded it and decompiled it (a pretty painful process – by the way – that requires decompressing the APK, converting smil files to dex, from dex to jar and finally to Java source files). Of course, I wasn’t able to just grab and use their implementation, but that was enough readable code to see that they use just about the same number of files that Chris Bane’s does.

I am sure every file has its meaning and need, but still too much work for this feature. And just to be sure we are in the same page, I am not counting any i18n files neither assets for supporting multiple screen densities whatsoever.

Anyways, I learned two things on all of this:

1. Android apps can be as good as iOS apps
2. #1 requires a lot more work than it takes on iOS (and I am not talking about device fragmentation)

For those that like references, here are the best pull to refresh libraries I tried on Android:

https://github.com/chrisbanes/Android-PullToRefresh
https://github.com/johannilsson/android-pulltorefresh
https://github.com/woozzu/RefreshableListView.git
https://github.com/erikwt/PullToRefresh-ListView

And the tools I used for decompiling Twitter:

http://code.google.com/p/android-apktool/
http://code.google.com/p/smali/
http://code.google.com/p/dex2jar/
http://www.varaneckas.com/jad/

Advertisements

Android Saga: Pull to Refresh

06/25/2012 § Leave a comment


Pull to refresh is an extremely popular UI gesture (that Loren Brichter pioneered in Tweetie) used in a lot of iOS apps. Basically it makes refreshing part of the scroll gesture itself.

The iOS community have had library support for this for a long time – I think that Three20, back in 2010, was the first library to offer this feature out of the box.

This very feature has come to the Android world later on and today many apps use it.

Since I don’t have much experience with Android, the first thing I did was to search for an open source implementation. I found plenty of them in a couple seconds.

(I also found a lot of Android developers thanking the Android open source eco-system for making libraries available as if that wasn’t true for other platforms. iOS as many other mobile platforms counts with a strong open source community too ^^)

The best implementation I found out there was a contribution from Johan Nilsson. Besides the sluggish scrolling and lack of animations, it works pretty well (correct me if I am wrong, but we can’t blame Johan for half the issues here since Android makes it really difficult to have smooth scrolling and bounce animations on ListViews).

I didn’t have any problems to import his library and use his implementation. Specially because he provides a very straightforward demo. The only thing that was really upsetting me though, was that pull to refresh header is supposed to be hidden all the time when the user isn’t scrolling or refreshing the list. And the header was standing there presenting a “Tap to Refresh” message.

That was when I decided to look the code and fix it. To be honest, the idea behind Johan’s implementation is very similar to the iOS approach. But not quite.

Let me tell you why.

On iOS, Pull To Refresh is implemented by the following steps:

1) Create the header view which displays the arrow, the spinner and the text messages
2) Add it to the UIScrollView with a negavite y value
3) Implement the UIScrollView’s delegate to set the contentInset as the header height (therefore making it visible) and ask the controller to refresh the content
4) Once the controller is done, it sets the contentInset to zero (therefore hiding the header view)

On Android, all the implementations I found follow the steps below:

1) Create the header view which displays the arrow, the spinner and the text messages
2) Extend the ListView and implement onAttachedToWindow, setAdapter, onTouchEvent to select the first row (WTF!?)
3) Implement the onScrollListener (equivalent to the UIScrollView’s delegate)
4) Once the controller is done, select the first row so the list scrolls to the top and hides the header if the content is higher then the list view

Although the approaches are very similar, Android’s version is essentially a hack that exploits the optional header in standard ListViews. When the list is displayed, it scrolls to the first item on the list, effectively hiding the header. When the list is short enough to be displayed entirely on screen, no scrolling is necessary, hence the “Tap to Refresh” button is always visible!

After an hour, I didn’t find a way to fix the issue of keeping the header hidden since hiding it would not make it disappear. That is when I came to a StackOverflow post  that basically told me to put the header in a LinearLayout that wraps it’s content, and hide the content so the wrapping LinearLayout collapses when its content is hidden, resulting in the header view being 0dip high and therefore invisible.

I find the solution very bizarre, but it worked out and that is what I am using right now. The only thing that still upsets me, is that the feature is not polished enough. It is still sluggish to pull, flicks once in a while, and lacks animation.

I will get back to this post once I figure out a better solution, if any. I am counting on you – Android devs – to help me out  😉

EDIT:

Found a library that provides a very good user experience. Full story here.

Where Am I?

You are currently browsing entries tagged with Pull to Refresh at iOS Guy.