MVVM Recyclerview Livedata Room SearchView

MVVM Recyclerview Livedata Room SearchView

我正在使用 room, mvvm, livedata 制作 数据库 应用程序。我已经用一些数据预先填充了它。现在我有两个选择,要么在应用程序通过 recyclerview 启动时显示预填充数据,要么在我使用 recyclerView.SearchView 搜索它时显示它。
问题 是当我搜索特定项目时,itw 会在我完成我的单词时显示该项目,当我尝试返回时我的 resView 返回空白或它始终停留在该项目上。我想找个时间 realtime 试试,比如:当我只输入一个字母表时,它显示所有建议都属于字母表,我只想用 livedata
更新 我尝试了什么?
1-> 我已经尝试过 switchMapliveData 一起工作,但我必须刷新我的 activity 才能取回我的列表。
2-> 我已经尝试过 resView 过滤器,但它没有用,因为我正在使用 livedata 更新我的 UI,并且在没有 livedata 的情况下定期尝试它,它仍然没有用。
3-> 我尝试过常规 editText 只是为了尝试,但我发现它没有用,因为面临同样的问题,我的主要关注点是 searchView
RecyclerView 代码 具有可过滤或忽略可过滤部分根本不是很好的尝试

class MyAdapter(
    private var context: Context,
    private var dataList: List<SearchPojo>
) : RecyclerView.Adapter<MyAdapter.BaseViewHolder<*>>(), Filterable {

    private var exampleListFull: List<SearchPojo>? = null

    init {
        exampleListFull = ArrayList(dataList)

    }

    companion object {
        const val SEARCH_TYPE = 1
    }

    abstract class BaseViewHolder<T>(view: View) : RecyclerView.ViewHolder(view) {
        abstract fun bind(t: T)
    }

    inner class SearchViewHolder(view: View) : BaseViewHolder<SearchPojo>(view) {
        private val userID: TextView = view.findViewById(R.id.idSearch)
        private val userName: TextView = view.findViewById(R.id.nameSearch)
        private val userPos: TextView = view.findViewById(R.id.positionSearch)

        override fun bind(t: SearchPojo) {
            userID.text = t.id
            userName.text = t.userName
            userPos.text = t.position
        }
    }


    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BaseViewHolder<*> {
        return when (viewType) {
            SEARCH_TYPE -> {
                val view =
                    LayoutInflater.from(context).inflate(R.layout.layout_show_data, parent, false)
                SearchViewHolder(view)
            }
            else -> {
                throw IllegalAccessException("In valid View Type")
            }
        }
    }

    override fun getItemCount(): Int {
        return dataList.size
    }

    override fun onBindViewHolder(holder: BaseViewHolder<*>, position: Int) {
        val element = dataList[position]
        when (holder) {
            is SearchViewHolder -> {
                holder.bind(element)
            }
        }
    }

    override fun getItemViewType(position: Int): Int {
        return when (dataList[position]) {
            is SearchPojo -> SEARCH_TYPE

            else -> throw IllegalAccessException()
        }
    }

    override fun getFilter(): Filter {
        return exampleFilter
    }

    private var exampleFilter = object : Filter() {

        override fun performFiltering(constraint: CharSequence?): FilterResults {
            val filteredList = ArrayList<SearchPojo>()

            if (constraint == null || constraint.isEmpty()) {
                filteredList.addAll(exampleListFull as Iterable<SearchPojo>)
            } else {
                val filterPattern = constraint.toString().toLowerCase().trim { it <= ' ' }

                for (item in exampleListFull!!) {
                    if (item.userName.toLowerCase().contains(filterPattern)) {
                        filteredList.add(item)
                    }
                }
            }

            val results = FilterResults()
            results.values = filteredList

            return results
        }

        override fun publishResults(constraint: CharSequence, results: FilterResults) {
            dataList.clear()
            dataList.addAll(results.values as List<SearchPojo>)
            notifyDataSetChanged()
        }
    }

}

主要Activity

