title: Android: Start activity from app widget with ListView and Service
body: <p>I am using a ListView in a App Widget to show some items from a RSS feed. I want to go to a activity of my app if I click on a item in the ListView. </p>
  
  <p>I am at the point that I can show a Toast with the clicked position. I want to go to. But I do not know how to start the activity.</p>
  
  <p>I need to put my RSSFeed and the position inside the intent which starts the activity.</p>
  
  <p>I have a WidgetProvider.java which calls a RemoteFetchService.java in the onUpdate() method. In the OnStartCommand() of this Service I start a AsyncTask and parse my RSS feed. In the OnPostExecute() I broadcast to the WidgetProvider.java that I successfully fetched the data. Then in the WidgetProvider.java I set a remote adapter via my ListProvider.java class that implents RemoteViewsFactory. So where and how can I start my activity?</p>
  
  <p><strong>WidgetProvider.java</strong></p>
  
  <pre><code>public class WidgetProvider extends AppWidgetProvider {
  
      // String to be sent on Broadcast as soon as Data is Fetched
      // should be included on WidgetProvider manifest intent action
      // to be recognized by this WidgetProvider to receive broadcast
      public static final String DATA_FETCHED = "mypackage.RSS.DATA_FETCHED";
      public static final String EXTRA_LIST_VIEW_ROW_NUMBER = "mypackage.EXTRA_LIST_VIEW_ROW_NUMBER";
  
      /*
       * this method is called every 30 mins as specified on widgetinfo.xml this
       * method is also called on every phone reboot from this method nothing is
       * updated right now but instead RetmoteFetchService class is called this
       * service will fetch data,and send broadcast to WidgetProvider this
       * broadcast will be received by WidgetProvider onReceive which in turn
       * updates the widget
       */
      @Override
      public void onUpdate(Context ctxt, AppWidgetManager appWidgetManager,
              int[] appWidgetIds) {
  
          Log.d("Widget", "Hello WidgetProvider onUpdate");
  
          /*
           * int[] appWidgetIds holds ids of multiple instance of your widget
           * meaning you are placing more than one widgets on your homescreen
           */
          for (int i = 0; i &lt; appWidgetIds.length; ++i) {
  
              Intent serviceIntent = new Intent(ctxt, RemoteFetchService.class);
              serviceIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID,
                      appWidgetIds[i]);
              ctxt.startService(serviceIntent);
          }
          super.onUpdate(ctxt, appWidgetManager, appWidgetIds);
      }
  
      /*
       * It receives the broadcast as per the action set on intent filters on
       * Manifest.xml once data is fetched from RemoteFetchService,it sends
       * broadcast and WidgetProvider notifies to change the data the data change
       * right now happens on ListProvider as it takes RemoteFetchService
       * listItemList as data
       */
      @SuppressWarnings("deprecation")
      @Override
      public void onReceive(Context context, Intent intent) {
          super.onReceive(context, intent);
  
          Log.d("Widget", "Hello WidgetProvider onReceive");
  
          //if RSS Feed was parsed in RemoteFetchService.java
          if (intent.getAction().equals(DATA_FETCHED)) {
  
              Log.d("Widget", "Data fetched in Widget Provider");
  
              int appWidgetId = intent.getIntExtra(
                      AppWidgetManager.EXTRA_APPWIDGET_ID,
                      AppWidgetManager.INVALID_APPWIDGET_ID);
              AppWidgetManager appWidgetManager = AppWidgetManager
                      .getInstance(context);
  
              // which layout to show on widget
              RemoteViews remoteViews = new RemoteViews(context.getPackageName(),
                      R.layout.widget_layout);
  
              // RemoteViews Service needed to provide adapter for ListView
              Intent svcIntent = new Intent(context, WidgetService.class);
              // passing app widget id to that RemoteViews Service
              svcIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, 
                      appWidgetId);
              // setting a unique Uri to the intent
              svcIntent.setData(Uri.parse(svcIntent
                      .toUri(Intent.URI_INTENT_SCHEME)));
              // setting adapter to listview of the widget
              remoteViews.setRemoteAdapter(appWidgetId, R.id.listViewWidget,
                      svcIntent);
              // setting an empty view in case of no data
              remoteViews.setEmptyView(R.id.listViewWidget, R.id.empty_view);
  
              // onclick item listview
  
              // This section makes it possible for items to have individualized
              // behavior.
              // It does this by setting up a pending intent template. Individuals
              // items of a collection
              // cannot set up their own pending intents. Instead, the collection
              // as a whole sets
              // up a pending intent template, and the individual items set a
              // fillInIntent
              // to create unique behavior on an item-by-item basis.
              Intent toastIntent = new Intent(context, WidgetProvider.class);
              // Set the action for the intent.
              // When the user touches a particular view, it will have the effect
              // of
              // broadcasting TOAST_ACTION.
              toastIntent.setAction(WidgetProvider.EXTRA_LIST_VIEW_ROW_NUMBER);
              toastIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID,
                      appWidgetId);
              intent.setData(Uri.parse(intent.toUri(Intent.URI_INTENT_SCHEME)));
              PendingIntent toastPendingIntent = PendingIntent.getBroadcast(
                      context, 0, toastIntent, PendingIntent.FLAG_UPDATE_CURRENT);
              remoteViews.setPendingIntentTemplate(R.id.listViewWidget,
                      toastPendingIntent);
  
              appWidgetManager.updateAppWidget(appWidgetId, remoteViews);
          }
          //if item on list was clicked
          if (intent.getAction().equals(EXTRA_LIST_VIEW_ROW_NUMBER)) {
              int appWidgetId = intent.getIntExtra(
                      AppWidgetManager.EXTRA_APPWIDGET_ID,
                      AppWidgetManager.INVALID_APPWIDGET_ID);
  
              AppWidgetManager appWidgetManager = AppWidgetManager
                      .getInstance(context);
  
              //get position on listview which was clicked
              int viewIndex = intent.getIntExtra(EXTRA_LIST_VIEW_ROW_NUMBER, 0);
  
              //get RSSFeed
              RSSFeed feed = ListItem.Feed;
  
              Toast.makeText(context, "Clicked on position :" + viewIndex,
                      Toast.LENGTH_SHORT).show();
          } else {
              Log.d("Widget", "No Data fetched in Widget Provider");
          }
  
      }
  }
  </code></pre>
  
  <p><strong>RemoteFetchService.java</strong></p>
  
  <pre><code>public class RemoteFetchService extends Service {
  
      private int appWidgetId = AppWidgetManager.INVALID_APPWIDGET_ID;
      RSSFeed feed;
      public Date pDate;
  
      public static ArrayList&lt;ListItem&gt; listItemList;
  
      @Override
      public IBinder onBind(Intent arg0) {
          return null;
      }
  
      /*
       * Retrieve appwidget id from intent it is needed to update widget later
       * start Async Task
       */
      @Override
      public int onStartCommand(Intent intent, int flags, int startId) {
  
          Log.d("Widget", "Hello RemoteFetchService onStartCommand");
  
          if (intent.hasExtra(AppWidgetManager.EXTRA_APPWIDGET_ID))
              appWidgetId = intent.getIntExtra(
                      AppWidgetManager.EXTRA_APPWIDGET_ID,
                      AppWidgetManager.INVALID_APPWIDGET_ID);
  
          //fetchDataFromWeb();
          new AsyncLoadXMLFeed().execute();
  
          return super.onStartCommand(intent, flags, startId);
      }
  
      /**
       * AsyncTask which parses the xml and post it
       **/
      public class AsyncLoadXMLFeed extends AsyncTask&lt;Void, Void, RSSFeed&gt; {
  
          protected RSSFeed doInBackground(Void... params) {
              try {
  
                  Log.d("Widget", "Starte Parsing von URL in Widget");
                  // Obtain feed
                  DOMParser myParser = new DOMParser();
                  feed = myParser.parseXml("http://www.test.de/feed");
                  Log.d("Widget","ItemCount Parser in Widget: "+feed.getItemCount());
  
                  return feed;
  
              } catch (Exception e) {
                  Log.d("Widget","Exception beim Parsen: "+e.toString());
                  return null;
              }
          }
  
          @Override
          protected void onPostExecute(RSSFeed parsed_feed) {
              // super.onPostExecute(result);
              Log.d("Widget", "Async Parse fertig");
              listItemList = new ArrayList&lt;ListItem&gt;();
              if(feed!=null){
                  try {
                      int length = feed.getItemCount();
                      for (int i = 0; i &lt; length; i++) {
  
                          String date = calc_date_difference(feed, i);
  
                          ListItem listItem = new ListItem();
                          listItem.Feed = feed;
                          listItem.heading = feed.getItem(i).getTitle();
                          listItem.pubDate = date;
                          listItem.linkUrl = feed.getItem(i).getLink();
                          Log.d("Widget Heading", feed.getItem(i).getTitle());
                          Log.d("Widget PubDate", date);
                          Log.d("Widget linkUrl", feed.getItem(i).getLink());
                          listItemList.add(listItem);
                      }
  
                  } catch (Exception e) {
                      Log.d("Widget","Exception onPostExecute: "+e.toString());
                  }
              }else{
                  Log.d("Widget", "Feed in onPostExecute ist null");
              }
  
              //start intent and broadcast WidgetProvider, that data is fetched
              Intent widgetUpdateIntent = new Intent();
              widgetUpdateIntent.setAction(WidgetProvider.DATA_FETCHED);
              widgetUpdateIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID,
                      appWidgetId);
              sendBroadcast(widgetUpdateIntent);
  
              //stop service
              stopSelf();
          }
      }
  
      /**
       * Method to calculate the time difference
       **/
      public String calc_date_difference (RSSFeed feed, int pos){
          // calculate the time difference to the actual system time
          String pubDate = feed.getItem(pos).getDate();
          SimpleDateFormat df = new SimpleDateFormat(
                  "EEE, dd MMM yyyy HH:mm:ss",Locale.ENGLISH);
          try {
              try {
                  pDate = df.parse(pubDate);
              } catch (java.text.ParseException e) {
                  // TODO Auto-generated catch block
                  e.printStackTrace();
              }
              pubDate = "Vor "
                      + DateUtils.getDateDifference(pDate);
              return pubDate;
          } catch (ParseException e) {
              Log.e("DATE PARSING", "Error parsing date..");
              return null;
          }
      }
  
  }
  </code></pre>
  
  <p><strong>WidgetService.java</strong></p>
  
  <pre><code>/**
   * 
   * Just consider this class as the class which tells the ListView of appwidget
   * to take what type of data. By data meaning what ListViewsFactory. To make it
   * more simple,if you have done ListView population,this class defines the
   * Adapter for the ListView. Let us name ListViewsService as WidgetService.java
   * 
   **/
  public class WidgetService extends RemoteViewsService {
      /*
       * So pretty simple just defining the Adapter of the listview here Adapter
       * is ListViewsFactory
       */
  
      @Override
      public RemoteViewsFactory onGetViewFactory(Intent intent) {
          int appWidgetId = intent.getIntExtra(
          AppWidgetManager.EXTRA_APPWIDGET_ID,
          AppWidgetManager.INVALID_APPWIDGET_ID);
          return (new ListProvider(this.getApplicationContext(), intent));
      }
  }
  </code></pre>
  
  <p><strong>ListItem.java</strong></p>
  
  <pre><code>public class ListItem {
      public String heading,pubDate,linkUrl;
      public static RSSFeed Feed;
  
  }
  </code></pre>
  
  <p><strong>ListProvider.java</strong></p>
  
  <pre><code>/**
   * If you are familiar with Adapter of ListView,this is the same as adapter with
   * few changes
   * 
   */
  public class ListProvider implements RemoteViewsFactory {
  
      private RemoteViews views;
      private Context ctxt = null;
      private int appWidgetId;
      private ArrayList&lt;ListItem&gt; listItemList = new ArrayList&lt;ListItem&gt;();
  
      public ListProvider(Context ctxt, Intent intent) {
          this.ctxt = ctxt;
          appWidgetId = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID,
                  AppWidgetManager.INVALID_APPWIDGET_ID);
  
          if (RemoteFetchService.listItemList != null)
              listItemList = (ArrayList&lt;ListItem&gt;) RemoteFetchService.listItemList
                      .clone();
          else
              listItemList = new ArrayList&lt;ListItem&gt;();
      }
  
      @Override
      public void onCreate() {
          // no-op
          Log.d("Widget", "Hello ListProvider onCreate");
      }
  
      @Override
      public void onDestroy() {
          // no-op
      }
  
      @Override
      public int getCount() {
          return listItemList.size();
      }
  
      /*
       * Similar to getView of Adapter where instead of Viewwe return RemoteViews
       */
      @Override
      public RemoteViews getViewAt(int position) {
  
          final RemoteViews remoteView = new RemoteViews(ctxt.getPackageName(),
                  R.layout.row);
          ListItem listItem = listItemList.get(position);
          remoteView.setTextViewText(R.id.heading, listItem.heading);
          remoteView.setTextViewText(R.id.pubDate, listItem.pubDate);
  
          //onclick item listview
          Intent fillInIntent = new Intent();
          fillInIntent.putExtra(WidgetProvider.EXTRA_LIST_VIEW_ROW_NUMBER, position);
          remoteView.setOnClickFillInIntent(R.id.heading, fillInIntent);
  
          return remoteView;
      }
  
      @Override
      public RemoteViews getLoadingView() {
          return (null);
      }
  
      @Override
      public int getViewTypeCount() {
          return (1);
      }
  
      @Override
      public long getItemId(int position) {
          return (position);
      }
  
      @Override
      public boolean hasStableIds() {
          return (true);
      }
  
      @Override
      public void onDataSetChanged() {
          // no-op
      }
  }
  </code></pre>