Android

Content Providers

Auth Gábor

Agenda

Mi is ez?
Hogy?
Lekérdezések
Adatmódosítások
Hogyan?
Kérdések-válaszok

Mi is ez?

Adatok tárolása és lekérdezése
Alkalmazások közötti kommunikáció egyetlen "jó" módja
Lehet beépített vagy saját

Beépített

Névjegyzék
SMS
Híváslista
Média tartalom
Könyvjelzők
stb

Saját

Az alkalmazásunk létre tud hozni és publikálni tud több Content Provider osztályt is, amelyeket akár más programból el lehet érni.

Hogy?

Egyszerű adatbázis
CRUD (Create, Read, Update, Delete) modell
A kiszolgáló oldalon többnyire SQLite van
A kliens a ContentResolver metódust használja

Adatmodell

Minden sor egy önálló bejegyzés
Minden oszlopnak lehet típusa
Minden sort egy _ID nevű oszlop egyértelműen azonosít

Query

A lekérdezés eredménye egy Cursor példány
A Cursor léptethető (moveToNext, moveToLast, stb)
A Cursor nem ismeri saját tartalmát
Nekünk kell gondoskodni arról, hogy a megfelelő sorrendben...
...és a megfelelő típust olvassuk ki...
...különben konvertál

URI

Minden táblának van egy egyedi URI címe
Minden adatnak van egy egyedi URI címe
android.provider.*.CONTENT_URI
A ContentResolver keresi meg az URI alapján a tartalmat

Az URI felépítése

content://hu.javaforum.example/adatok/1234
type      content provider     table  id
                

Lekérdezés

Kell az URI (mutathat egy sorra is)
Kell egy lista a mezőkről
Esetleg egy szűkítés se árt

Példa

final Cursor nextTrackCursor = getContentResolver()
        .query(PlayListContentProvider.CONTENT_URI,
               new String[]{"_id","artist","timestamp"},
               "timestamp > ?",
               new String[]{"" + now},
               "timestamp ASC LIMIT 1 OFFSET 0");
                

Cursor?!

if (nextTrackCursor.moveToNext()) {
    artist = nextTrackCursor.getString(1);
    nextTrackTimestamp = nextTrackCursor.getLong(2);
}
                

Adatmódosítás

Sor(ok) beszúrása
Sor(ok) módosítása
Sor(ok) törlése

Sor(ok) beszúrása

final ContentValues cv = new ContentValues();
cv.put("artist", "Senki Valaki");
final URI row = getContentResolver()
        .insert(PlayListContentProvider.CONTENT_URI,
                cv);
                

Sor(ok) módosítása

final ContentValues ev = new ContentValues();
ev.put("artist", "Valaki Más");
final URI row = getContentResolver()
        .update(PlayListContentProvider.CONTENT_URI,
                cv,
                null,
                null);
                

Sor(ok) módosítása

final ContentValues ev = new ContentValues();
ev.put("artist", "Valaki Más");
final URI row = getContentResolver()
        .update(PlayListContentProvider.CONTENT_URI,
                cv,
                "timstampe = ?",
                new String[]{now});
                

Sor(ok) törlése

final URI row = getContentResolver()
        .delete(PlayListContentProvider.CONTENT_URI,
                null,
                null);
                

Sor(ok) törlése

final URI row = getContentResolver()
        .delete(PlayListContentProvider.CONTENT_URI,
                "timstampe = ?",
                new String[]{now});
                

Hogyan?!

Kell egy bejegyzése az AndroidManifest.xml fájlban
Kell egy adatforrás
Kell egy saját ContentProvider

AndroidManifest.xml

<provider android:authorities="hu.javaforum.playlist.contentProvider"
          android:name=".contentproviders.PlayListContentProvider"
          android:exported="false"/>
                
public class PlayListDatabase extends SQLiteOpenHelper {

    private static final String DATABASE_NAME = "playlist.db";
    private static final int DATABASE_VERSION = 1;

    public PlayListDatabase(final Context context) {
        super(context, DATABASE_NAME, null, DATABASE_VERSION);
    }

