So, I've been used Realm for a while. For now, I have a task to share the login data with my other apps.
Since the login data is stored using Realm. I choose to use Content Provider.
I found an example: https://speakerdeck.com/androhi/realm-with-contentprovider
Unfortunately, I was unable to make it work. This is my Content Provider in app A
static final String[] sColumns = new String[]{
        "LoginResultData"
};
public Cursor query(@NonNull Uri uri, @Nullable String[] projection, @Nullable String selection,
                    @Nullable String[] selectionArgs, @Nullable String sortOrder) {
    Realm mRealm = Realm.getDefaultInstance();
    RealmQuery<LoginResultData> query = mRealm.where(LoginResultData.class);
    LoginResultData result = query.findFirst();
    String json = new Gson().toJson(result);
    MatrixCursor matrixCursor = new MatrixCursor(sColumns);
    Object[] rowData = new Object[]{json};
    matrixCursor.addRow(rowData);
    return matrixCursor;
}
App B (which need to get the login data) got hang when I
getContentResolver.query(uri, null, null, null, null);
I don't know why but it worked well when I use SQlite. So I'm assuming that Realm doesn't work well with Content Provider smh. Is that true?
If not, please show me a sample to using Content Provider with Realm.
Thanks!
Content Provider works well with RealmDB.
All you need to do is to override the CRUD methods inside the ContentProvider. Please take a look at this content provider class below. 3 things to note:
RealmDB is initialized in the onCreate() method of the ContentProvider (not the app activity)
You override the CRUD methods(Query, Insert, Delete, Update) in a manner appropriate for RealmDB. Check below samples.
- This is all you need to do. In the rest of the code, you will be using native components like recyclerview, adapter, loaders, services. Everywhere you need a query, you will call it with getContentResolver.query(uri, null, null, null, null);
 
