使用 Realm 库获取光标

Get cursor by using Realm library

我正在为我的列表视图使用游标适配器。我打算使用内容解析器来获取光标。现在我改变了主意,给它一个学习 Realm 的机会。

如何使用领域获取 "Cursor" 对象?顺便说一下,我也很感激能提供一些片段来对光标进行排序。

谢谢。

final class Contact extends RealmObject {

private CharSequence mName;


public CharSequence getName() {
    return mName;
}

public void setName(CharSequence name) {
    this.mName = name;
}

}

final class ContactListAdapter extends CursorRecyclerViewAdapter<ContactListAdapter.ContactHolder> implements View.OnClickListener {

private OnContactClickListener mListener;


public ContactListAdapter(Context context, Cursor cursor) {
    super(context, cursor);
}

@Override
public ContactHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    View itemView = getLayoutInflater().inflate(R.layout.cell_contact, parent, false);

    ContactHolder contactHolder = new ContactHolder(itemView);
    contactHolder.mContactPhotoImageView.setOnClickListener(this);

    return contactHolder;
}

@Override
public void onBindViewHolder(ContactHolder viewHolder, Cursor cursor) {
    viewHolder.mNameTextView.setText("Emre Akturk");

    int position = cursor.getPosition();
    viewHolder.mContactPhotoImageView.setImageResource(R.mipmap.ic_launcher);
    viewHolder.mContactPhotoImageView.setTag(position);
}

@Override
public int getItemCount() {
    return 5;
}

public void setOnContactClickListener(OnContactClickListener callback) {
    this.mListener = callback;
}

@Override
public void onClick(View v) {
    if (mListener == null) {
        return;
    }

    int position = (int) v.getTag();
    if (position == -1) {
        mListener.onContactCallClicked(v, getCursor(), position);
    } else {
        mListener.onContactAddClicked(v, position);
    }
}

public interface OnContactClickListener {
    void onContactCallClicked(View v, Cursor cursor, int position);

    void onContactAddClicked(View v, int position);
}

protected class ContactHolder extends RecyclerView.ViewHolder {
    private TextView mNameTextView;
    private CircleImageView mContactPhotoImageView;

    protected ContactHolder(View itemView) {
        super(itemView);
        mNameTextView = (TextView) itemView.findViewById(R.id.cell_contact_name_textview);
        mContactPhotoImageView = (CircleImageView) itemView.findViewById(R.id.cell_contact_photo_imageview);
    }
}

}

这里是 Realm 的基督徒。 Realm 目前没有公开 Cursor,尽管这是我们想要做的事情:https://github.com/realm/realm-java/issues/438

如果您想将 RecyclerView 与 Realm 一起使用,我会推荐这篇博文以获取有关如何集成它们的建议:http://gradlewhy.ghost.io/realm-results-with-recyclerview/

目前,我认为 Realm 不支持 ContentProvider 架构。

但是,只是为了在 Cursor 界面上进行匹配,您可以从 Realm 中获取列表结果并根据该数据创建一个 MatrixCursor

当然,这不是 RAM 性能的最佳解决方案。游标支持确实是 Realm 上非常需要的功能。

试试这个。它并不完美(我什至不知道所有 Cursor 方法的作用...),但它对我有用:

open class DetachedRealmCursor<T : RealmModel>(val clazz: Class<T>, fn: (Realm) -> RealmResults<T>) : Cursor {
    open val result: List<T> by lazy {
        val realm = Realm.getDefaultInstance()
        val list = realm.copyFromRealm(fn(realm))
        //val list = fn(realm)
        realm.close()
        closed = false
        list
    }
    var current = 0
    protected var notUri: Uri? = null
    protected var contencontObservable = ContentObservable()
    protected var datasetObservable = DataSetObservable()

    private val columnTypes: List<Int>
    private val columnNames: List<String>
    private var extras : Bundle = Bundle.EMPTY
    private var closed = true

    val FIELD_TYPE_REALMLIST = Cursor.FIELD_TYPE_BLOB+1

    init {
        columnTypes = getFieldTypes()
        columnNames = getFieldNames()
    }

    private fun getFieldNames(): List<String> {
        return clazz.declaredFields?.map {
            it.name
        } ?: listOf("col1")
    }

    private fun getFieldTypes(): List<Int> {
        return clazz.declaredFields?.map {
            when (it.type) {
                String::class.java -> Cursor.FIELD_TYPE_STRING
                Float::class.java -> Cursor.FIELD_TYPE_FLOAT
                Int::class.java -> Cursor.FIELD_TYPE_INTEGER
                RealmList::class.java -> FIELD_TYPE_REALMLIST
                else -> Cursor.FIELD_TYPE_NULL
            }
        } ?: listOf(Cursor.FIELD_TYPE_STRING)
    }

