Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

AppWidgetHost not updating widgets

Can I use AppWidgetHost inside a Fragment? I can't get most widgets added to my AppWidgetHost to update. Here is my scenario..

LauncherActivity.java

  • Very simple, just calling setContentView with a layout.

main.xml

  • Contains a couple fragments, including one that has the AppWidgetHost in it.

CodeRedWidgetHostFragment.java

  • onCreateView
    create instances of AppWidgetHost & AppWidgetManager
    create and setup my host view with a widget ID that I've stored in preferences

  • onStart()
    appWidgetHost.startListening()

  • onStop()
    appWidgetHost.stopListening()

When I get my instances of AppWidgetHost and AppWidgetManager I'm using getActivity() to get the Fragments hosting activity. I'm wondering if this is why my widgets aren't updating?

Some widgets actually do update, like the Analog Clock for example, however, the Youtube widget doesn't auto cycle through video thumbnails.

I should mention that I select the widget I want in my AppWidgetHost in another activity that stores the selected widget's id in SharedPreferences.

Here is the code for my Fragment class.

package com.brockoli.android.codered.widgethost;

import android.app.Fragment;
import android.appwidget.AppWidgetHost;
import android.appwidget.AppWidgetHostView;
import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProviderInfo;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

import com.brockoli.android.codered.R;

public class CodeRedWidgetHostFragment extends Fragment {
private static final String TAG = CodeRedWidgetHostFragment.class.getSimpleName();

public static final String CODERED_WIDGET_ID = "CODERED_WIDGET_ID";

private SharedPreferences mSharedPrefsWidgets;

AppWidgetManager mAppWidgetManager;
AppWidgetHost mAppWidgetHost;

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
        Bundle savedInstanceState) {
    View parentView = inflater.inflate(R.layout.widget_host, null);

    mSharedPrefsWidgets = getActivity().getSharedPreferences("codered_widgets", 0);

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

    createWidget(parentView);

    return parentView;
}

@Override
public void onStart() {
    super.onStart();
    mAppWidgetHost.startListening();
}

@Override
public void onStop() {
    super.onStop();
    mAppWidgetHost.stopListening();
}


@Override
public void onResume() {
    super.onResume();
    createWidget(getView());
}

/**
 * Creates the widget and adds to our view layout.
 */
public void createWidget(View v) {
    if (v != null) {
        // Remove any existing widgets from the widget host
        ((ViewGroup) v).removeAllViews();
        int appWidgetId = mSharedPrefsWidgets.getInt(CODERED_WIDGET_ID, -1);
        if (appWidgetId > -1) {
            AppWidgetProviderInfo appWidgetInfo = mAppWidgetManager.getAppWidgetInfo(appWidgetId);
            AppWidgetHostView hostView = mAppWidgetHost.createView(getActivity(), appWidgetId, appWidgetInfo);
            hostView.setAppWidget(appWidgetId, appWidgetInfo);
            ((ViewGroup) v).addView(hostView);
            Log.i(TAG, "The widget size is: " + appWidgetInfo.minWidth + "*" + appWidgetInfo.minHeight);
        }   
    }
}
}
like image 985
brockoli Avatar asked Apr 03 '14 03:04

brockoli


1 Answers

Building on Clemens answer, the AppWidgetHost should be alive during the entire lifecycle of your application. This means that regardless of Activity you should have an instance of AppWidgetHost and AppWidgetManager somewhere easily accessible to your app.

public class YourApp extends Application {

    private static final int HARDCODED_ID = 0; 

    private static AppWidgetHost appWidgetHost;
    private static AppWidgetManager appWidgetManager;

    @Override
    public void onCreate() {
        super.onCreate();

        appWidgetManager = AppWidgetManager.getInstance(getApplicationContext());
        appWidgetHost = new AppWidgetHost(getApplicationContext(), HARDCODED_ID);
        appWidgetHost.startListening();
    }

    @Override
    public void onTerminate() {
        super.onTerminate();

        appWidgetHost.stopListening();
        appWidgetHost = null;
    }

    public static AppWidgetHost getAppWidgetHost() { return appWidgetHost; }

    public static AppWidgetManager getAppWidgetManager() { return appWidgetManager; }

}

My current implementation has been updating correctly. Tested with many apps that need 'real-time' updates like my music player widget.

Please keep in mind, that application context was used to ensure that the context for AppWidgetHost and AppWidgetManager would always be available.

Also, newer widgets that use the AppCompat libraries within their widgets currently have a bug in com.android.support:appcompat-v7:23.1.1 dependencies. To avoid this use application context when calling the following.

AppWidgetHostView hostView = YourApp.getAppWidgetHost()
            .createView(context.getApplicationContexxt(), appWidgetId, info);
like image 87
Chris Sullivan Avatar answered Sep 20 '22 21:09

Chris Sullivan