Incorporate Broadcast Event Senders/Receivers into the application. Use BootReciever to recieve boot event to start application service on launch. Use NetworkReveicer to stop/start service when network is starting/stopping. Use Broadcast Events for status updates from background service to TimelineActivity
Introduce this class to receive bootloader events:
class BootReceiver extends BroadcastReceiver
{
  override onReceive(Context context, Intent intent) 
  {
    context.startService(new Intent(context, typeof(UpdaterService)))
  }
}
This will start the updater service when the device boots. It requires this permission in the manifest:
    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
      <receiver android:name="com.marakana.yambax.BootReceiver">
        <intent-filter>
          <action android:name="android.intent.action.BOOT_COMPLETED" />
        </intent-filter> 
      </receiver>
We can change our default service state to running:
  @Property boolean                serviceRunning = true
.. and also make some adjustments to the toggle service action:
  val toggleService = [ | intent = new Intent(this, typeof(UpdaterService))
                          if (app.isServiceRunning)
                            stopService(intent)
                           else
                            startService(intent) 
                          app.serviceRunning = !app.serviceRunning] as Command
You can inspect the list of running services on the device:

We can employ Android Broadcast events for the status updates, removing the custom event mechanism we have hand coded.
We first define some resources to describe the events:
  <string name="send_timeline_notifications_permission_label">Sends Timeline Notifications</string>
  <string name="send_timeline_notifications_permission_description">Allow this application to send timeline notifications to other applications</string>
  <string name="receive_timeline_notifications_permission_label">Receive Timeline Notifications</string>
  <string name="receive_timeline_notifications_permission_description">Allow this application to receive timeline notifications from other applications</string>
.. and then declare them in the manifest:
    <uses-permission android:name="com.marakana.yamba.SEND_TIMELINE_NOTIFICATIONS" />
    <uses-permission android:name="com.marakana.yamba.RECEIVE_TIMELINE_NOTIFICATIONS" />
    <permission android:name="com.marakana.yamba.SEND_TIMELINE_NOTIFICATIONS"
      android:label="@string/send_timeline_notifications_permission_label"
      android:description="@string/send_timeline_notifications_permission_description"
      android:permissionGroup="android.permission-group.PERSONAL_INFO"
      android:protectionLevel="normal" />
    <permission android:name="com.marakana.yamba.RECEIVE_TIMELINE_NOTIFICATIONS"
      android:label="@string/receive_timeline_notifications_permission_label"
      android:description="@string/receive_timeline_notifications_permission_description"
      android:permissionGroup="android.permission-group.PERSONAL_INFO"
      android:protectionLevel="normal" />
The strings need to be replicated in the UpdaterService class:
  public static final String NEW_STATUS_INTENT              = "com.marakana.yamba.NEW_STATUS"
  public static final String SEND_TIMELINE_NOTIFICATIONS    = "com.marakana.yamba.SEND_TIMELINE_NOTIFICATIONS";
  public static final String RECEIVE_TIMELINE_NOTIFICATIONS = "com.marakana.yamba.RECEIVE_TIMELINE_NOTIFICATIONS"
.. and then dispatched :
  override def void doBackgroundTask()
  {
    try
    {
      val List<Twitter.Status> timeline  = twitter.getFriendsTimeline
      newTweets = if (app.timeline.size == 0) timeline else timeline.filter [it.id > app.timeline.get(0).id]
      Log.e("YAMBA", "number of new tweets= " + newTweets.size)      
      app.updateTimeline(newTweets)
      sendBroadcast(new Intent(NEW_STATUS_INTENT), RECEIVE_TIMELINE_NOTIFICATIONS);      
    }
    catch (TwitterException e)
    {
      Log.e("YAMBA", "Failed to connect to twitter service", e); 
    }
  }
