Leonardo Garcia Fischer

LinkedIn Facebook Twitter Feeds

Hosting Android Widgets – My AppWidgetHost Tutorial

30Jan'12

Written by Leonardo Fischer

Hi,

No, this isn’t another tutorial on how to create Android Widgets. For this, I recommend you the Android SDK or Google. This post is on how to create a simple app that lets the user add and remove widgets, like the Android Home Screen does.

I decided to write this one because I couldn’t find anything on the web saying how to do this. I found how to create this example looking at the Android Home Screen Source Code (AHSSC). So, if you already did this, you may find some variable names similar. You can use this as trails to look yourself on the AHSSC ツ

Initialization

You start by creating two objects. The first is an AppWidgetManager, which will give you the data you need about installed widgets. The second one is an AppWidgetHost, which will keep in memory your widget instances. Latter, your app will handle only the view that will draw the widget:

mAppWidgetManager = AppWidgetManager.getInstance(this);
mAppWidgetHost = new AppWidgetHost(this, R.id.APPWIDGET_HOST_ID);

Selecting the Widget

You start by asking to the AppWidgetHost to allocate resources for a widget instance. It will return an ID for that. Then, you need to start an activity to let the user select which widget he wants to add to your app. You need to give this ID to the activity.

void selectWidget() {
    int appWidgetId = this.mAppWidgetHost.allocateAppWidgetId();
    Intent pickIntent = new Intent(AppWidgetManager.ACTION_APPWIDGET_PICK);
    pickIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
    addEmptyData(pickIntent);
    startActivityForResult(pickIntent, R.id.REQUEST_PICK_APPWIDGET);
}
void addEmptyData(Intent pickIntent) {
    ArrayList customInfo = new ArrayList();
    pickIntent.putParcelableArrayListExtra(AppWidgetManager.EXTRA_CUSTOM_INFO, customInfo);
    ArrayList customExtras = new ArrayList();
    pickIntent.putParcelableArrayListExtra(AppWidgetManager.EXTRA_CUSTOM_EXTRAS, customExtras);
};

Unfortunately, any kind of software has bugs, and here is one of the Android SDK. The Widget API supports that you merge custom widgets of your application with the installed ones. But if you don’t add anything, the Activity that shows the list of widgets to the user crashes with a NullPointerException. The addEmptyData() method above adds some dummy data to avoid this bug. More on this bug here. If you want to add a custom widget, start looking at this point of the AHSSC.

Configuring the Widget

If the user successfully selects a widget from the list (he didn’t pressed “back”), it will return an OK to you as an activity result. The data for this result contains the widget ID. Use it to retrieve the AppWidgetProviderInfo to check if the widget requires any configuration (some widgets does need). If it requires, you need to launch the activity to configure the widget. If not, jump to the next step.

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    if (resultCode == RESULT_OK ) {
        if (requestCode == REQUEST_PICK_APPWIDGET) {
            configureWidget(data);
        }
        else if (requestCode == REQUEST_CREATE_APPWIDGET) {
            createWidget(data);
        }
    }
    else if (resultCode == RESULT_CANCELED && data != null) {
        int appWidgetId = data.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, -1);
        if (appWidgetId != -1) {
            mAppWidgetHost.deleteAppWidgetId(appWidgetId);
        }
    }
}

private void configureWidget(Intent data) {
    Bundle extras = data.getExtras();
    int appWidgetId = extras.getInt(AppWidgetManager.EXTRA_APPWIDGET_ID, -1);
    AppWidgetProviderInfo appWidgetInfo = mAppWidgetManager.getAppWidgetInfo(appWidgetId);
    if (appWidgetInfo.configure != null) {
        Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_CONFIGURE);
        intent.setComponent(appWidgetInfo.configure);
        intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
        startActivityForResult(intent, REQUEST_CREATE_APPWIDGET);
    } else {
        createWidget(data);
    }
}

Creating and Adding it to Your Views

Now is time to create the widget itself. You will use the Widget ID and the AppWidgetProviderInfo to ask to the AppWidgetHost “could you please create a view of this widget for me?“. It will return an AppWidgetHostView which is a derived class from View. This one you can handle as any other view from the Framework. But don’t forget to set the Widget ID and Widget Info on the view (I don’t know why the AppWidgetHost didn’t when creating the view).

public void createWidget(Intent data) {
    Bundle extras = data.getExtras();
    int appWidgetId = extras.getInt(AppWidgetManager.EXTRA_APPWIDGET_ID, -1);
    AppWidgetProviderInfo appWidgetInfo = mAppWidgetManager.getAppWidgetInfo(appWidgetId);
    AppWidgetHostView hostView = mAppWidgetHost.createView(this, appWidgetId, appWidgetInfo);
    hostView.setAppWidget(appWidgetId, appWidgetInfo);
    layout.addView(hostView);
}

Updating

The widget is now working, but is not being updated by your app. If the widget is a clock, it will be stuck at the time you added it. To register the widget to receive the events it needs, call startListening() on the AppWidgetHost. To avoid wasting battery with unnecessary updates while your app is not visible, call it during the onStart() method of your activity, and call stopListening() during the onStop() method.

