Search in sources :

Example 1 with FeedParser

use of com.example.android.basicsyncadapter.net.FeedParser in project Android-Developers-Samples by johnjohndoe.

the class SyncAdapter method updateLocalFeedData.

/**
     * Read XML from an input stream, storing it into the content provider.
     *
     * <p>This is where incoming data is persisted, committing the results of a sync. In order to
     * minimize (expensive) disk operations, we compare incoming data with what's already in our
     * database, and compute a merge. Only changes (insert/update/delete) will result in a database
     * write.
     *
     * <p>As an additional optimization, we use a batch operation to perform all database writes at
     * once.
     *
     * <p>Merge strategy:
     * 1. Get cursor to all items in feed<br/>
     * 2. For each item, check if it's in the incoming data.<br/>
     *    a. YES: Remove from "incoming" list. Check if data has mutated, if so, perform
     *            database UPDATE.<br/>
     *    b. NO: Schedule DELETE from database.<br/>
     * (At this point, incoming database only contains missing items.)<br/>
     * 3. For any items remaining in incoming list, ADD to database.
     */
public void updateLocalFeedData(final InputStream stream, final SyncResult syncResult) throws IOException, XmlPullParserException, RemoteException, OperationApplicationException, ParseException {
    final FeedParser feedParser = new FeedParser();
    final ContentResolver contentResolver = getContext().getContentResolver();
    Log.i(TAG, "Parsing stream as Atom feed");
    final List<FeedParser.Entry> entries = feedParser.parse(stream);
    Log.i(TAG, "Parsing complete. Found " + entries.size() + " entries");
    ArrayList<ContentProviderOperation> batch = new ArrayList<ContentProviderOperation>();
    // Build hash table of incoming entries
    HashMap<String, FeedParser.Entry> entryMap = new HashMap<String, FeedParser.Entry>();
    for (FeedParser.Entry e : entries) {
        entryMap.put(e.id, e);
    }
    // Get list of all items
    Log.i(TAG, "Fetching local entries for merge");
    // Get all entries
    Uri uri = FeedContract.Entry.CONTENT_URI;
    Cursor c = contentResolver.query(uri, PROJECTION, null, null, null);
    assert c != null;
    Log.i(TAG, "Found " + c.getCount() + " local entries. Computing merge solution...");
    // Find stale data
    int id;
    String entryId;
    String title;
    String link;
    long published;
    while (c.moveToNext()) {
        syncResult.stats.numEntries++;
        id = c.getInt(COLUMN_ID);
        entryId = c.getString(COLUMN_ENTRY_ID);
        title = c.getString(COLUMN_TITLE);
        link = c.getString(COLUMN_LINK);
        published = c.getLong(COLUMN_PUBLISHED);
        FeedParser.Entry match = entryMap.get(entryId);
        if (match != null) {
            // Entry exists. Remove from entry map to prevent insert later.
            entryMap.remove(entryId);
            // Check to see if the entry needs to be updated
            Uri existingUri = FeedContract.Entry.CONTENT_URI.buildUpon().appendPath(Integer.toString(id)).build();
            if ((match.title != null && !match.title.equals(title)) || (match.link != null && !match.link.equals(link)) || (match.published != published)) {
                // Update existing record
                Log.i(TAG, "Scheduling update: " + existingUri);
                batch.add(ContentProviderOperation.newUpdate(existingUri).withValue(FeedContract.Entry.COLUMN_NAME_TITLE, title).withValue(FeedContract.Entry.COLUMN_NAME_LINK, link).withValue(FeedContract.Entry.COLUMN_NAME_PUBLISHED, published).build());
                syncResult.stats.numUpdates++;
            } else {
                Log.i(TAG, "No action: " + existingUri);
            }
        } else {
            // Entry doesn't exist. Remove it from the database.
            Uri deleteUri = FeedContract.Entry.CONTENT_URI.buildUpon().appendPath(Integer.toString(id)).build();
            Log.i(TAG, "Scheduling delete: " + deleteUri);
            batch.add(ContentProviderOperation.newDelete(deleteUri).build());
            syncResult.stats.numDeletes++;
        }
    }
    c.close();
    // Add new items
    for (FeedParser.Entry e : entryMap.values()) {
        Log.i(TAG, "Scheduling insert: entry_id=" + e.id);
        batch.add(ContentProviderOperation.newInsert(FeedContract.Entry.CONTENT_URI).withValue(FeedContract.Entry.COLUMN_NAME_ENTRY_ID, e.id).withValue(FeedContract.Entry.COLUMN_NAME_TITLE, e.title).withValue(FeedContract.Entry.COLUMN_NAME_LINK, e.link).withValue(FeedContract.Entry.COLUMN_NAME_PUBLISHED, e.published).build());
        syncResult.stats.numInserts++;
    }
    Log.i(TAG, "Merge solution ready. Applying batch update");
    mContentResolver.applyBatch(FeedContract.CONTENT_AUTHORITY, batch);
    mContentResolver.notifyChange(// URI where data was modified
    FeedContract.Entry.CONTENT_URI, // No local observer
    null, // IMPORTANT: Do not sync to network
    false);
// This sample doesn't support uploads, but if *your* code does, make sure you set
// syncToNetwork=false in the line above to prevent duplicate syncs.
}
Also used : ContentProviderOperation(android.content.ContentProviderOperation) HashMap(java.util.HashMap) ArrayList(java.util.ArrayList) Cursor(android.database.Cursor) Uri(android.net.Uri) ContentResolver(android.content.ContentResolver) FeedParser(com.example.android.basicsyncadapter.net.FeedParser)

Aggregations

ContentProviderOperation (android.content.ContentProviderOperation)1 ContentResolver (android.content.ContentResolver)1 Cursor (android.database.Cursor)1 Uri (android.net.Uri)1 FeedParser (com.example.android.basicsyncadapter.net.FeedParser)1 ArrayList (java.util.ArrayList)1 HashMap (java.util.HashMap)1