Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

AppWidgetProvider with Android Architecture Component

I want to implement Android Architecture Component with AppWidgetProvider.

I'm not sure to map properly Widget LifeCycle to LifeCycle events.

I created a BaseAppWidgetProvider to be extented by my widgets:

/**
 * Base class for {@link BaseAppWidgetProvider} to manage {@link Lifecycle}
 */

public abstract class BaseAppWidgetProvider extends AppWidgetProvider implements LifecycleOwner {
    private final AppWidgetProviderLifecycleDispatcher mDispatcher = new AppWidgetProviderLifecycleDispatcher(this);

    public BaseAppWidgetProvider(){
        mDispatcher.onConstructor();
    }

    @CallSuper
    @Override
    public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
        mDispatcher.onUpdate();
        super.onUpdate(context, appWidgetManager, appWidgetIds);
    }

    @CallSuper
    @Override
    public void onDeleted(Context context, int[] appWidgetIds) {
        mDispatcher.onDeleted();
        super.onDeleted(context, appWidgetIds);
    }

    @CallSuper
    @Override
    public void onEnabled(Context context) {
        mDispatcher.onEnabled();
        super.onEnabled(context);
    }

    @CallSuper
    @Override
    public void onDisabled(Context context) {
        mDispatcher.onDisabled();
        super.onDisabled(context);
    }

    @CallSuper
    @Override
    public void onRestored(Context context, int[] oldWidgetIds, int[] newWidgetIds) {
        mDispatcher.onRestored();
        super.onRestored(context, oldWidgetIds, newWidgetIds);
    }

    @CallSuper
    @Override
    public void onAppWidgetOptionsChanged(Context context, AppWidgetManager appWidgetManager, int appWidgetId, Bundle newOptions) {
        mDispatcher.onAppWidgetOptionsChanged();
        super.onAppWidgetOptionsChanged(context, appWidgetManager, appWidgetId, newOptions);
    }

    @NonNull
    @Override
    public Lifecycle getLifecycle() {
        return mDispatcher.getLifecycle();
    }
}

And the dispatcher

public class AppWidgetProviderLifecycleDispatcher {
    private final LifecycleRegistry mRegistry;
    private final Handler mHandler;
    private DispatchRunnable mLastDispatchRunnable;


    /**
     * @param provider {@link LifecycleOwner} for a service, usually it is a service itself
     */
    public AppWidgetProviderLifecycleDispatcher(@NonNull LifecycleOwner provider) {
        mRegistry = new LifecycleRegistry(provider);
        mHandler = new Handler();
    }
    private void postDispatchRunnable(Lifecycle.Event event) {
        Timber.d("postDispatchRunnable event="+event);
        if (mLastDispatchRunnable != null) {
            mLastDispatchRunnable.run();
        }
        mLastDispatchRunnable = new DispatchRunnable(mRegistry, event);
        mHandler.postAtFrontOfQueue(mLastDispatchRunnable);
    }


    /**
     * Must be a first call in {@link android.appwidget.AppWidgetProvider#AppWidgetProvider()} constructor, even before super call.
     */
    public void onConstructor(){
        postDispatchRunnable(Lifecycle.Event.ON_CREATE);
        postDispatchRunnable(Lifecycle.Event.ON_START);
    }

    /**
     * Must be a first call in {@link android.appwidget.AppWidgetProvider#onDeleted(Context, int[])} method, even before super.onDeleted call.
     */
    public void onDeleted(){
        postDispatchRunnable(Lifecycle.Event.ON_PAUSE);
        postDispatchRunnable(Lifecycle.Event.ON_STOP);
        postDispatchRunnable(Lifecycle.Event.ON_DESTROY);
    }

    /**
     * Must be a first call in {@link android.appwidget.AppWidgetProvider#onDisabled(Context)} method, even before super.onDisabled call.
     */
    public void onDisabled(){
        postDispatchRunnable(Lifecycle.Event.ON_PAUSE);
        postDispatchRunnable(Lifecycle.Event.ON_STOP);
        postDispatchRunnable(Lifecycle.Event.ON_DESTROY);
    }

    /**
     * Must be a first call in {@link android.appwidget.AppWidgetProvider#onEnabled(Context)} method, even before super.onEnabled call.
     */
    public void onEnabled(){
        postDispatchRunnable(Lifecycle.Event.ON_CREATE);
        postDispatchRunnable(Lifecycle.Event.ON_START);
    }


    /**
     * Must be a first call in {@link android.appwidget.AppWidgetProvider#onRestored(Context, int[], int[])} method, even before super.onRestored call.
     */
    public void onRestored(){
        postDispatchRunnable(Lifecycle.Event.ON_CREATE);
        postDispatchRunnable(Lifecycle.Event.ON_START);
    }

    /**
     * Must be a first call in {@link android.appwidget.AppWidgetProvider#onUpdate(Context, AppWidgetManager, int[])} method, even before super.onUpdate call.
     */
    public void onUpdate(){
        postDispatchRunnable(Lifecycle.Event.ON_RESUME);
    }

    /**
     * @return {@link Lifecycle} for the given {@link LifecycleOwner}
     */
    public Lifecycle getLifecycle() {
        return mRegistry;
    }

    public void onAppWidgetOptionsChanged() {
        postDispatchRunnable(Lifecycle.Event.ON_RESUME);
    }

    static class DispatchRunnable implements Runnable {
        private final LifecycleRegistry mRegistry;
        final Lifecycle.Event mEvent;
        private boolean mWasExecuted = false;
        DispatchRunnable(@NonNull LifecycleRegistry registry, Lifecycle.Event event) {
            mRegistry = registry;
            mEvent = event;
        }
        @Override
        public void run() {
            if (!mWasExecuted) {
                mRegistry.handleLifecycleEvent(mEvent);
                mWasExecuted = true;
            }
        }
    }

}
like image 701
LaurentY Avatar asked Nov 14 '17 17:11

LaurentY


Video Answer


1 Answers

An AppWidgetProvider is a BroadcastReceiver. It does not have a lifecycle. An instance of your AppWidgetProvider lives for exactly one callback method (e.g., onUpdate()). Hence, there is no mapping to Lifecycle events, just as there is no mapping of Lifecycle events to an ordinary BrodadcastReceiver.

like image 75
CommonsWare Avatar answered Sep 28 '22 01:09

CommonsWare