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!
    😀

  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. 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.

  8. 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 ?

  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.

  19. Sachindra (February 3rd, 2015)

    Everything is understandable …Can you please confirm how it shows all the widgets in List view after clicking Add ..and in which .xml file Two buttons i.e. Add and Remove exists .?

  20. wilson (April 9th, 2015)

    Hi, can you help me on saving the chosen widget?

  21. Malte (April 15th, 2015)

    I used your code to host widgets in my app. I`m facing some issue though:

    If i save the widgets IDs to a database, i can use these ids to restore the widgets after restart of my app (recreating them). But if i start my app before the device booting is done, widgets never get updated. I have to wait until booting-process is done.

    Does anyone of you have an idea how to solve this?

    See this for more detail: http://stackoverflow.com/questions/29658528/how-to-update-third-party-widgets-at-boot-completed

  22. gunman (May 21st, 2015)

    Very helpful information to me. Thank you very much!

  23. Duy Pham (July 2nd, 2015)

    Hi Fischer. It is a great tutorial. I have followed it and was successful. There is only a problem. Would you mind check the Play – My Library Widget ? After adding it, and choosing the options in the configuration dialog, the Widget still does not work (the library doesn’t show and tapping doesn’t have any effect).

    I have the same problem in my app and i’m stuck with it. The Google Default Launcher, however, displays this widget normally.

  24. Leonardo Fischer (July 5th, 2015)

    Thank you for your comment, Duy Phan. I am not working with Android development for the past year, so I do not have an Android development environment configured right now. I will be pleased to give a look at your library when I go back to Android development, but I am unable to do this for now.

  25. Durga (July 13th, 2015)

    Thank you Leonardo Fischer for a great article. I want to know how to add click handlers to these widgets like resize or delete.
    ..Regards
    Durga

  26. Girish (July 21st, 2015)

    Hi Fischer,

    Thanks for the wonderful tutorial. Gone through other comments as well. Very helpful.

    Is there a way to display only a particular widget (filter other unwanted widgets) in the list, if I know the packagename/classname of the widget?

    Here, I donot want to filter widgets based on category (which is not possible – with respect to above mentioned comments), but have the exact information such as classname of the widget, so can I display only this widget in list?

    Thanks.

  27. Saving App widget ID's on restart device or run the app - BlogoSfera (August 10th, 2015)

    […] have got the below code from http://leonardofischer.com/hosting-android-widgets-my-appwidgethost-tutorial/ , I learned how to get all widgets and add them to my scrollview […]

  28. Johnny B (September 2nd, 2015)

    First off: thanks, this helped me a lot!
    But one thing doesn’t want to work, maybe you have a clue why even though you’re not in an android environment currently:

    My app crashes every time I call mAppWidgetHost.startListening(); and I can’t really see why. Its a TransactionTooLargeException and I didn’t find much information about it. Without it, everything except updating works like a charm. Do you have any idea?

  29. Alpaca (October 28th, 2015)

    For who have problems with the widget that don’t update itself after the boot I suggest to move startListening and stopListening methods in onCreate and onDestroy as reported here http://selvaline.blogspot.it/2015/10/hosting-widgets-and-regurally-update.html

  30. Sandeep Bhandari (April 6th, 2016)

    Hey Leonardo Fischer, Excellent article. I just have one problem, I did not wanted to use the intent to pick the widget so I managed to list all the widgets pre installed and show it to user using grid view by my self using,
    List infoList = appWidgetManager.getInstalledProviders();
    And when user taps on any cell I add it to main screen using

    AppWidgetHostView hostView = appWidgetHost.createView(this.getActivity(), appWidgetId, widgetProviderInfo);
    hostView.setAppWidget(appWidgetId, widgetProviderInfo);
    widgetHolder.addView(hostView);
    ViewGroup.LayoutParams params = hostView.getLayoutParams();
    params.width = Math.round(availableWidth);
    params.height = Math.round(availableHeight);
    hostView.setLayoutParams(params);

    Everything is fine, but when I tap on widget in home screen widget wont respond 🙁 I wasted hours on it 🙁 please help me understand where am I going wrong? Please help Thanks in advance.

  31. Leonardo Fischer (April 6th, 2016)

    Hey Sandeep Bhandari, thank you for your compliment.

    Unfortunately, I’m not into Android development anymore, so I can’t test your code to see exactly why widgets are not responding. But I would recommend you to give a second look on the mAppWidgetHost.startListening() and mAppWidgetHost.stopListening() methods above.

Leave a Reply

Your email address will not be published.

css.php