@Override
protected void onStart() {
    super.onStart();
    mAppWidgetHost.startListening();
}
@Override
protected void onStop() {
    super.onStop();
    mAppWidgetHost.stopListening();
}

Releasing the Widget

The widget should be working now. But if you want to remove the widget, you need to ask to the AppWidgetHost to release it. If you do not release it, you’ll get a memory leak (your app will consume unnecessary memory). Finally, remove it from your LayoutView.

public void removeWidget(AppWidgetHostView hostView) {
    mAppWidgetHost.deleteAppWidgetId(hostView.getAppWidgetId());
    layout.removeView(hostView);
}

Note that the widget ID is also deleted during the onActivityResult() method if the user gave up selecting the widget.

I hope this can help you develop widget based apps. You can download the full source code for this post here or on GitHub. There is also an APK to install on your phone (just make sure you can install it).

Tags:

Comments

  1. Thomas Barrasso (February 18th, 2012)

    Excellent article, there are plenty of articles written about how to make Android Widgets but not nearly enough about how to host them in your application.

  2. Anonymous (March 15th, 2012)

    thank you thank you thank you. This code and information has helped me so much in turning an idea into a project. I couldn’t find this info anywhere else.

  3. Anonymous (April 3rd, 2012)

    Hi! can you please tell me how to add a certain widget (like google search) without using the widget picker activity? Thank you!

  4. Anonymous (April 3rd, 2012)

    If I add it by just specifying an ID I always get errors.

    I also tried
    ComponentName cn = new ComponentName(getBaseContext(), “com.android.quicksearchbox.SearchWidgetProvider”);
    int[] ids = AppWidgetManager.getInstance(getApplicationContext()).getAppWidgetIds (cn);

  5. Kamran Ahmed Ansari (July 5th, 2012)

    That was indeed really very helpful!

    Keep blogging!
    :D

  6. Andrew Jackson (January 18th, 2013)

    Thank you very much!

    Can an AppWidget added in HomeScreen be removed by not user touch but AppWidgetSelf or other code?

    And, can a Service Component add AppWidget in HomeScreen under a certain conditions.

    For example,
    HomeScreenLayout.addView(hostView);
    HomeScreenLayout.removeView(hostView);

    If possible, could you teach me the code simply?

  7. binu (March 26th, 2013)

    Do you save the id of the widget somewhere so you know how to add it back after a power cycle ?

  8. Leonardo Fischer (March 26th, 2013)

    Thank you for the comment! Sorry for taking so long to reply you, for some reason your comment was tagged as ‘spam’. I will check the spam folder more often to avoid this again.

    I didn’t though about adding programatically an AppWidget to the HomeScreen, but I don’t see why it couldn’t be done. The only code that this example call is the one handling menus and touches, and I don’t believe that this part of the Android API has any checking that the widget is being added during a touch or menu event.

  9. Leonardo Fischer (March 26th, 2013)

    Thank you for the comment!

    No, I don’t save the id of the widget in this example, but I believe that you should do that if you want to keep the Widgets after you restart your phone.

    Probably the onCreate method of your activity is the best place to load the list of saved ids. Then, use a variant of the createWidget(Intent data) method that receives an int id as parameter, instead of the Intent data.

  10. Ale110 (September 27th, 2013)

    Can I somehow access data inside the widget?

  11. Ale110 (September 27th, 2013)

    Thanks for a great tutorial! One more question: can I somehow access data inside the widget?

  12. Leonardo Fischer (September 28th, 2013)

    Thank you for the comment. I’m not sure if this is possible or not. My first guess is that you can’t, for security reasons. But if you have access to the code of the widget host and of the widget itself, you may try to communicate between the two apps using broadcasts (maybe this will help http://www.techotopia.com/index.php/Android_Broadcast_Intents_and_Broadcast_Receivers).

  13. another_coder (February 20th, 2014)

    Could you please provide the entire source for this tutorial? You have code snippets but no indication as to where several of them should be included, which is confusing.

    Thank you.

  14. Leonardo Fischer (February 20th, 2014)

  15. Neha (May 14th, 2014)

    Thanks for such a wonderful tutorial. I wanted to ask if there is any way such that i can get only music widgets from the list of all the widgets ?? i dnt want to see any other widgets just music widgets should be there in the list.

  16. Leonardo Fischer (May 14th, 2014)

    Thanks for the comment! I am not sure about this, but I believe that its not possible to define a “category” for a widget, thus, it should be not possible to filter widgets by category (such as “only the music widgets”).

  17. Tzeik (July 2nd, 2014)

    Great work there!! It helped me a lot !!! Is it possible to drag or delete the created widget? Is there an exact code or something.

  18. Leonardo Fischer (July 2nd, 2014)

    Thank you for your comment. I believe that dragging a widget is possible by manipulating the layout where you are adding the hostView. You can delete a widget from your app using the removeWidget method above.

Leave a Reply

Your email address will not be published.

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

css.php