private void update(FeedType feedType, UpdateType updateType) {
    ArticleDao articleDao = DbConnection.getSession().getArticleDao();
    SQLiteDatabase db = articleDao.getDatabase();

    db.beginTransaction();
    try {

      Integer latestID = null;
      if (feedType == FeedType.Main || feedType == FeedType.Archive) {
        WhereCondition cond =
            feedType == FeedType.Main
                ? ArticleDao.Properties.Archive.notEq(true)
                : ArticleDao.Properties.Archive.eq(true);
        List<Article> l =
            articleDao
                .queryBuilder()
                .where(cond)
                .orderDesc(ArticleDao.Properties.ArticleId)
                .limit(1)
                .list();

        if (!l.isEmpty()) {
          latestID = l.get(0).getArticleId();
        }
      }

      if (!updateByFeed(articleDao, feedType, updateType, latestID)) {
        return;
      }

      db.setTransactionSuccessful();
    } finally {
      db.endTransaction();
    }
  }
  private void updateAllFeeds() {
    Log.i(TAG, "updateAllFeeds() started");

    ArticleDao articleDao = DbConnection.getSession().getArticleDao();
    SQLiteDatabase db = articleDao.getDatabase();

    Log.d(TAG, "updateAllFeeds() beginning transaction");
    db.beginTransaction();
    try {
      Log.d(TAG, "updateAllFeeds() deleting old articles");
      articleDao.deleteAll();

      Log.d(TAG, "updateAllFeeds() updating Main feed");
      if (!updateByFeed(articleDao, FeedType.Main, UpdateType.Full, 0)) {
        Log.w(TAG, "updateAllFeeds() Main feed update failed; exiting");
        return;
      }

      Log.d(TAG, "updateAllFeeds() updating Archive feed");
      if (!updateByFeed(articleDao, FeedType.Archive, UpdateType.Full, 0)) {
        Log.w(TAG, "updateAllFeeds() Archive feed update failed; exiting");
        return;
      }

      Log.d(TAG, "updateAllFeeds() updating Favorite feed");
      if (!updateByFeed(articleDao, FeedType.Favorite, UpdateType.Fast, 0)) {
        Log.w(TAG, "updateAllFeeds() Favorite feed update failed; exiting");
        return;
      }

      Log.d(TAG, "updateAllFeeds() setting transaction successful");
      db.setTransactionSuccessful();
    } finally {
      Log.d(TAG, "updateAllFeeds() ending transaction");
      db.endTransaction();
    }

    Log.d(TAG, "updateAllFeeds() finished");
  }
  private void processFeed(
      ArticleDao articleDao,
      InputStream is,
      FeedType feedType,
      UpdateType updateType,
      Integer latestID)
      throws XmlPullParserException, IOException {
    // TODO: use parser.require() all over the place?

    XmlPullParser parser = Xml.newPullParser();
    parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, false);
    parser.setInput(is, null);

    parser.nextTag();
    parser.require(XmlPullParser.START_TAG, null, "rss");

    goToElement(parser, "channel", true);
    parser.next();

    DateFormat dateFormat = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss Z", Locale.US);

    while (parser.next() != XmlPullParser.END_DOCUMENT) {
      if (parser.getEventType() != XmlPullParser.START_TAG) {
        continue;
      }

      if ("item".equals(parser.getName())) {
        if (feedType == FeedType.Main
            || feedType == FeedType.Archive
            || (feedType == FeedType.Favorite && updateType == UpdateType.Full)) {
          // Main: Full, Fast
          // Archive: Full, Fast
          // Favorite: Full

          Item item = parseItem(parser);

          Integer id = getIDFromURL(item.sourceUrl);

          if (updateType == UpdateType.Fast && latestID != null && id != null && latestID >= id)
            break;

          Article article =
              articleDao
                  .queryBuilder()
                  .where(ArticleDao.Properties.ArticleId.eq(id))
                  .build()
                  .unique();

          boolean existing = true;
          if (article == null) {
            article = new Article(null);
            existing = false;
          }

          article.setTitle(item.title);
          article.setContent(item.description);
          article.setUrl(item.link);
          article.setArticleId(id);
          try {
            article.setUpdateDate(dateFormat.parse(item.pubDate));
          } catch (ParseException e) {
            e.printStackTrace();
          }
          if (existing) {
            if (feedType == FeedType.Archive) {
              article.setArchive(true);
            } else if (feedType == FeedType.Favorite) {
              article.setFavorite(true);
            }
          } else {
            article.setArchive(feedType == FeedType.Archive);
            article.setFavorite(feedType == FeedType.Favorite);
          }

          articleDao.insertOrReplace(article);
        } else if (feedType == FeedType.Favorite) {
          // Favorite: Fast (ONLY applicable if Main and Archive feeds are up to date)
          // probably a bit faster then "Favorite: Full"

          Integer id = parseItemID(parser);
          if (id == null) continue;

          Article article =
              articleDao
                  .queryBuilder()
                  .where(ArticleDao.Properties.ArticleId.eq(id))
                  .build()
                  .unique();

          if (article.getFavorite() != null && article.getFavorite()) continue;

          article.setFavorite(true);

          articleDao.update(article);
        }
      } else {
        skipElement(parser);
      }
    }
  }