    private fun getValueFromColumn(col: Int, pos: Int): Any? {
        val field = result[pos].javaClass.getDeclaredField(getColumnName(col))
        field.isAccessible = true
        return field.get(result[pos])
    }

    override fun moveToPosition(p0: Int): Boolean =
            if (p0 >= -1 && p0 <= result.size) {
                current = p0
                true
            } else
                false

    override fun moveToFirst(): Boolean =
            if (result.isNotEmpty()) {
                current = 0
                true
            } else false

    override fun move(p0: Int): Boolean = if (p0 >= -1 && p0 <= result.size) {
        current = p0
        true
    } else {
        false
    }

    override fun moveToPrevious(): Boolean = if (current > -1) {
        current--
        true
    } else false

    override fun moveToNext(): Boolean = if (current < result.size) {
        current++
        true
    } else false

    override fun isBeforeFirst(): Boolean = current == -1

    override fun moveToLast(): Boolean = if (result.isNotEmpty()) {
        current = result.size - 1
        true
    } else false

    override fun isAfterLast(): Boolean = current >= result.size

    override fun getColumnIndexOrThrow(p0: String): Int {
        val found = columnNames.indexOf(p0)
        return if (found == -1) throw IllegalArgumentException() else found
    }

    override fun getColumnNames(): Array<String> = columnNames.toTypedArray()

    override fun getType(p0: Int): Int = columnTypes[p0]

    override fun getColumnName(p0: Int): String = columnNames[p0]

    override fun getColumnIndex(p0: String?): Int = columnNames.indexOf(p0)

    override fun getColumnCount(): Int = columnNames.size

    override fun getNotificationUri(): Uri? = notUri

    override fun deactivate() {}

    override fun requery(): Boolean = true

    override fun registerContentObserver(p0: ContentObserver) {
        // Register an observer that is called when changes happen to the content backing this cursor.
        // Typically the data set won't change until requery() is called.
        contencontObservable.registerObserver(p0)
    }

    override fun registerDataSetObserver(p0: DataSetObserver) {
        // Register an observer that is called when changes happen to the contents of the this
        // cursors data set, for example, when the data set is changed via requery(), deactivate(), or close().
        datasetObservable.registerObserver(p0)
    }

    override fun unregisterContentObserver(p0: ContentObserver?) {
        if(!closed) {
            contencontObservable.unregisterObserver(p0)
        }
    }

    override fun unregisterDataSetObserver(p0: DataSetObserver?) {
        datasetObservable.unregisterObserver(p0)
    }

    override fun getWantsAllOnMoveCalls(): Boolean = false

    override fun getPosition(): Int = current

    override fun close() {
        closed = true
        contencontObservable.unregisterAll()
        datasetObservable.notifyInvalidated()
    }

    override fun isClosed() = closed

    override fun getCount(): Int = result.size

    override fun isFirst(): Boolean = current == 1

    override fun isLast(): Boolean {
        return current == result.size - 1
    }

    override fun isNull(p0: Int): Boolean = getValueFromColumn(p0, current) == null

    // poniższe można zamienić na getValueFromColumn

    override fun getLong(p0: Int): Long = getValueFromColumn(p0, current) as Long

    override fun getFloat(p0: Int): Float = getValueFromColumn(p0, current) as Float

    override fun getInt(p0: Int): Int = getValueFromColumn(p0, current) as Int

    override fun getBlob(p0: Int): ByteArray = getValueFromColumn(p0, current) as ByteArray

    override fun getShort(p0: Int): Short = getValueFromColumn(p0, current) as Short

    override fun getString(p0: Int): String = getValueFromColumn(p0, current) as String

    override fun getDouble(p0: Int): Double = getValueFromColumn(p0, current) as Double

    fun getList(p0: Int): RealmList<*> = getValueFromColumn(p0, current) as RealmList<*>

    override fun setNotificationUri(p0: ContentResolver?, p1: Uri?) {
        notUri = p1
    }

    override fun copyStringToBuffer(p0: Int, p1: CharArrayBuffer?) {}

    override fun respond(extras: Bundle): Bundle = Bundle.EMPTY

    override fun getExtras(): Bundle = extras

    override fun setExtras(p0: Bundle) {
        extras = p0
    }
}

然后你可以像这样使用它:

val cursor = RealmCursor(RAlbum::class.java) { it.where(RAlbum::class.java).distinct("sTitle") }

当然,如果你在同一个线程上完成所有工作,你可以直接使用 realm 实例而不是 realm.copyFromRealm(fn(realm))