2017-08-21 13 views
0

レルムを使用していて、素晴らしいです。RealmRecyclerViewAdapterにレルムクエリーの更新が反映されていません

何かに対処してください。私が何か悪いことをしているのかなと思います。

レルムクエリの結果を表示するために使用しているRealmRecyclerViewAdapterがあります。レルム内のレコードを追加または更新すると、これは完全に機能します。リサイクルビューでsetHasFixedSize(false)にしていたので、すぐに更新することができました。これが正しいかどうかは分かりませんが、それはうまくいきます。

とにかく、それは私の問題ではありません。

私は自分のデータをフィルタリングすることを試みています。私は、次のクエリを持っている:

realm.where(Person::class.java).contains("name", nameFilter, Case.INSENSITIVE).findAllSorted("name") 

私はリサイクル業者ビューにこのRealmResultsを渡すことだし、それは追加/更新に素晴らしい作品。

ただし、フィルタを試みると自動的に更新されません。

フィルタ(nameFilterで指定)を単に変更するだけでは、クエリを再実行するには不十分です。これは私が推測するほど公平だ。私は文字列の値を変更したことを知るために領域がトリガーされないと思うので、

ただし、クエリを再計算しても、明示的にupdateDataをアダプタで呼び出さない限り、Recyclerビューで更新されないようです。これを行うには、これが最善の方法か、最も効率的な方法かどうかはわかりません。より良い方法がありますか?

完全なコード:

主な活動

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

'私のアダプタでupdateDataを明示的に呼び出します。これを行うには、これが最善の方法か、最も効率的な方法かどうかはわかりません。いい方法はありますか?いいえ – EpicPandaForce

答えて

1

うん、updateData()はそれを行うための方法です。クエリを更新したので、表示したいResultsは別のオブジェクトになります。データソースが変更されたことをアダプターに通知するには、updateData()を呼び出す必要があります。

ただし、データソースが変更されたため、ビュー全体がリフレッシュされるため、このようにRecyclerViewの素晴らしいアニメーションが失われる可能性があります。これを回避するにはいくつかの方法があります。

例:isSelectedに1つのフィールドを追加できます。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フィールドを設定するよりも高速です。

ほとんどの場合、フィルタ全体がリフレッシュされますが、updateData()は十分に機能しています。それだけで十分です。

+0

答えをありがとう。それについてもう少し考えてみると、同じクエリオブジェクトであるため、追加/更新が機能することは明らかだったはずです。しかし、フィルターの場合、照会は再実行する必要があり、アダプターが認識していない新しいオブジェクトであるため、なぜupdateDataを呼び出す必要がありますか。クエリを再実行して元のオブジェクトを更新する方法はありますか? –

+2

いいえ、今のところそれを行う方法はありません。 – beeender

関連する問題