包含 headers 部分的 RealmBaseAdapter
RealmBaseAdapter with section headers
我正在尝试为 Android 使用 realm
数据存储,并且我正在尝试构建一个应用程序向用户显示 ListView
中的选项列表,有点像用户联系人列表。每个部分(如 A、B、C 等)的首字母应为 header。有没有办法用 RealmBaseAdapter
来实现这个?
目前我正在使用它 ArrayAdapter
并且我只是有一个填充了值的数组,但如果可能的话,我想使用它的适配器从 Realm 中提取数据。我知道在 iOS 中使用 NSFetchedResultsController
非常简单。我们如何将 RealmResults
分成几个部分?
RealmBaseAdapter 不能与 ExpandableListAdapter 一起使用(我假设您正在使用它来创建部分?),所以现在您唯一的选择是创建您自己的实现。但是 RealmResults 也是一个列表,因此它应该可以与 ArrayAdapter 无缝协作。
您还可以在此处查看更多详细信息:https://github.com/realm/realm-java/issues/978
这是我用的:
package com.poterion.android.library.adapters
import android.widget.BaseExpandableListAdapter
import io.realm.*
/**
* @author Jan Kubovy <jan@kubovy.eu>
*/
abstract class RealmExpandableListAdapter<out Group : Any, Item : RealmModel>(
private val itemGroupsProvider: (Item) -> Collection<Group?>,
private val groupsProvider: (Collection<Item>) -> List<Group?>,
private var adapterData: OrderedRealmCollection<Item>?) : BaseExpandableListAdapter() {
private val listener: RealmChangeListener<OrderedRealmCollection<Item>>?
protected val groups: List<Group?>
get() {
return adapterData?.takeIf { isDataValid }?.let(groupsProvider) ?: emptyList()
}
private val isDataValid: Boolean
get() = adapterData?.isValid == true
init {
if (adapterData?.isManaged == false)
throw IllegalStateException("Only use this adapter with managed list, for un-managed lists you can just use the BaseAdapter")
this.listener = RealmChangeListener { notifyDataSetChanged() }
adapterData?.takeIf { isDataValid }?.also { addListener(it) }
}
private fun addListener(data: OrderedRealmCollection<Item>) {
when (data) {
is RealmResults<Item> -> data.addChangeListener((listener as RealmChangeListener<RealmResults<Item>>))
is RealmList<Item> -> data.addChangeListener((listener as RealmChangeListener<RealmList<Item>>))
else -> throw IllegalArgumentException("RealmCollection not supported: " + data.javaClass)
}
}
private fun removeListener(data: OrderedRealmCollection<Item>) {
when (data) {
is RealmResults<Item> -> data.removeChangeListener((listener as RealmChangeListener<RealmResults<Item>>))
is RealmList<Item> -> data.removeChangeListener((listener as RealmChangeListener<RealmList<Item>>))
else -> throw IllegalArgumentException("RealmCollection not supported: " + data.javaClass)
}
}
override fun getGroupCount(): Int = groups.size
override fun getChildrenCount(groupPosition: Int): Int = adapterData?.takeIf { isDataValid }?.let { data ->
val g = groups[groupPosition]
data.filter { g == null || groups(it).contains(g) }.size
} ?: 0
override fun getGroup(groupPosition: Int): Group? = if (groups.size > groupPosition) groups[groupPosition] else null
override fun getChild(groupPosition: Int, childPosition: Int): Item? = children(groupPosition)
.takeIf { it.size > childPosition }?.get(childPosition)
override fun notifyDataSetChanged() {
super.notifyDataSetChanged()
}
private fun children(groupPosition: Int): List<Item> {
return getGroup(groupPosition)
?.let { g -> adapterData?.takeIf { isDataValid }?.filter { groups(it).contains(g) } } ?: emptyList()
}
}
和用法:
class PersonListAdapter(realm: Realm) :
RealmExpandableListAdapter<String, Person>(
itemGroupsProvider = { person -> arrayOf(person.group, null) },
groupsProvider = { people -> people.map { it.group } },
adapterData = realm.where(Person::class.java)
.findAllSortedAsync("lastName", Sort.ASCENDING, "firstName", Sort.ASCENDING)) {
override fun getGroupId(groupPosition: Int) = getGroup(groupPosition).id
override fun getChildId(groupPosition: Int, childPosition: Int) = getChild(groupPosition, childPosition).id
override fun hasStableIds() = true
override fun getGroupView(groupPosition: Int, isExpanded: Boolean, convertView: View?, parent: ViewGroup?): View {
// ... Item View here ...
}
override fun getChildView(groupPosition: Int, childPosition: Int, isLastChild: Boolean,
convertView: View?, parent: ViewGroup?): View {
// ... Group View here ...
}
override fun isChildSelectable(groupPosition: Int, childPosition: Int) = true
}
我正在尝试为 Android 使用 realm
数据存储,并且我正在尝试构建一个应用程序向用户显示 ListView
中的选项列表,有点像用户联系人列表。每个部分(如 A、B、C 等)的首字母应为 header。有没有办法用 RealmBaseAdapter
来实现这个?
目前我正在使用它 ArrayAdapter
并且我只是有一个填充了值的数组,但如果可能的话,我想使用它的适配器从 Realm 中提取数据。我知道在 iOS 中使用 NSFetchedResultsController
非常简单。我们如何将 RealmResults
分成几个部分?
RealmBaseAdapter 不能与 ExpandableListAdapter 一起使用(我假设您正在使用它来创建部分?),所以现在您唯一的选择是创建您自己的实现。但是 RealmResults 也是一个列表,因此它应该可以与 ArrayAdapter 无缝协作。
您还可以在此处查看更多详细信息:https://github.com/realm/realm-java/issues/978
这是我用的:
package com.poterion.android.library.adapters
import android.widget.BaseExpandableListAdapter
import io.realm.*
/**
* @author Jan Kubovy <jan@kubovy.eu>
*/
abstract class RealmExpandableListAdapter<out Group : Any, Item : RealmModel>(
private val itemGroupsProvider: (Item) -> Collection<Group?>,
private val groupsProvider: (Collection<Item>) -> List<Group?>,
private var adapterData: OrderedRealmCollection<Item>?) : BaseExpandableListAdapter() {
private val listener: RealmChangeListener<OrderedRealmCollection<Item>>?
protected val groups: List<Group?>
get() {
return adapterData?.takeIf { isDataValid }?.let(groupsProvider) ?: emptyList()
}
private val isDataValid: Boolean
get() = adapterData?.isValid == true
init {
if (adapterData?.isManaged == false)
throw IllegalStateException("Only use this adapter with managed list, for un-managed lists you can just use the BaseAdapter")
this.listener = RealmChangeListener { notifyDataSetChanged() }
adapterData?.takeIf { isDataValid }?.also { addListener(it) }
}
private fun addListener(data: OrderedRealmCollection<Item>) {
when (data) {
is RealmResults<Item> -> data.addChangeListener((listener as RealmChangeListener<RealmResults<Item>>))
is RealmList<Item> -> data.addChangeListener((listener as RealmChangeListener<RealmList<Item>>))
else -> throw IllegalArgumentException("RealmCollection not supported: " + data.javaClass)
}
}
private fun removeListener(data: OrderedRealmCollection<Item>) {
when (data) {
is RealmResults<Item> -> data.removeChangeListener((listener as RealmChangeListener<RealmResults<Item>>))
is RealmList<Item> -> data.removeChangeListener((listener as RealmChangeListener<RealmList<Item>>))
else -> throw IllegalArgumentException("RealmCollection not supported: " + data.javaClass)
}
}
override fun getGroupCount(): Int = groups.size
override fun getChildrenCount(groupPosition: Int): Int = adapterData?.takeIf { isDataValid }?.let { data ->
val g = groups[groupPosition]
data.filter { g == null || groups(it).contains(g) }.size
} ?: 0
override fun getGroup(groupPosition: Int): Group? = if (groups.size > groupPosition) groups[groupPosition] else null
override fun getChild(groupPosition: Int, childPosition: Int): Item? = children(groupPosition)
.takeIf { it.size > childPosition }?.get(childPosition)
override fun notifyDataSetChanged() {
super.notifyDataSetChanged()
}
private fun children(groupPosition: Int): List<Item> {
return getGroup(groupPosition)
?.let { g -> adapterData?.takeIf { isDataValid }?.filter { groups(it).contains(g) } } ?: emptyList()
}
}
和用法:
class PersonListAdapter(realm: Realm) :
RealmExpandableListAdapter<String, Person>(
itemGroupsProvider = { person -> arrayOf(person.group, null) },
groupsProvider = { people -> people.map { it.group } },
adapterData = realm.where(Person::class.java)
.findAllSortedAsync("lastName", Sort.ASCENDING, "firstName", Sort.ASCENDING)) {
override fun getGroupId(groupPosition: Int) = getGroup(groupPosition).id
override fun getChildId(groupPosition: Int, childPosition: Int) = getChild(groupPosition, childPosition).id
override fun hasStableIds() = true
override fun getGroupView(groupPosition: Int, isExpanded: Boolean, convertView: View?, parent: ViewGroup?): View {
// ... Item View here ...
}
override fun getChildView(groupPosition: Int, childPosition: Int, isLastChild: Boolean,
convertView: View?, parent: ViewGroup?): View {
// ... Group View here ...
}
override fun isChildSelectable(groupPosition: Int, childPosition: Int) = true
}