FileDocCategorySizeDatePackage
RssService.javaAPI DocAndroid 1.5 API11006Wed May 06 22:41:08 BST 2009com.example.codelab.rssexample

RssService

public class RssService extends android.app.Service implements Runnable

Fields Summary
private Logger
mLogger
public static final String
REQUERY_KEY
public static final String
RSS_URL
private android.app.NotificationManager
mNM
private android.database.Cursor
mCur
private GregorianCalendar
mLastCheckedTime
private final String
LAST_CHECKED_PREFERENCE
static final int
UPDATE_FREQUENCY_IN_MINUTES
private android.os.Handler
mHandler
private final int
NOTIFY_ID
private final android.os.IBinder
mBinder
Constructors Summary
Methods Summary
public android.os.IBinderonBind(android.content.Intent intent)

        return mBinder;
    
protected voidonCreate()

    // Identifies our service icon in the icon tray.
    
    
      
        // Display an icon to show that the service is running.
        mNM = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
        Intent clickIntent = new Intent(Intent.ACTION_MAIN);
        clickIntent.setClassName(MyRssReader5.class.getName());
        Notification note = new Notification(this, R.drawable.rss_icon, "RSS Service",
                clickIntent, null);
        mNM.notify(NOTIFY_ID, note);
        mHandler = new Handler();

        // Create the intent that will be launched if the user clicks the 
        // icon on the status bar. This will launch our RSS Reader app.
        Intent intent = new Intent(MyRssReader.class);
        
        // Get a cursor over the RSS items.
        ContentResolver rslv = getContentResolver();
        mCur = rslv.query(RssContentProvider.CONTENT_URI, null, null, null, null);
        
        // Load last updated value.
        // We store last updated value in preferences.
        SharedPreferences pref = getSharedPreferences("", 0);
        mLastCheckedTime = new GregorianCalendar();
        mLastCheckedTime.setTimeInMillis(pref.getLong(LAST_CHECKED_PREFERENCE, 0));

//BEGIN_INCLUDE(5_1)
        // Need to run ourselves on a new thread, because 
        // we will be making resource-intensive HTTP calls.
        // Our run() method will check whether we need to requery
        // our sources.
        Thread thr = new Thread(null, this, "rss_service_thread");
        thr.start();
//END_INCLUDE(5_1)        
        mLogger.info("RssService created");
    
protected voidonDestroy()

      mNM.cancel(NOTIFY_ID);
    
protected voidonStart(android.content.Intent intent, int startId)

        super.onStart(startId, arguments);
        Bundle arguments = intent.getExtras();
        if(arguments != null) {
            if(arguments.containsKey(REQUERY_KEY)) {
                queryRssItems();
            }
            if(arguments.containsKey(RSS_URL)) {
                // Typically called after adding a new RSS feed to the list.
                queryItem(arguments.getString(RSS_URL));
            }
        }    
    
private java.util.GregorianCalendarparseRssDocPubDate(java.lang.String xml)

        GregorianCalendar cal = new GregorianCalendar();
        cal.setTimeInMillis(0);
        String patt ="<[\\s]*pubDate[\\s]*>(.+?)</pubDate[\\s]*>";
        Pattern p = Pattern.compile(patt);
        Matcher m = p.matcher(xml);
        try {
            if(m.find()) {
                mLogger.info("pubDate: " + m.group());
                SimpleDateFormat pubDate = new SimpleDateFormat();
                cal.setTime(pubDate.parse(m.group(1)));
            }
       } catch(ParseException ex) {
            mLogger.warning("parseRssDocPubDate couldn't find a <pubDate> tag. Returning default value.");
       }
        return cal;
    