class MainActivity : AppCompatActivity() {

    lateinit var searchViewModel: SearchViewModel
    lateinit var myAdapter: MyAdapter

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        if (!::searchViewModel.isInitialized) {
            searchViewModel = ViewModelProviders.of(this)[SearchViewModel::class.java]
            searchViewModel.getAll().observe(this, Observer {
                myAdapter(it)
            })

        }

        searchItems.addTextChangedListener(object : TextWatcher {
            override fun afterTextChanged(s: Editable?) {
            }

            override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
            }

            override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
                nameFromDb(s.toString())
            }
        })
    }

    override fun onCreateOptionsMenu(menu: Menu?): Boolean {
        menuInflater.inflate(R.menu.search_item, menu)

        val searchItem = menu!!.findItem(R.id.search_menu)
        val searchView = searchItem.actionView as SearchView


        searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
            override fun onQueryTextSubmit(query: String?): Boolean {
                return false
            }

            override fun onQueryTextChange(newText: String?): Boolean {
                myAdapter.getFilter().filter(newText)
                return true
            }
        })


        return super.onCreateOptionsMenu(menu)
    }

    override fun onOptionsItemSelected(item: MenuItem?): Boolean {
        when (item!!.itemId) {
            R.id.refresh -> {
                val intent = Intent(this, MainActivity::class.java)
                startActivity(intent)
            }
        }
        return true
    }


    private fun nameFromDb(searchTxt: String) {
        searchViewModel = ViewModelProviders.of(this)[SearchViewModel::class.java]
        searchViewModel.items.observe(this, object : Observer<List<SearchPojo>> {
            override fun onChanged(t: List<SearchPojo>?) {
                if (t == null) {
                    return
                }
                myAdapter(t)
            }
        })

        searchViewModel.searchIt(searchTxt)

    }

    private fun myAdapter(t: List<SearchPojo>) {
        searchResultResView.apply {
            layoutManager = LinearLayoutManager(context)
            myAdapter = MyAdapter(this@MainActivity, t)
            adapter = myAdapter

        }
    }
}

ViewModel

lass SearchViewModel(application: Application) :
    AndroidViewModel(application) {
    private val repo: SearchRepo = SearchRepo(application)

    private val _searchItem : MutableLiveData<String> = MutableLiveData()

    val items : LiveData<List<SearchPojo>> = Transformations.switchMap(_searchItem) { myItems ->
        repo.searchItem(myItems)
    }

    init {
            _searchItem.value = ""
    }

    fun searchIt(items: String) {
        _searchItem.value = items
    }

    fun getAll() = repo.allSearch()
}

存储库

class SearchRepo(application: Application) {

    private val searchDao: SearchDao


    init {
        val db = SearchDb.instance(application)
        searchDao = db.searchDao()

    }


    fun searchItem(id: String): LiveData<List<SearchPojo>> {
        return searchDao.searchViaID(id)
    }

    fun allSearch() : LiveData<List<SearchPojo>> {
        return searchDao.allSearch()
    }


}

@Dao
abstract class SearchDao : BaseDao<SearchPojo> {

    @Query("Select * from SearchPojo")
    abstract fun allSearch(): LiveData<List<SearchPojo>>

    @Query("Select * from SearchPojo where userName Like :userNameSearch or LOWER(userName) like LOWER(:userNameSearch)")
    abstract fun searchViaID(userNameSearch: String) : LiveData<List<SearchPojo>>

    @Insert
    abstract override fun insert(searchPojo: SearchPojo)

}

请像这样改变你的@Dao class

@Dao
abstract class SearchDao : BaseDao<SearchPojo> {

    @Query("Select * from SearchPojo")
    abstract fun allSearch(): LiveData<List<SearchPojo>>

    @Query("Select * from SearchPojo where userName GLOB '*' || :userNameSearch|| '*'")
    abstract fun searchViaID(userNameSearch: String) : LiveData<List<SearchPojo>>

    @Insert
    abstract override fun insert(searchPojo: SearchPojo)

}