一直在使用领域,它很棒。
遇到了什么。想知道我做错了什么。
我有RealmRecyclerViewAdapter
我用来显示领域查询的结果。如果我在领域中添加或更新记录,这将完美地工作。我必须在回收站视图上setHasFixedSize(false)
才能让它在运行时更新。不确定这是否正确但是有效。
无论如何,这不是我的问题。
我正在尝试过滤我的数据。我有以下查询:
realm.where(Person::class.java).contains("name", nameFilter, Case.INSENSITIVE).findAllSorted("name")
我将此RealmResults传递给我的回收站视图,它在添加/更新时效果很好。
但是,当我尝试过滤时,它不会自动更新。
我是否正确地说,仅仅更改我的过滤器(由nameFilter
指定)是不足以重新运行查询?我认为这是公平的。因为我觉得领域没有触发器知道我已经改变了字符串的值。
但是,即使我重新计算查询,它似乎也不会在Recycler视图中更新,除非我在我的适配器上显式调用updateData
。我不确定这是否是最好或最有效的方法。还有更好的方法吗?
完整代码:
主要活动
class MainActivity : AppCompatActivity(), View.OnClickListener {
private val TAG: String = this::class.java.simpleName
private val realm: Realm = Realm.getInstance(RealmConfiguration.Builder().deleteRealmIfMigrationNeeded().build())
private var nameFilter = ""
private var allPersons: RealmResults<Person> = realm.where(Person::class.java).contains("name", nameFilter, Case.INSENSITIVE).findAllSorted("name")
private val adapter: PersonRecyclerViewAdapter = PersonRecyclerViewAdapter(allPersons)
private lateinit var disposable: Disposable
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
realm.executeTransaction({
// realm.deleteAll()
})
Log.i(TAG, "Deleted all objects from Realm")
buttonAddOrUpdatePerson.setOnClickListener(this)
setUpRecyclerView()
disposable = RxTextView.textChangeEvents(editTextNameFilter)
// .debounce(400, TimeUnit.MILLISECONDS) // default Scheduler is Computation
.observeOn(AndroidSchedulers.mainThread())
.subscribeWith<DisposableObserver<TextViewTextChangeEvent>>(getSearchObserver())
}
private fun getSearchObserver(): DisposableObserver<TextViewTextChangeEvent> {
return object : DisposableObserver<TextViewTextChangeEvent>() {
override fun onComplete() {
Log.i(TAG,"--------- onComplete")
}
override fun onError(e: Throwable) {
Log.i(TAG, "--------- Woops on error!")
}
override fun onNext(onTextChangeEvent: TextViewTextChangeEvent) {
nameFilter = editTextNameFilter.text.toString()
allPersons = realm.where(Person::class.java).contains("name", nameFilter, Case.INSENSITIVE).findAllSorted("name")
// this is necessary or the recycler view doesn't update
adapter.updateData(allPersons)
Log.d(TAG, "Filter: $nameFilter")
}
}
}
override fun onDestroy() {
super.onDestroy()
realm.close()
}
override fun onClick(view: View?) {
if(view == null) return
when(view) {
buttonAddOrUpdatePerson -> handleAddOrUpdatePerson()
}
}
private fun handleAddOrUpdatePerson() {
val personToAdd = Person()
personToAdd.name = editTextName.text.toString()
personToAdd.email = editTextEmail.text.toString()
realm.executeTransactionAsync({
bgRealm -> bgRealm.copyToRealmOrUpdate(personToAdd)
})
}
private fun setUpRecyclerView() {
recyclerViewPersons.layoutManager = LinearLayoutManager(this)
recyclerViewPersons.adapter = adapter
recyclerViewPersons.setHasFixedSize(false)
recyclerViewPersons.addItemDecoration(DividerItemDecoration(this, LinearLayoutManager.VERTICAL))
}
}
PersonRecyclerViewAdapter
internal class PersonRecyclerViewAdapter(data: OrderedRealmCollection<Person>?, autoUpdate: Boolean = true) : RealmRecyclerViewAdapter<Person, PersonRecyclerViewAdapter.PersonViewHolder>(data, autoUpdate) {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): PersonViewHolder {
val itemView = LayoutInflater.from(parent.context).inflate(R.layout.person_row, parent, false)
return PersonViewHolder(itemView)
}
override fun onBindViewHolder(holder: PersonViewHolder?, position: Int) {
if(holder == null || data == null) return
val personList = data ?: return
val person = personList[position]
holder.bind(person)
}
internal class PersonViewHolder(view: View) : RecyclerView.ViewHolder(view) {
var textViewName: TextView = view.findViewById(R.id.textViewNameDisplay)
var textViewEmail: TextView = view.findViewById(R.id.textViewEmailDisplay)
internal fun bind(person: Person) {
textViewEmail.text = person.email
textViewName.text = person.name
}
}
}
答案 0 :(得分:2)
是的,int(); // value initialized - always 0
int{}; // value initialized - always 0
int a; // default initialized - indeterminate value
struct X {};
X x{}; // aggregate initialized
是这样做的方法。由于您更新了查询,因此要显示的updateData()
将成为另一个对象。必须调用Results
来通知适配器数据源已更改。
但是,您可能会以这种方式丢失RecyclerView的漂亮动画,因为由于数据源已更改,整个视图将被刷新。有一些方法可以解决这个问题。
例如:您可以向updateData()
添加一个字段isSelected
。按Person
字段查询结果并将其传递给适配器:
isSelected
更改查询时:
allPersons = realm.where(Person::class.java).equalTo("isSelected", true).findAllSorted("name")
adapter = PersonRecyclerViewAdapter(allPersons)
这取决于您的使用案例,如果要显示的列表很长,此方法可能会很慢,您可以尝试将所有已过滤的人员添加到realm.executeTransactionAsync({
var allPersons = realm.where(Person::class.java).equalTo("isSelected", true).findAllSorted("name")
for (person in allPersons) person.isSelected = false; // Clear the list first
allPersons = realm.where(Person::class.java).contains("name", nameFilter, Case.INSENSITIVE).findAllSorted("name") // new query
for (person in allPersons) person.isSelected = true;
})
并将RealmList
设置为适配器的数据源。 RealmList
是一个快速操作,而不是迭代整个结果集来设置RealmList.clear()
字段。
如果过滤器主要导致整个视图刷新,那么isSelected
就足够了,只需使用它即可。