TaskProvider.java
package com.example.rgher.realmtodo.data;
import android.app.job.JobInfo;
import android.app.job.JobScheduler;
import android.content.ComponentName;
import android.content.ContentProvider;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.MatrixCursor;
import android.net.Uri;
import android.support.annotation.Nullable;
import android.text.format.DateUtils;
import android.util.Log;
import io.realm.DynamicRealm;
import io.realm.Realm;
import io.realm.RealmConfiguration;
import io.realm.RealmMigration;
import io.realm.RealmResults;
import io.realm.RealmSchema;
import com.example.rgher.realmtodo.data.DatabaseContract.TaskColumns;
public class TaskProvider extends ContentProvider {
    private static final String TAG = TaskProvider.class.getSimpleName();
    private static final int CLEANUP_JOB_ID = 43;
    private static final int TASKS = 100;
    private static final int TASKS_WITH_ID = 101;
    private static final UriMatcher sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
    static {
        // content://com.example.rgher.realmtodo/tasks
        sUriMatcher.addURI(DatabaseContract.CONTENT_AUTHORITY,
                DatabaseContract.TABLE_TASKS,
                TASKS);
        // content://com.example.rgher.realmtodo/tasks/id
        sUriMatcher.addURI(DatabaseContract.CONTENT_AUTHORITY,
                DatabaseContract.TABLE_TASKS + "/#",
                TASKS_WITH_ID);
    }
    @Override
    public boolean onCreate() {
        //Innitializing RealmDB
        Realm.init(getContext());
        RealmConfiguration config = new RealmConfiguration.Builder()
                .schemaVersion(1)
                .migration(new MyRealmMigration())
                .build();
        Realm.setDefaultConfiguration(config);
        manageCleanupJob();
        return true;
    }
    @Nullable
    @Override
    public String getType(Uri uri) {
        return null; /* Not used */
    }
    @Nullable
    @Override
    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
                        String sortOrder) {
        int match = sUriMatcher.match(uri);
        //Get Realm Instance
        Realm realm = Realm.getDefaultInstance();
        MatrixCursor myCursor = new MatrixCursor( new String[]{TaskColumns._ID, TaskColumns.DESCRIPTION
                , TaskColumns.IS_COMPLETE, TaskColumns.IS_PRIORITY
                , TaskColumns.DUE_DATE
        });
        try {
            switch (match) {
                //Expected "query all" Uri: content://com.example.rgher.realmtodo/tasks
                case TASKS:
                    RealmResults<RealmTask> tasksRealmResults = realm.where(RealmTask.class).findAll();
                    for (RealmTask myTask : tasksRealmResults) {
                        Object[] rowData = new Object[]{myTask.getTask_id(), myTask.getDescription(), myTask.getIs_complete()
                                , myTask.getIs_priority(), myTask.getDue_date()};
                        myCursor.addRow(rowData);
                        Log.v("RealmDB", myTask.toString());
                    }
                    break;
                //Expected "query one" Uri: content://com.example.rgher.realmtodo/tasks/{id}
                case TASKS_WITH_ID:
                    Integer id = Integer.parseInt(uri.getPathSegments().get(1));
                    RealmTask myTask = realm.where(RealmTask.class).equalTo("task_id", id).findFirst();
                    myCursor.addRow(new Object[]{myTask.getTask_id(), myTask.getDescription(), myTask.getIs_complete(), myTask.getIs_priority(), myTask.getDue_date()});
                    Log.v("RealmDB", myTask.toString());
                    break;
                default:
                    throw new UnsupportedOperationException("Unknown uri: " + uri);
            }
        myCursor.setNotificationUri(getContext().getContentResolver(), uri);
        } finally {
            realm.close();
        }
        return myCursor;
    }
    @Nullable
    @Override
    public Uri insert(Uri uri, final ContentValues contentValues) {
        //COMPLETE: Expected Uri: content://com.example.rgher.realmtodo/tasks
        //final SQLiteDatabase taskDb = mDbHelper.getReadableDatabase();
        int match = sUriMatcher.match(uri);
        Uri returnUri;
        //Get Realm Instance
        Realm realm = Realm.getDefaultInstance();
        try {
            switch (match) {
                case TASKS:
                    realm.executeTransaction(new Realm.Transaction() {
                        @Override
                        public void execute(Realm realm) {
                            Number currId = realm.where(RealmTask.class).max(TaskColumns._ID);
                            Integer nextId = (currId == null) ? 1 : currId.intValue() + 1;
                            RealmTask myNewTask = realm.createObject(RealmTask.class, nextId);
                            myNewTask.setDescription(contentValues.get(TaskColumns.DESCRIPTION).toString());
                            myNewTask.setIs_complete((Integer) contentValues.get(TaskColumns.IS_COMPLETE));
                            myNewTask.setIs_priority((Integer) contentValues.get(TaskColumns.IS_PRIORITY));
                            myNewTask.setDue_date((Long) contentValues.get(TaskColumns.DUE_DATE));
                        }
                    });
                    returnUri = ContentUris.withAppendedId(DatabaseContract.CONTENT_URI, '1');
                    break;
                default:
                    throw new UnsupportedOperationException("Unknown uri: " + uri);
            }
            getContext().getContentResolver().notifyChange(uri, null);
        }finally {
            realm.close();
        }
        return returnUri;
    }
    @Override
    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
        //Expected Uri: content://com.example.rgher.realmtodo/tasks/{id}
        Realm realm = Realm.getDefaultInstance();
            int match = sUriMatcher.match(uri);
            int nrUpdated = 0;
        try {
            switch (match) {
                case TASKS_WITH_ID:
                    Integer id = Integer.parseInt(uri.getPathSegments().get(1));
                    RealmTask myTask = realm.where(RealmTask.class).equalTo("task_id", id).findFirst();
                    realm.beginTransaction();
                    myTask.setIs_complete(Integer.parseInt(values.get(TaskColumns.IS_COMPLETE).toString()));
                    if (values.get(TaskColumns.DUE_DATE) != null) {
                        myTask.setDue_date(Long.valueOf(values.get(TaskColumns.DUE_DATE).toString()));
                    }
                    nrUpdated++;
                    realm.commitTransaction();
                    break;
                default:
                    throw new UnsupportedOperationException("Unknown uri: " + uri);
            }
        } finally {
            realm.close();
        }
        if (nrUpdated != 0) {
            getContext().getContentResolver().notifyChange(uri, null);
        }
        return nrUpdated;
    }
    @Override
    public int delete(Uri uri, String selection, String[] selectionArgs) {
        int count = 0;
        Realm realm = Realm.getDefaultInstance();
        try {
            switch (sUriMatcher.match(uri)) {
                case TASKS:
                    selection = (selection == null) ? "1" : selection;
                    RealmResults<RealmTask> tasksRealmResults = realm.where(RealmTask.class).equalTo(selection, Integer.parseInt(selectionArgs[0])).findAll();
                    realm.beginTransaction();
                    tasksRealmResults.deleteAllFromRealm();
                    count++;
                    realm.commitTransaction();
                    break;
                case TASKS_WITH_ID:
                    Integer id = Integer.parseInt(String.valueOf(ContentUris.parseId(uri)));
                    RealmTask myTask = realm.where(RealmTask.class).equalTo("task_id", id).findFirst();
                    realm.beginTransaction();
                    myTask.deleteFromRealm();
                    count++;
                    realm.commitTransaction();
                    break;
                default:
                    throw new IllegalArgumentException("Illegal delete URI");
            }
        } finally {
            realm.close();
        }
        if (count > 0) {
            //Notify observers of the change
            getContext().getContentResolver().notifyChange(uri, null);
        }
        return count;
    }
}
// Example of REALM migration
class MyRealmMigration implements RealmMigration {
    @Override
    public void migrate(DynamicRealm realm, long oldVersion, long newVersion) {
        RealmSchema schema = realm.getSchema();
        if (oldVersion != 0) {
            schema.create(DatabaseContract.TABLE_TASKS)
                    .addField(DatabaseContract.TaskColumns._ID, Integer.class)
                    .addField(DatabaseContract.TaskColumns.DESCRIPTION, String.class)
                    .addField(DatabaseContract.TaskColumns.IS_COMPLETE, Integer.class)
                    .addField(DatabaseContract.TaskColumns.IS_PRIORITY, Integer.class);
            oldVersion++;
        }
    }
}
You can find the full working app here https://github.com/rgherta/RealmTodo
Good luck
来源:https://stackoverflow.com/questions/43485746/realm-with-content-provider