The knock on changes involve changes to the main application object:
  def updateTimeline(Iterable<Twitter.Status> newTweets)
  {
    newTweets.forEach[timeline.add(0, it)]
  }
  def clearTimeline()
  {
    timeline.clear
    // todo - clear timeline view
  }
}
.. and the TimelineActivity, which gets an new receiver object:
class TimelineReceiver extends BroadcastReceiver
{
  var TimelineActivity timelineActivity
  new (TimelineActivity activity)
  {
      timelineActivity = activity;
  }
  override onReceive(Context context, Intent intent) 
  {
      timelineActivity.timelineAdapter.notifyDataSetChanged
  }
} 
class TimelineActivity extends BaseActivity
{  
  @Property TimelineAdapter timelineAdapter
  var TimelineReceiver receiver
  var IntentFilter     filter
  override onCreate(Bundle savedInstanceState)
  {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.timeline)
    timelineAdapter    = new TimelineAdapter(this, R.layout.row, app.timeline)
    receiver = new TimelineReceiver (this)
    filter   = new IntentFilter( UpdaterService.NEW_STATUS_INTENT )
  }
  override onStart()
  { 
    super.onStart    
    val listTimeline = findViewById(R.id.listTimeline) as ListView
    listTimeline.setAdapter(timelineAdapter);
  }
  override onResume()
  {
      super.onResume
    super.registerReceiver(receiver, filter, UpdaterService.SEND_TIMELINE_NOTIFICATIONS, null);
  }
  override onPause() 
  {
    super.onPause();
    unregisterReceiver(receiver) 
  }
}
We can also potentially improve the energy deficiency of our application by disabling the background task when the network is unavailable:
class NetworkReceiver extends BroadcastReceiver 
{ 
  override onReceive(Context context, Intent intent) 
  {
    val isNetworkDown = intent.getBooleanExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, false); 
    if (isNetworkDown) 
    {
      if (YambaApplication.serviceRunning)
      {
        Log.d("YAMBA", "onReceive: NOT connected, stopping UpdaterService");
        context.stopService(new Intent(context, typeof(UpdaterService)))
      }
    }
    else 
    {
      if (!YambaApplication.serviceRunning)
      {
        Log.d("YAMBA", "onReceive: connected, starting UpdaterService");
        context.startService(new Intent(context, typeof(UpdaterService)))
      }
    }
  }
}
This will involves setting our initial service back to false:
  public static boolean            serviceRunning = false
.. and other adjustments:
  val toggleService = [ | intent = new Intent(this, typeof(UpdaterService))
                          if (YambaApplication.serviceRunning)
                            stopService(intent)
                           else
                            startService(intent) 
                          YambaApplication.serviceRunning = !YambaApplication.serviceRunning] as Command
  override onMenuOpened(int featureId, Menu menu)
  { 
    val toggleItem = menu.findItem(R.id.itemToggleService)
    toggleItem.title = if (YambaApplication.serviceRunning) R.string.titleServiceStop         else R.string.titleServiceStart
    toggleItem.icon  = if (YambaApplication.serviceRunning) android.R.drawable.ic_media_pause else android.R.drawable.ic_media_play
    true
  }
  override onStartCommand(Intent intent, int flags, int startId)
  {
    super.onStartCommand(intent, flags, startId)
    startBackgroundTask
    YambaApplication.serviceRunning = true
    START_STICKY;
  }
  override onDestroy()
  {
    super.onDestroy
    stopBackgroundTask
    YambaApplication.serviceRunning = false
  }
  <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
      <receiver android:name="com.marakana.yambax.NetworkReceiver">
        <intent-filter>
          <action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
        </intent-filter>
      </receiver>
Finally, our timeline should be cleared if a purge action received:
  def clearTimeline()
  {
    timeline.clear
    sendBroadcast(new Intent(UpdaterService.NEW_STATUS_INTENT), UpdaterService.RECEIVE_TIMELINE_NOTIFICATIONS);   
  }
These labs are based on the application developed using this text:
The Yamba application here uses android API largely compatible with Android 3.0 and earlier.
However, it has been substantially revised to use a full suite of modern facilities introduced in subsequent releases:
A full set up repos for all the code in the revised application is here:
(Toc is reproduce at the end of this page)
Specifically, the revised application includes:
Live Wallpapers
a number of minor improvements.
A version of YambaX (written in xtend) - fully updated to include the above features, would be an interesting and useful assignment topic