2012-04-20 7 views
11

Ho un Android ContentProvider che consente di eseguire query LEFT OUTER JOIN su un database SQLite.Android ContentProvider URI schema per notificare CursorAdapters in ascolto su query OUTER JOIN

Supponiamo che nel database ci siano 3 tabelle, Users, Articles e Comments. Il ContentProvider è qualcosa di simile al seguente:

public class SampleContentProvider extends ContentProvider { 
    private static final UriMatcher sUriMatcher; 
    public static final String AUTHORITY = "com.sample.contentprovider"; 
    private static final int USERS_TABLE = 1; 
    private static final int USERS_TABLE_ID = 2; 
    private static final int ARTICLES_TABLE = 3; 
    private static final int ARTICLES_TABLE_ID = 4; 
    private static final int COMMENTS_TABLE = 5; 
    private static final int COMMENTS_TABLE_ID = 6; 
    private static final int ARTICLES_USERS_JOIN_TABLE = 7; 
    private static final int COMMENTS_USERS_JOIN_TABLE = 8; 

    // [...] other ContentProvider methods 

    @Override 
    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { 
     String table = getTableName(uri); 

     // SQLiteWrapper is a wrapper class to manage a SQLiteHelper 
     Cursor c = SQLiteWrapper.get(getContext()).getHelper().getReadableDatabase() 
       .query(table, projection, selection, selectionArgs, null, null, sortOrder); 

     c.setNotificationUri(getContext().getContentResolver(), uri); 
     return c; 
    } 

    @Override 
    public Uri insert(Uri uri, ContentValues values) { 
     String table = getTableName(uri); 

     // SQLiteWrapper is a wrapper class to manage a SQLiteHelper 
     long id = SQLiteWrapper.get(getContext()).getHelper().getWritableDatabase() 
       .insert(table, null, values); 

     Uri itemUri = ContentUris.withAppendedId(uri, id); 
     getContext().getContentResolver().notifyChange(itemUri, null); 

     return itemUri; 
    } 

    private String getTableName(Uri uri) { 
     switch (sUriMatcher.match(uri)) { 
     case USERS_TABLE: 
     case USERS_TABLE_ID: 
      return "Users"; 

     case ARTICLES_TABLE: 
     case ARTICLES_TABLE_ID: 
      return "Articles"; 

     case COMMENTS_TABLE: 
     case COMMENTS_TABLE_ID: 
      return "Comments"; 

     case ARTICLES_USERS_JOIN_TABLE: 
      return "Articles a LEFT OUTER JOIN Users u ON (u._id = a.user_id)"; 

     case COMMENTS_USERS_JOIN_TABLE: 
      return "Comments c LEFT OUTER JOIN Users u ON (u._id = c.user_id)"; 

     default: 
      throw new IllegalArgumentException("Unknown URI " + uri); 
     } 
    } 

    static { 
     sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH); 
     sUriMatcher.addURI(AUTHORITY, "users", USERS_TABLE); 
     sUriMatcher.addURI(AUTHORITY, "articles", ARTICLES_TABLE); 
     sUriMatcher.addURI(AUTHORITY, "comments", COMMENTS_TABLE); 
     sUriMatcher.addURI(AUTHORITY, "users" + "/#", USERS_TABLE_ID); 
     sUriMatcher.addURI(AUTHORITY, "articles" + "/#", ARTICLES_TABLE_ID); 
     sUriMatcher.addURI(AUTHORITY, "comments" + "/#", COMMENTS_TABLE_ID); 
     sUriMatcher.addURI(AUTHORITY, "???", ARTICLES_USERS_JOIN_TABLE); // what uri here? 
     sUriMatcher.addURI(AUTHORITY, "???", COMMENTS_USERS_JOIN_TABLE); // what uri here? 
    } 
} 

Qual è il miglior schema URI di notificare tutti CursorAdapter s ascolto su query uniti e non iscritti ogni volta che inserisco (o aggiornare) una riga nella tabella Users?

In altre parole, se aggiungere o aggiornare una nuova riga in una delle tabelle, voglio inviare un singolo notifica con getContext().getContentResolver().notifyChange(itemUri, null) in modo che tutto il CursorAdapter s ascolto su qualsiasi query (USERS_TABLE, ARTICLES_USERS_JOIN_TABLE, COMMENTS_USERS_JOIN_TABLE) ricevere una notifica per aggiornare il loro contenuto.

Se ciò non è possibile, esiste un modo alternativo per avvisare tutti gli osservatori?

risposta

5

si può avere speciale Uri di interrogare con:

sUriMatcher.addURI(AUTHORITY, "articlesusers", ARTICLES_USERS_JOIN_TABLE); 
    sUriMatcher.addURI(AUTHORITY, "commentsusers", COMMENTS_USERS_JOIN_TABLE); 

ma non riesco a pensare ad un modo per inviare una singola notifica. Sembra che la scelta migliore sia quella di inviare una notifica per ogni Uri che si riferisce alla tabella che viene modificata. Quindi i tuoi metodi di inserimento/aggiornamento/cancellazione chiamerebbero notifyChange più volte a seconda della tabella interessata. Per le modifiche a "utenti" ci saranno 3 notifiche - utenti, utenti di articoli e utenti di commenti - poiché dipendono tutti dalla tabella "utenti".

1

Come risposto da prodaea, ecco un'altra alternativa che è possibile utilizzare per la notifica Uri. Questa non è una soluzione perfetta, ma usa solo un Uri per la notifica.

La soluzione consiste nell'utilizzare l'Uri principale senza alcun nome di tabella (ad esempio contenuto: //com.example.app.provider/) come Uri di notifica nel metodo di query per ARTICLES_USERS_JOIN_TABLE e COMMENTS_USERS_JOIN_TABLE. Quindi, il cursore relativo verrà notificato ogni volta che c'è un cambiamento in qualsiasi tabella. C'è una limitazione però. Cioè, il cursore ARTICLES_USERS_JOIN_TABLE verrà avvisato anche quando c'è una variazione nella tabella Articles.

Per le tabelle, Users' and Articoli ', è possibile utilizzare il proprio Uris specifico per la notifica.

+0

modo più elegante di chiamare notifyChange dopo ogni inserimento/aggiornamento/eliminazione come suggerito in [risposta satur9nine] (http://stackoverflow.com/a/11661855/5756760)! – Joni