我正在用RoomDB写一个笔记应用程序,当我试图更新现有的笔记时,它会在数据库中更新,但我必须重新启动应用程序或打开另一个片段,然后返回Recycler视图进行更新
下面是我的适配器:
class RVNotesAdapter : ListAdapter<Note, RVNotesAdapter.NoteViewHolder>(DiffUtilCallback()) {
inner class NoteViewHolder(item: View) : RecyclerView.ViewHolder(item) {
val binding = NoteItemLayoutBinding.bind(item)
val title = binding.noteItemTitle
val content = binding.noteContentItem
val date = binding.noteDate
val parent = binding.noteItemLayoutParent
val markWon = Markwon.builder(item.context)
.usePlugin(StrikethroughPlugin.create())
.usePlugin(TaskListPlugin.create(item.context))
.usePlugin(object : AbstractMarkwonPlugin() {
override fun configureVisitor(builder: MarkwonVisitor.Builder) {
super.configureVisitor(builder)
builder.on(
SoftLineBreak::class.java
) { visitor, _ ->
visitor.forceNewLine()
}
}
}).build()
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): NoteViewHolder {
return NoteViewHolder(LayoutInflater.from(parent.context)
.inflate(R.layout.note_item_layout,parent,false))
}
override fun onBindViewHolder(holder: NoteViewHolder, position: Int) {
getItem(position).let {note->
holder.apply {
parent.transitionName = "recyclerView_${note.id}"
title.text = note.title
markWon.setMarkdown(content,note.content)
date.text = note.date
parent.setCardBackgroundColor(note.color)
itemView.setOnClickListener {
val action = NoteFragmentDirections.actionNoteFragmentToSaveOrUpdateFragment()
.setNote(note)
val extras = FragmentNavigatorExtras(parent to "recyclerView_${note.id}")
it.hideKeyboard()
Navigation.findNavController(it).navigate(action,extras)
}
content.setOnClickListener {
val action = NoteFragmentDirections.actionNoteFragmentToSaveOrUpdateFragment()
.setNote(note)
val extras = FragmentNavigatorExtras(parent to "recyclerView_${note.id}")
it.hideKeyboard()
Navigation.findNavController(it).navigate(action,extras)
}
}
}
}
}
字符串
下面是Diffutil类:
class DiffUtilCallback : DiffUtil.ItemCallback<Note>() {
override fun areItemsTheSame(oldItem: Note, newItem: Note): Boolean {
return oldItem.id == newItem.id
}
override fun areContentsTheSame(oldItem: Note, newItem: Note): Boolean {
return oldItem.id == newItem.id
}
}
型
下面是NoteFragment:
@AndroidEntryPoint
class NoteFragment : Fragment(R.layout.fragment_note) {
private lateinit var binding: FragmentNoteBinding
private val noteActivityViewModel by viewModels<NoteActivityViewModel>()
private lateinit var rvNotesAdapter: RVNotesAdapter
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding = FragmentNoteBinding.bind(view)
val activity = activity as MainActivity
val navController = Navigation.findNavController(view)
requireView().hideKeyboard()
CoroutineScope(Dispatchers.Main).launch {
delay(10)
// activity.window.statusBarColor = Color.WHITE
activity.window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS)
activity.window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS)
activity.window.statusBarColor = Color.parseColor("#9e9d9d")
}
binding.addNoteFab.setOnClickListener {
binding.appBar.visibility = INVISIBLE
navController.navigate(NoteFragmentDirections.actionNoteFragmentToSaveOrUpdateFragment())
}
binding.innerFab.setOnClickListener {
binding.appBar.visibility = INVISIBLE
navController.navigate(NoteFragmentDirections.actionNoteFragmentToSaveOrUpdateFragment())
}
recyclerViewDisplay()
swipeToDelete(binding.rvNote)
// implement search
binding.search.addTextChangedListener(object : TextWatcher {
override fun beforeTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {
binding.noData.isVisible = false
}
override fun onTextChanged(s: CharSequence?, p1: Int, p2: Int, p3: Int) {
if (s.toString().isNotEmpty()) {
val text = s.toString()
val query = "%$text%"
if (query.isNotEmpty()) {
noteActivityViewModel.searchNote(query).observe(viewLifecycleOwner) {
rvNotesAdapter.submitList(it)
}
} else {
observerDataChanges()
}
} else {
observerDataChanges()
}
}
override fun afterTextChanged(p0: Editable?) {
}
})
binding.search.setOnEditorActionListener { v, actionId, _ ->
if (actionId == EditorInfo.IME_ACTION_SEARCH) {
v.clearFocus()
requireView().hideKeyboard()
}
return@setOnEditorActionListener true
}
binding.rvNote.setOnScrollChangeListener { _, scrollX, scrollY, _, oldscrollY ->
when {
scrollY > oldscrollY -> {
binding.fabText.isVisible = false
}
scrollX == scrollY -> {
binding.fabText.isVisible = true
}
else -> {
binding.fabText.isVisible = true
}
}
}
}
private fun swipeToDelete(rvNote: RecyclerView) {
val swipeToDeleteCallBack = object : SwipeToDelete() {
override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {
val position = viewHolder.absoluteAdapterPosition
val note = rvNotesAdapter.currentList[position]
var actionBTNTab = false
noteActivityViewModel.deleteNote(note)
binding.search.apply {
hideKeyboard()
clearFocus()
}
if (binding.search.toString().isEmpty()) {
observerDataChanges()
}
val snackBar = Snackbar.make(
requireView(),
"یادداشت حذف شد",
Snackbar.LENGTH_SHORT
)
.addCallback(object : BaseTransientBottomBar.BaseCallback<Snackbar>() {
override fun onDismissed(transientBottomBar: Snackbar?, event: Int) {
super.onDismissed(transientBottomBar, event)
}
override fun onShown(transientBottomBar: Snackbar?) {
transientBottomBar?.setAction("برگرد") {
noteActivityViewModel.addNote(note)
actionBTNTab = true
binding.noData.isVisible = false
}
super.onShown(transientBottomBar)
}
})
.apply {
animationMode = Snackbar.ANIMATION_MODE_SLIDE
setAnchorView(R.id.add_note_fab)
}
snackBar.setActionTextColor(
ContextCompat.getColor(
requireContext(),
R.color.yellowOrange
)
)
.show()
}
}
val itemTouchHelper = ItemTouchHelper(swipeToDeleteCallBack)
itemTouchHelper.attachToRecyclerView(rvNote)
}
private fun recyclerViewDisplay() {
when (resources.configuration.orientation) {
Configuration.ORIENTATION_PORTRAIT -> {
setUpRecyclerView(2)
}
Configuration.ORIENTATION_LANDSCAPE -> {
setUpRecyclerView(3)
}
}
}
private fun setUpRecyclerView(spanCount: Int) {
binding.rvNote.apply {
layoutManager =
StaggeredGridLayoutManager(spanCount, StaggeredGridLayoutManager.VERTICAL)
setHasFixedSize(true)
rvNotesAdapter = RVNotesAdapter()
rvNotesAdapter.stateRestorationPolicy =
RecyclerView.Adapter.StateRestorationPolicy.PREVENT_WHEN_EMPTY
adapter = rvNotesAdapter
postponeEnterTransition(300L, TimeUnit.MILLISECONDS)
viewTreeObserver.addOnPreDrawListener {
startPostponedEnterTransition()
true
}
}
observerDataChanges()
}
private fun observerDataChanges() {
noteActivityViewModel.allNotes.observe(viewLifecycleOwner) { list ->
binding.noData.isVisible = list.isEmpty()
rvNotesAdapter.submitList(list)
}
}
}
型
下面是saveOrUpdate Fragment的所有代码:
@AndroidEntryPoint
class SaveOrUpdateFragment : Fragment(R.layout.fragment_save_or_update) {
private lateinit var navController: NavController
private lateinit var binding: FragmentSaveOrUpdateBinding
private var note: Note? = null
private var color = -1
private lateinit var result: String
private val noteActivityViewModel by viewModels<NoteActivityViewModel>()
private val currentDate = SimpleDateFormat.getInstance().format(Date())
private val job = CoroutineScope(Dispatchers.Main)
private val args: SaveOrUpdateFragmentArgs by navArgs()
private lateinit var rvNotesAdapter: RVNotesAdapter
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val animation = MaterialContainerTransform().apply {
drawingViewId = R.id.fragment
scrimColor = Color.TRANSPARENT
duration = 300
}
sharedElementEnterTransition = animation
sharedElementReturnTransition = animation
}
@SuppressLint("SetTextI18n")
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding = FragmentSaveOrUpdateBinding.bind(view)
navController = Navigation.findNavController(view)
val activity = activity as MainActivity
ViewCompat.setTransitionName(
binding.noteContentFragParent,
"recyclerView_${args.note?.id}"
)
binding.backButton.setOnClickListener {
requireView().hideKeyboard()
navController.popBackStack()
}
binding.saveNote.setOnClickListener {
saveNote()
}
try {
binding.etNoteContent.setOnFocusChangeListener { view, hasFocus ->
if (hasFocus) {
binding.bottomBar.visibility = View.VISIBLE
binding.etNoteContent.setStylesBar(binding.styleBar)
} else {
binding.bottomBar.visibility = View.GONE
}
}
} catch (e: Exception) {
Log.e("TAG", "$e")
}
binding.fabColorPicker.setOnClickListener {
val bottomSheetDialog = BottomSheetDialog(
requireContext(),
R.style.BottomSheetDialogTheme
)
val bottomSheetView: View = layoutInflater.inflate(R.layout.bottom_sheet_layout, null)
with(bottomSheetDialog) {
setContentView(bottomSheetView)
show()
}
val bottomSheetBinding = BottomSheetLayoutBinding.bind(bottomSheetView)
bottomSheetBinding.apply {
colorPicker.apply {
setSelectedColor(color)
setOnColorSelectedListener { value ->
color = value
binding.apply {
noteContentFragParent.setBackgroundColor(color)
toolbarFragNoteContent.setBackgroundColor(color)
bottomBar.setBackgroundColor(color)
activity.window.statusBarColor = color
}
bottomSheetBinding.bottomSheetParent.setCardBackgroundColor(color)
}
}
bottomSheetParent.setCardBackgroundColor(color)
}
bottomSheetView.post {
bottomSheetDialog.behavior.state = BottomSheetBehavior.STATE_EXPANDED
}
}
// opens existing item
setUpNote()
}
@SuppressLint("SetTextI18n")
private fun setUpNote() {
val note = args.note
val title = binding.etTitle
val content = binding.etNoteContent
val lastEdited = binding.lastEdited
if (note == null){
binding.lastEdited.text =
"${getString(R.string.edited_on)}: ${SimpleDateFormat.getDateInstance().format(Date())}"
}
if (note!=null){
title.setText(note.title)
content.renderMD(note.content)
lastEdited.text = "${getString(R.string.edited_on)}: ${note.date}"
color = note.color
binding.apply {
job.launch {
delay(10)
noteContentFragParent.setBackgroundColor(color)
}
toolbarFragNoteContent.setBackgroundColor(color)
bottomBar.setBackgroundColor(color)
}
activity?.window?.statusBarColor = note.color
}
}
private fun saveNote() {
if (binding.etNoteContent.text.toString().isEmpty() || binding.etTitle.text.toString()
.isEmpty()
) {
Toast.makeText(activity, "یادداشت نباید خالی باشد", Toast.LENGTH_SHORT).show()
} else {
note = args.note
when (note) {
null -> {
noteActivityViewModel.addNote(
Note(
0,
title = binding.etTitle.text.toString(),
content = binding.etNoteContent.getMD(),
color = color,
date = currentDate
)
)
result = "ذخیره شد"
setFragmentResult(
"key",
bundleOf("bundleKey" to result)
)
navController.navigate(SaveOrUpdateFragmentDirections.actionSaveOrUpdateFragmentToNoteFragment())
}
else -> {
updateNote()
navController.popBackStack()
}
}
}
}
private fun updateNote() {
if (note != null) {
noteActivityViewModel.updateNote(
Note(
id = note!!.id,
content = binding.etNoteContent.getMD(),
title = binding.etTitle.text.toString(),
date = currentDate,
color = color
)
)
}
}
}
型
我将感激任何帮助。
1条答案
按热度按时间tnkciper1#
你的问题在于你的
diffUtil
类。简短回答:
将
areContentsTheSame
更改为:字符串
详细回答:
DiffUtil
有两种方法:areItemsTheSame
:当比较两个列表中的项目时,首先调用这个函数,这样它就知道两个项目是否相同(然后检查更改).所以在这里你需要检查它们的唯一标识符,比如id
,你做得对。areContentsTheSame
:这被称为后前一个返回真,它希望你比较这些类的内容,看看他们是否改变。第二个是你做得对的,正如我提到的,只有当前面的函数返回true时才调用它,因为你正在检查id,那么id肯定会是相同的(这也是你在这里检查的条件),所以item不会改变。
在这里,你需要检查类的Content是否发生了变化,其中两种最常用的方法是hashCode比较
oldItem.hashCode() == newItem.hashCode()
或相等性比较oldItem == newItem
。虽然如果你有一些数据在你的类中发生了变化,但没有显示在ui中(你有很多字段),我建议做一个更详细的检查:型
请注意,使用自定义相等检查,意味着如果您添加与数据类相关的UI,则需要在此处添加,因此UI会更新