public voidqueryIfPeriodicRefreshRequired()

        GregorianCalendar nextCheckTime = new GregorianCalendar();
        nextCheckTime = (GregorianCalendar) mLastCheckedTime.clone();
        nextCheckTime.add(GregorianCalendar.MINUTE, UPDATE_FREQUENCY_IN_MINUTES);
        mLogger.info("last checked time:" + mLastCheckedTime.toString() + "  Next checked time: " + nextCheckTime.toString());
        
        if(mLastCheckedTime.before(nextCheckTime)) {
            queryRssItems();
        } else {
            // Post a message to query again when we get to the next check time.
            long timeTillNextUpdate = mLastCheckedTime.getTimeInMillis() - GregorianCalendar.getInstance().getTimeInMillis();
            mHandler.postDelayed(this, 1000 * 60 * UPDATE_FREQUENCY_IN_MINUTES);
        }
          
    
private booleanqueryItem(java.lang.String url)

        try {
            URL wrappedUrl = new URL(url);
            String rssFeed = readRss(wrappedUrl);
            mLogger.info("RSS Feed " + url + ":\n " + rssFeed);
            if(TextUtils.isEmpty(rssFeed)) {
                return false;
            }
              
            // Parse out the feed update date, and compare to the current version.
            // If feed update time is newer, or zero (if never updated, for new 
            // items), then update the content, date, and hasBeenRead fields.
            // lastUpdated = <rss><channel><pubDate>value</pubDate></channel></rss>.
            // If that value doesn't exist, the current date is used.
            GregorianCalendar feedPubDate = parseRssDocPubDate(rssFeed);
            GregorianCalendar lastUpdated = new GregorianCalendar();
            int lastUpdatedColumnIndex = mCur.getColumnIndex(RssContentProvider.LAST_UPDATED);
            lastUpdated.setTimeInMillis(mCur.getLong(lastUpdatedColumnIndex));
            if(lastUpdated.getTimeInMillis() == 0 ||
                lastUpdated.before(feedPubDate) && !TextUtils.isEmpty(rssFeed)) {
                // Get column indices.
                int contentColumnIndex = mCur.getColumnIndex(RssContentProvider.CONTENT);
                int updatedColumnIndex = mCur.getColumnIndex(RssContentProvider.HAS_BEEN_READ);
                 
                // Update values.
                mCur.updateString(contentColumnIndex, rssFeed);
                mCur.updateLong(lastUpdatedColumnIndex, feedPubDate.getTimeInMillis());
                mCur.updateInt(updatedColumnIndex, 0);
                mCur.commitUpdates();
            }
        } catch (MalformedURLException ex) {
              mLogger.warning("Error in queryItem: Bad url");
              return false;
        }
        return true;
    
voidqueryRssItems()

        mLogger.info("Querying Rss feeds...");
 
        // The cursor might have gone stale. Requery to be sure.
        // We need to call next() after a requery to get to the 
        // first record.
        mCur.requery();
        while (mCur.next()){
             // Get the URL for the feed from the cursor.
             int urlColumnIndex = mCur.getColumnIndex(RssContentProvider.URL);
             String url = mCur.getString(urlColumnIndex);
             queryItem(url);
        }
        // Reset the global "last checked" time
        mLastCheckedTime.setTimeInMillis(System.currentTimeMillis());
      
        // Post a message to query again in [update_frequency] minutes
        mHandler.postDelayed(this, 1000 * 60 * UPDATE_FREQUENCY_IN_MINUTES);
    
java.lang.StringreadRss(java.net.URL url)

      String html = "<html><body><h2>No data</h2></body></html>";
      try {
          mLogger.info("URL is:" + url.toString());
          BufferedReader inStream =
              new BufferedReader(new InputStreamReader(url.openStream()),
                      1024);
          String line;
          StringBuilder rssFeed = new StringBuilder();
          while ((line = inStream.readLine()) != null){
              rssFeed.append(line);
          }
          html = rssFeed.toString();
      } catch(IOException ex) {
          mLogger.warning("Couldn't open an RSS stream");
      }
      return html;
    
public voidrun()

        queryIfPeriodicRefreshRequired();