    @Override
    public final void onCreate(final SQLiteDatabase database) {
        final String createSql = "create table item("
                + "_id integer primary key autoincrement, "
                + "artist text NOT NULL,"
                + "timestamp integer NOT NULL,"
                + ")";
        database.execSQL(createSql);
    }

    @Override
    public final void onUpgrade(final SQLiteDatabase db, final int oldVersion, final int newVersion) {
    }
                

ContentProvider

public class PlayListContentProvider extends ContentProvider {

    @Override
    public final boolean onCreate() {
    }

    @Override
    public final int delete(final Uri uri, final String selection, final String[] selectionArgs) {
    }

    @Override
    public final Uri insert(final Uri uri, final ContentValues values) {
    }

    @Override
    public final Cursor query(final Uri uri, final String[] projection, final String selection,
                              final String[] selectionArgs, final String sortOrder) {
    }

    @Override
    public final int update(final Uri uri, final ContentValues values,
                            final String selection, final String[] selectionArgs) {
    }

    @Override
    public String getType(final Uri uri) {
    }
}
                
    public static final int ITEM_CONSTANT = 10;
    public static final String ITEM_TYPE = ContentResolver.CURSOR_ITEM_BASE_TYPE + "/item";
    public static final int TABLE_CONSTANT = 20;
    public static final String TABLE_TYPE = ContentResolver.CURSOR_DIR_BASE_TYPE + "/table";

    @Override
    public final boolean onCreate() {
        this.database = new PlayListDatabase(getContext());

        return false;
    }
                
    @Override
    public final int delete(final Uri uri, final String selection, final String[] selectionArgs) {
        final SQLiteDatabase db = this.database.getWritableDatabase();

        switch (this.getUriMatcher().match(uri)) {
            case TABLE_CONSTANT:
                return db.delete("item", selection, selectionArgs);
            case ITEM_CONSTANT:
                String id = uri.getLastPathSegment();
                if (TextUtils.isEmpty(selection)) {
                    return db.delete("item", "_id=" + id, null);
                }
                return db.delete("item", "_id=" + id + " and " + selection, selectionArgs);
            default:
                throw new IllegalArgumentException("Unknown URI: " + uri);
    }
                
    @Override
    public final Uri insert(final Uri uri, final ContentValues values) {
        if (TABLE_CONSTANT != this.getUriMatcher().match(uri)) {
            logger.warn("Unknown URI type: %1$s", uri);
            return null;
        }

        final SQLiteDatabase db = this.database.getWritableDatabase();
        final long id = db.insert("item", null, values);

        return Uri.parse("item" + "/" + id);
    }
                
    @Override
    public final Cursor query(final Uri uri, final String[] projection, final String selection,
                              final String[] selectionArgs, final String sortOrder) {
        SQLiteQueryBuilder queryBuilder = new SQLiteQueryBuilder();
        queryBuilder.setTables("item");

        switch (this.getUriMatcher().match(uri)) {
            case TABLE_CONSTANT:
                break;
            case ITEM_CONSTANT:
                queryBuilder.appendWhere("_id=" + uri.getLastPathSegment());
                break;
            default:
                throw new IllegalArgumentException("Unknown URI: " + uri);
        }
        SQLiteDatabase db = this.database.getWritableDatabase();
        Cursor cursor = queryBuilder.query(db, projection, selection, selectionArgs, null, null, sortOrder);
        cursor.setNotificationUri(getContext().getContentResolver(), uri);

        return cursor;
    }
                
    @Override
    public final int update(final Uri uri, final ContentValues values,
                            final String selection, final String[] selectionArgs) {
        final SQLiteDatabase db = this.database.getWritableDatabase();

        switch (this.getUriMatcher().match(uri)) {
            case TABLE_CONSTANT:
                return db.update("item", values, selection, selectionArgs);
            case ITEM_CONSTANT:
                final String id = uri.getLastPathSegment();
                if (TextUtils.isEmpty(selection)) {
                    return db.update("item", values, "_id=" + id, null);
                }
                return db.update("item", values, "_id=" + id + " and " + selection, selectionArgs);
            default:
                throw new IllegalArgumentException("Unknown URI: " + uri);
        }
    }
                

Kérdések? :)


images/qr_code.png
(Presentation by impress.js)