I have a code base that has a working widget. The basic structure of this is
MyAppWidget extends AppWidgetProvider
MyWidgetService extends IntentService
MyWidgetService updates MyAppWidget and all was well until I decided to turn my app into a library to create a “free / pro” combo from the same code base. Now I have something like this
com.example.myapp.free.MyAppWidget extends com.example.myapp.library.MyAppWidget
com.example.myapp.pro.MyAppWidget extends com.example.myapp.library.MyAppWidget
com.example.myapp.library.MyAppWidget extends AppWidgetProvider
com.example.myapp.library.MyWidgetService extends IntentService
MyWidgetService runs a MyAppWidget.update() method in order to update the display.
In this case, the widgets have minor tweaks to adjust for the version of the app and everything displays fine, but MyWidgetService doesn’t update the widgets.
I’ve verified that MyWidgetService actually runs as scheduled but it doesn’t know what update method to call. As it stands MyWidgetService will call com.example.myapp.library.MyAppWidget.update() instead of the pro or free versions.
I was able to pass down a flag and tell it which widget class it is, but that means my parent class (library MyWidgetService) needs to know details about the pro / free classes to update. This breaks the proper object orientated model.
My question is, what is the proper way to communicate which widget class should be updated?
Since this is a difficult thing to explain, below are some skeleton details of my classes in case it helps explain things.
Any help is appreciated.
Library MyWidgetService
public class MyWidgetService extends IntentService {
public MyWidgetService() {
super(MyWidgetService.class.getSimpleName());
}
@Override
protected void onHandleIntent(Intent intent) {
// this calls the update method of the widget
// but it doesn't know which object to call
MyAppWidget.update();
scheduleNextUpdate();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
super.onStartCommand(intent, flags, startId);
return START_STICKY;
}
private void scheduleNextUpdate() {
// schedule next time for the service to work
}
}
Library MyAppWidget
public class MyAppWidget extends AppWidgetProvider {
@Override
public void onEnabled(Context context) {
super.onEnabled(context);
Intent intent = new Intent(context, MyWidgetService.class);
context.startService(intent);
}
public static void update() {
// update widget display
}
}
Free MyAppWidget that extends Library MyAppWidget
public class MyAppWidget extends com.example.myapp.library.MyAppWidget {
@Override
public void onEnabled(Context context) {
super.onEnabled(context);
// setup free widget
// what can I do here to pass down to the service
// to make sure it updates this widget class
}
}
Free app manifest
<!-- use the extended widget from com.example.myapp.free -->
<receiver
android:name=".MyWidgetApp"
android:label="@string/clock_widget_name">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_ENABLED" />
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
<meta-data
android:name="android.appwidget.provider"
android:resource="@xml/clock_widget" />
</receiver>
<!-- use the service from the library project -->
<service android:name="com.example.myapp.library.MyWidgetService" />
Instead of passing the flag, pass the fully-qualified class name, and use reflection to access it.
Or, make
update()be an instance method, triggered by a custom broadcast action and dispatch logic inonReceive(). Then have the service send a matching broadcast.