我正在使用RxJava2,Kotlin和Room作为我的例子。
这是用于将我的项目填充到recyclerView的适配器:
class ShoppingListDetailsAdapter(val list: ArrayList<ShoppingListElementItem>, val context: Context, val listener: ShoppingItemCheckboxListener, val isArchived: Boolean) : RecyclerView.Adapter<ShoppingListDetailsAdapter.ViewHolder>() {
override fun getItemCount(): Int {
return list.count()
}
override fun onCreateViewHolder(parent: ViewGroup?, viewType: Int): ViewHolder {
val itemView = LayoutInflater.from(parent?.getContext())
.inflate(R.layout.item_shopping_list_element, parent, false)
return ViewHolder(itemView)
}
override fun onBindViewHolder(holder: ViewHolder?, position: Int) {
val item = list.get(position)
holder?.name?.setText(item.name)
if(item.isCompleted){
holder?.isCompleted?.isChecked = true
}
if(isArchived)
holder?.isCompleted?.isEnabled = false
else{
holder?.isCompleted?.isEnabled = true
}
holder?.isCompleted?.setOnCheckedChangeListener{
buttonView, isChecked ->
item.isCompleted = isChecked
listener.onClick(position, isChecked)
}
}
inner class ViewHolder(view: View) : RecyclerView.ViewHolder(view) {
var name: TextView
var isCompleted: CheckBox
private var viewClickListener: ShoppingItemCheckboxListener? = null
init {
name = view.findViewById(R.id.itemName)
isCompleted = view.findViewById(R.id.checkbox)
}
}
fun removeItem(position: Int) {
list.removeAt(position)
// notify the item removed by position
// to perform recycler view delete animations
// NOTE: don't call notifyDataSetChanged()
notifyItemRemoved(position)
}
fun restoreItem(item: ShoppingListElementItem, position: Int) {
list.add(position, item)
// notify item added by position
notifyItemInserted(position)
}
}
这是我的ViewModel:
class ShoppingListViewModel(private val dataSource: ShoppingListDao) : ViewModel() {
fun createShoppingList(listName: String){
val arrayList = ArrayList<ShoppingListItem>()
val shoppingList = ShoppingList(name = listName, isArchived = false, items = arrayList, timestamp = Date())
dataSource.insertShoppingList(shoppingList)
}
fun createShoppingListItem(itemName: String, shoppingListId: Int){
dataSource.getShoppingList(shoppingListId)
.firstElement()
.subscribe {
shoppingList: ShoppingList ->
val items = shoppingList.items
items.add(ShoppingListItem(itemName, false, Date()))
dataSource.updateShoppingList(shoppingList = shoppingList)
}
}
fun getShoppingLists(): Flowable<List<ShoppingList>> {
return dataSource.getActiveShoppingLists()
.map {
t -> t.sortedByDescending { it.timestamp }
}
}
fun getArchivedLists(): Flowable<List<ShoppingList>> {
return dataSource.getArchivedShoppingLists()
.map {
t -> t.sortedByDescending { it.timestamp }
}
}
fun getShoppingList(id: Int): Flowable<ShoppingList> {
return dataSource.getShoppingList(id)
}
fun archiveItem(deletedShoppingListItem: com.app.shoppinglistapp.ui.ShoppingListDTO) {
dataSource.archiveShoppingList(deletedShoppingListItem.id)
}
fun reArchiveItem(deletedShoppingListItem: com.app.shoppinglistapp.ui.ShoppingListDTO){
dataSource.reArchiveShoppingList(deletedShoppingListItem.id)
}
fun removeShoppingListItem(deletedItem: ShoppingListElementItem, shoppingListId: Int) {
dataSource.getShoppingList(shoppingListId)
.firstElement()
.subscribe {
shoppingList: ShoppingList ->
val items: ArrayList<ShoppingListItem> = shoppingList.items
val filter = items.filter {
it.timestamp != deletedItem.timestamp
}
dataSource.updateShoppingList(shoppingList = ShoppingList(id = shoppingList.id,
name = shoppingList.name,
isArchived = shoppingList.isArchived,
timestamp = shoppingList.timestamp,
items = filter as ArrayList<ShoppingListItem>
))
}
}
fun restoreShoppingListItem(deletedItem: ShoppingListElementItem, shoppingListId: Int) {
dataSource.getShoppingList(shoppingListId)
.firstElement()
.subscribe {
shoppingList: ShoppingList ->
val items = shoppingList.items
items.add(ShoppingListItem(deletedItem.name, deletedItem.isCompleted, deletedItem.timestamp))
dataSource.updateShoppingList(shoppingList = ShoppingList(id = shoppingList.id,
name = shoppingList.name,
isArchived = shoppingList.isArchived,
timestamp = shoppingList.timestamp,
items = items
))
}
}
fun updateShoppingList(shoppingList: ArrayList<ShoppingListElementItem>, shoppingListId: Int) {
dataSource.getShoppingList(shoppingListId)
.firstElement()
.subscribe {
t: ShoppingList ->
val dbShoppingList = ArrayList<ShoppingListItem>()
shoppingList.forEach {
it -> dbShoppingList.add(ShoppingListItem(it.name, it.isCompleted, it.timestamp))
}
dataSource.updateShoppingList(shoppingList = ShoppingList(id = t.id,
name = t.name,
isArchived = t.isArchived,
timestamp = t.timestamp,
items = dbShoppingList
))
}
}
}
这是我的Dao界面:
@Dao
interface ShoppingListDao {
@Query("SELECT * FROM shopping_list where id = :id limit 1")
fun getShoppingList(id: Int): Flowable<ShoppingList>
@Query("SELECT * FROM shopping_list where not is_archived")
fun getActiveShoppingLists(): Flowable<List<ShoppingList>>
@Query("SELECT * FROM shopping_list where is_archived")
fun getArchivedShoppingLists(): Flowable<List<ShoppingList>>
@Insert(onConflict = OnConflictStrategy.REPLACE)
fun insertShoppingList(shoppingList: ShoppingList)
@Update
fun updateShoppingList(shoppingList: ShoppingList)
@Query("UPDATE shopping_list SET is_archived = 1 where id = :id")
fun archiveShoppingList(id: Int)
@Query("UPDATE shopping_list SET is_archived = 0 where id = :id")
fun reArchiveShoppingList(id: Int)
}
这是活动:
class ShoppingListDetailsActivity : AppCompatActivity(), RecyclerItemTouchHelper.RecyclerItemTouchHelperListener, ShoppingItemCheckboxListener {
private lateinit var viewModelFactory: ViewModelFactory
private lateinit var viewModel: ShoppingListViewModel
private var intExtra: Int? = null
private var isArchived: Boolean? = null
private val disposable = CompositeDisposable()
private var shoppingList = ArrayList<ShoppingListElementItem>()
private var mAdapter: ShoppingListDetailsAdapter? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main2)
setSupportActionBar(toolbar)
supportActionBar!!.setDisplayHomeAsUpEnabled(true)
intExtra = getIntent().getIntExtra("id", 0)
isArchived = getIntent().getBooleanExtra("isArchived", false)
viewModelFactory = Injection.provideViewModelFactory(this)
viewModel = ViewModelProviders.of(this, viewModelFactory).get(ShoppingListViewModel::class.java)
// mAdapter = ShoppingListDetailsAdapter(shoppingList, this, this, isArchived!!)
val mLayoutManager = LinearLayoutManager(applicationContext)
recyclerView.setLayoutManager(mLayoutManager)
recyclerView.setItemAnimator(DefaultItemAnimator())
recyclerView.addItemDecoration(DividerItemDecoration(this, DividerItemDecoration.VERTICAL))
// recyclerView.setAdapter(mAdapter)
if (isArchived as Boolean) {
fab.visibility = View.GONE
}
else{
fab.setOnClickListener { view ->
val alertDialogAndroid = getShoppingListDialog()
alertDialogAndroid?.show()
}
}
val itemTouchHelperCallback1 = object : ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.LEFT or ItemTouchHelper.RIGHT) {
override fun onMove(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder, target: RecyclerView.ViewHolder): Boolean {
return true
}
override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {
// Row is swiped from recycler view
// remove it from adapter
if (viewHolder is ShoppingListDetailsAdapter.ViewHolder) {
// get the removed item name to display it in snack bar
val name = shoppingList[viewHolder.adapterPosition].name
// backup of removed item for undo purpose
val deletedItem = shoppingList[viewHolder.adapterPosition]
val deletedIndex = viewHolder.adapterPosition
// remove the item from recycler view
mAdapter?.removeItem(viewHolder.adapterPosition)
viewModel.removeShoppingListItem(deletedItem, intExtra!!)
// showing snack bar with Undo option
val snackbar = Snackbar
.make(coordinatorLayout, name + " is deleted!", Snackbar.LENGTH_LONG)
snackbar.setAction("UNDO", View.OnClickListener {
// undo is selected, restore the deleted item
mAdapter?.restoreItem(deletedItem, deletedIndex)
viewModel.restoreShoppingListItem(deletedItem, intExtra!!)
})
snackbar.setActionTextColor(Color.YELLOW)
snackbar.show()
}
Log.v("Test", "test")
}
override fun onChildDraw(c: Canvas, recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder, dX: Float, dY: Float, actionState: Int, isCurrentlyActive: Boolean) {
super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive)
}
}
if (!isArchived!!)
ItemTouchHelper(itemTouchHelperCallback1).attachToRecyclerView(recyclerView)
}
fun getShoppingListDialog(): AlertDialog? {
val layoutInflaterAndroid = LayoutInflater.from(this)
val mView = layoutInflaterAndroid.inflate(R.layout.dialog_input_name, null)
val alertDialogBuilderUserInput = AlertDialog.Builder(this)
alertDialogBuilderUserInput.setView(mView)
val userInputDialogEditText = mView.findViewById(R.id.userInputDialog) as EditText
alertDialogBuilderUserInput
.setCancelable(false)
.setPositiveButton("Send", DialogInterface.OnClickListener { dialogBox, id ->
viewModel.createShoppingListItem(userInputDialogEditText.text.toString(), intExtra!!)
})
.setNegativeButton("Cancel",
DialogInterface.OnClickListener { dialogBox, id -> dialogBox.cancel() })
return alertDialogBuilderUserInput.create()
}
override fun onSupportNavigateUp(): Boolean {
onBackPressed()
return true
}
override fun onStart() {
super.onStart()
if (intExtra != null)
viewModel.getShoppingList(intExtra!!)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe({ t ->
shoppingList.clear()
t.items.forEach {
val item = ShoppingListElementItem(0, it.name, false, it.timestamp)
shoppingList.add(item)
}
shoppingList.size
mAdapter = ShoppingListDetailsAdapter(shoppingList, this, this, isArchived!!)
recyclerView.setAdapter(mAdapter)
// mAdapter?.notifyDataSetChanged()
})
}
override fun onStop() {
super.onStop()
// clear all the subscription
disposable.clear()
}
override fun onClick(position: Int, isChecked: Boolean) {
shoppingList.get(position).isCompleted = isChecked
viewModel.updateShoppingList(shoppingList, intExtra!!)
Toast.makeText(applicationContext, "isChecked: ${isChecked}", Toast.LENGTH_SHORT).show()
}
override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int, position: Int) {
}
}
当我试图检查我的RecyclerView项目中的checbox时,它立即被检查为false。
以下是模型实体:
@Entity(tableName = "shopping_list")
data class ShoppingList(
@PrimaryKey(autoGenerate = true)
@ColumnInfo(name = "id")
val id: Int = 0,
@ColumnInfo(name = "name")
val name: String,
@ColumnInfo(name = "is_archived")
val isArchived: Boolean,
@ColumnInfo(name = "timestamp")
val timestamp: Date,
@ColumnInfo(name = "items")
val items: ArrayList<ShoppingListItem>
)
data class ShoppingListItem(
val name: String,
val isCompleted: Boolean,
val timestamp: Date
)
购物清单项目的布局:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout android:orientation="horizontal"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
xmlns:tools="http://schemas.android.com/tools">
<CheckBox
android:id="@+id/checkbox"
android:layout_weight="1"
android:layout_width="0dp"
android:layout_height="match_parent" />
<TextView
android:id="@+id/itemName"
android:layout_gravity="start"
tools:text="GOWNO"
android:layout_weight="1"
android:textAlignment="textStart"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
和ShoppingListElementItem类:
data class ShoppingListElementItem(
var id: Int,
var name: String,
var isCompleted: Boolean,
val timestamp: Date
)
听众:
interface ShoppingItemCheckboxListener {
fun onClick(position: Int, isChecked: Boolean)
}
当我尝试检查我的RecyclerView项目中的复选框时,立即检查它是否为false。在更新复选框后的我的Acitivty订阅方法中,从db获取的更新项目被正确设置为选中(“isCompleted”),但我想我的适配器设置有问题。在我的onBindViewHolder方法中,设置为选中的项目始终为false,因此我猜它没有正确更新适配器列表项。
如何使其正常工作?
更新
即使我重新启动应用程序,复选框也不会设置为true,但是db中提取的项目的属性“isCompleted”设置为true。问题是在适配器真的,我不知道为什么它没有我期望的项目 - 在我的Activity中的订阅方法中,我正在获取要正确填充到适配器的项目。
答案 0 :(得分:1)
可以请检查此功能
/**
* Returns an unordered integer array.
* @return
*/
private static int[] getIntArray() {
return new int[]{54, 899, 213, 2, 43, 8, 12, 11, 111, 43, 6, 44, 83, 3458};
}
在此功能中,您订阅了可流动的购物清单,这意味着只要数据库中有更新,此订阅方法就会被调用,以下代码会将完成的值重置为false
override fun onStart() {
super.onStart()
if (intExtra != null)
viewModel.getShoppingList(intExtra!!)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe({ t ->
shoppingList.clear()
t.items.forEach {
val item = ShoppingListElementItem(0, it.name, false, it.timestamp)
shoppingList.add(item)
}
shoppingList.size
mAdapter = ShoppingListDetailsAdapter(shoppingList, this, this, isArchived!!)
recyclerView.setAdapter(mAdapter)
// mAdapter?.notifyDataSetChanged()
})
答案 1 :(得分:0)
我认为问题在于这段代码
holder?.isCompleted?.setOnCheckedChangeListener{
buttonView, isChecked ->
item.isCompleted = isChecked
listener.onClick(position, isChecked)
}
当您点击该复选框时,isChecked
为真,如果我没有记错,listener.onClick(position,isChecked)
会点击RecyclerView
中的相同项目。 ShoppingItemCheckboxListener
做了什么?