Android Scrollable Widgets


Introduction
This was the most obscure thing to me in Android development.  I'd read on many forums that in the standard Android OS SDK there was nothing available to allow for developing widgets that you could do to add a Scrollable ListView.

It's worth noting first that when developing widgets you can't access views like you would in an Activity. i.e no more findViewById(R.id.someview);

Instead you're required to go through an intermediary or delegate.  Something that DOES have access to them.  This thing is a RemoteViews object and it can see and access all views in your widgets layout.

The only downside is that the RemoteViews object is not as versatile as you'd expect and can only do so much.

More specifically :


A RemoteViews object (and, consequently, an App Widget) can support the following layout classes:
And the following widget classes:

 So if you have it set in your mind that I'm going to add a ScrollView into your widget....THINK AGAIN!



Custom Home Screen Launchers to the Rescue
This is where custom Home Screen Launchers come into play.  The developers that designed them felt the same obvious pain you're feeling right now and saw to it that there was an easy way developers could have this feature when developing widgets.

To make it easy they built in the functionality into their respective Launcher apps. Namely Home++, Launcher Pro, ADW Launcher..etc.

Please note from here on I'm only referring to Custom Home Launchers not the stock standard one that's bundled with the Android OS.

The basic rundown a developer needs to understand in order to use this is :

  • The Home Screen Launcher renders the scrollable Listview and gives it life
  • You must provide the Launcher with all the information describing the scrollable list view the Launcher needs before it can instantiate your scrollable list view.
  • You must provide your data using a ContentProvider that offers say a database to ContentResolvers.
 Whoa!!! You've lost me there, why does this have to be so tricky?  Tricky to some others it's second nature but for me tricky was the case.  I hadn't used ContentProviders before and my understanding of them was that you only used them when you wanted to share data with apps????

Well that is exactly what you need to do.  Since the Launcher app is the thing that renders the scrollable list you MUST provide the data in YOUR app to the the Launcher app.

Walkthrough
Let's walk you through my perception of what goes on from start to finish.

  1. You're widget instance is created as per normal.
  2. The Custom Home Screen Launcher (ADW / HPP / LPP) draws your widget and when finished sends an ACTION_READY intent to your widget.
  3. You catch this intent in your widgets onReceive() method and prepare a reply intent that will describe the scrollable list you want the Home Screen Launcher to create for you.  It also mentions what ContentProvider to use to populate this scrollable ListView.
  4. The reply intent you create has an action ACTION_WIDGET_START_SCROLL. This tells the Launcher what and how to render you a scrollable list.
  5. The Launcher receives your intent you replied and it proceeds to connect your widgets ContentProvider.
  6. It queries the ContentProvider and gets the returned dataset your ContentProvider is......PROVIDING.
  7. The Launcher then begins to create clickable child items and add them to a scrollable ListView.
  8. In the case that YOUR ContentProvider sends out a notifyChange() the Launcher will update the scrollable ListView by requerying the ContentProvider then redrawing the ListView.

That's it.  Sounds pretty simple.

Important things you should know :
  • The Home Screen Launcher is expecting a specially made intent.  So you will need to import this class into your project mobi.intuitit.android.content.LauncherIntent.java found here : LauncherIntent.java
  • When creating your reply intent you put a lot of Extras into it.  One important thing to put in is the requery boolean.  This is required if you would like the Launcher to be able to requery your ContentProvider in the event that it receives a notifyChange(), especially important if using a database.
  •  Your reply intent MUST BE UNIQUE! You do this by setting the URI value to something unique like CONTENT_URI + widget ID.  Read the link below on ContentProviders for more info on URI's.
  •  In order for the Launcher to know to update the list you MUST send out a notifyChange() from your DataProvider to it's resolvers.
  •  There will be no update if the URI you send out does not match the resolver's URI (in this case the Launcher's URI, Remember you defined this URI in your reply intent).
Resources to help you on your way:





    Comments

    1. Would it be possible to create a widget that makes use of custom homescreen launchers on older Androids and the RemoteViewService on Honeycomb onwards Android devices (without custom homescreen launcher)??

      Android Pro Widgets seem to be able to do so but I can't figure out how..

      ReplyDelete
    2. Implementation-wise, you should look at http://code.google.com/p/scrollablecontacts/

      It has ImplSWA and ImplHC for such implementation-differences.

      You can hide the Honeycomb-widget on older Android-versions. The source of SeriesGuide does this, its done with an XML-boolean set to true in values-v11 directory, and used in AndroidManifest.xml, I think. You can't hide widgets for custom launcher-widgets, though, I think.

      ReplyDelete
    3. You can also post questions here: https://groups.google.com/forum/?fromgroups#!forum/android-appwidget-extensions

      The experts regarding this topic are posting there, too (author of ADWlauncher2, author of PureCalendar Widget etc).

      ReplyDelete
    4. I have indeed referred to both sources for further information during my learning, you might even find a few questions I asked in the google code group to lol.

      Thanks for the links Arne.

      ReplyDelete

    Post a Comment

    Popular posts from this blog

    Lenovo Y500 - Ubuntu 12.04 LTS Installation Guide

    Balco 3D Printer Z Brace Mod

    Teensy LCD Display for MSI Afterburner 3.0