【问题标题】:Recycler view not updating properly回收站视图未正确更新
【发布时间】:2018-08-26 16:56:18
【问题描述】:

我已经多次问过这个类似的问题,我试图找出解决方案已经超过 2 周了。是的,我知道有多个类似的问题,但我问的原因是因为堆栈溢出的解决方案都不起作用。我是 Android 开发的初学者,因此我请你请帮我解决这个问题。我几乎放弃了我的项目。

应用的工作原理

应用有两个活动。主要活动用于使用从 SQ Lite DB 加载的回收器视图以卡片视图的形式显示数据。用户可以点击一张卡片,点击后将启动一个新活动(参考活动)。点击卡片的数据在第二个活动中加载。在这里用户可以执行UPDATEDELETE功能。

问题

问题是我必须重新启动我的应用程序才能看到注释中的更改。例如,如果我在第二个活动中创建一个便笺并返回到主活动,则该 CREATED 便笺在重新启动应用程序之前可见。更新或删除笔记时也是如此。仅在重新启动应用程序时才会发生更改。

到目前为止我所尝试的...

  • 在 MAIN 活动的 onRestart() 中调用 notifyDataSetChanged()。

  • 在 onRestart() 中调用了首先加载回收站视图项的整个加载

  • 尝试使用新数据更新适配器

----- 代码 -----

主要活动

class MainActivity : AppCompatActivity() {

var dbHandler: PediaDatabase = PediaDatabase(this)
var adapter: PediaAdapter? = null
var newAdapter: PediaAdapter? = null
var layoutManager: RecyclerView.LayoutManager? = null
var list: ArrayList<UserNotes>? = ArrayList()
var listItems: ArrayList<UserNotes>? = ArrayList()
var updatedList: ArrayList<UserNotes> = ArrayList()
var tempList: ArrayList<UserNotes>? = null
var myPrefs: SharedPreferences? = null
var first_run: Boolean = true
var isCreated: Boolean = false
var isUpdated: Boolean = false
var isDeleted: Boolean = false
var isReturning: Boolean = false

var updatedTitle: String? = null
var updatedText: String? = null

val PREFS_NAME: String = "MYPREFS"
val REQUEST_CODE: Int = 1


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

     showOneTimeMessage()
     invalidateOptionsMenu()

    if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
    {
        window.navigationBarColor = Color.BLACK
    }

}

override fun onRestart() {
    super.onRestart()

    if(isUpdated)
    {
        recyclerViewID.recycledViewPool.clear()
        var test = listItems!![adapPos]
        test.noteTitle = updatedTitle
        test.noteText = updatedText
        listItems!!.set(adapPos, test)
        adapter!!.notifyItemChanged(adapPos)

        isUpdated = false
    }
}


override fun onStart() {
    super.onStart()

    if(isReturning)
    {
        adapter!!.updateResults(this.listItems!!)
        adapter!!.notifyDataSetChanged()
    }

    adapter = PediaAdapter(this, listItems!!)
    layoutManager = LinearLayoutManager(this)

    recyclerViewID.adapter = adapter
    recyclerViewID.layoutManager = layoutManager


    list = dbHandler.readAllNotes()

    for(reader in list!!.iterator())
    {
        var note = UserNotes()

        note.noteTitle = reader.noteTitle
        note.noteText = reader.noteText
        note.noteID = reader.noteID
        note.noteDate = reader.noteDate

        listItems!!.add(note)
    }

    adapter!!.notifyDataSetChanged()


    if(dbHandler.totalNotes() == 0) {
        recyclerViewID.visibility = View.GONE
    }
    else{
        recyclerViewID.visibility = View.VISIBLE
        showWhenEmptyID.visibility = View.GONE
    }
    recyclerViewID.hasFixedSize()
}





override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
    super.onActivityResult(requestCode, resultCode, data)

    if(requestCode == REQUEST_CODE)
        if(resultCode == Activity.RESULT_OK)
        {
            //isCreated = data!!.extras!!.getBoolean("isCreated")

            updatedTitle = data!!.extras.getString("updatedTitle")
            updatedText = data!!.extras.getString("updatedText")

            isReturning = data.extras!!.getBoolean("returningBack")
           // isUpdated = data.extras!!.getBoolean("isUpdated")
        }
}


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

    val item = menu!!.findItem(R.id.delete_note_menu)
    item.setVisible(false)
    return true
}

override fun onOptionsItemSelected(item: MenuItem?): Boolean {

    if(item!!.itemId == R.id.add_note_menu){

        isNewNote = true
        startActivity(Intent(this, ReferenceActivity::class.java))
    }

    if(item!!.itemId == R.id.delete_note_menu)
    {

        Toast.makeText(this,"DELETED", Toast.LENGTH_SHORT).show()
    }

    return super.onOptionsItemSelected(item)
}

private fun showOneTimeMessage()
{
    var data: SharedPreferences = getSharedPreferences(PREFS_NAME, 0)
    if(data.contains("isShown"))
    {
        first_run = data.getBoolean("isShown", true)
    }


    Log.d("FIRST_RUN", first_run.toString())

    if(first_run)
    {
        val oneTimeMsg = SweetAlertDialog(this)
        oneTimeMsg.setTitleText("Hey there!")
        oneTimeMsg.setContentText("Thank you for downloading! Please don`t forget to rate our app :)").show()

        oneTimeMsg.setConfirmClickListener(object : SweetAlertDialog.OnSweetClickListener
        {

            override fun onClick(sweetAlertDialog: SweetAlertDialog?)
            {
                oneTimeMsg.dismissWithAnimation()
            }
        }).show()


        myPrefs = getSharedPreferences(PREFS_NAME, 0)
        var editor: SharedPreferences.Editor = (myPrefs as SharedPreferences).edit()
        editor.putBoolean("isShown", false)
        editor.commit()

    }
}

参考活动

class ReferenceActivity : AppCompatActivity() {

var dbHandler: PediaDatabase? = null
var note = UserNotes()

var noteExisted: Boolean = false
var cardAdapterPos: Int? = null

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

    getSupportActionBar()!!.setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM)
     getSupportActionBar()!!.setCustomView(R.layout.custom_toolbar)
      val dateTxtView = findViewById<View>(resources.getIdentifier("action_bar_title", "id", packageName)) as TextView


    overridePendingTransition(R.anim.slide_in, R.anim.slide_out)

    if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
        window.navigationBarColor = Color.BLACK


    dbHandler = PediaDatabase(this)
    val data = intent
        if(isNewNote != true/*isNewNote.extras.getBoolean("isNewNote") != true*/)
        {
            getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN)

            if(data != null)
            {
                noteExisted = true

                this.cardAdapterPos = data.extras.getInt("cardPosition")
                cardID = data.extras.getInt("cardID")


                existingNote = dbHandler!!.readNote(cardID)

                refTitleID.setText(existingNote.noteTitle, TextView.BufferType.EDITABLE)
                refTextID.setText(existingNote.noteText, TextView.BufferType.EDITABLE)
                dateTxtView.text = existingNote.noteDate.toString()
            }
        }else{
            dateTxtView.text = "New note"
        }
}

override fun onStop() {
    super.onStop()


    var title: String = refTitleID.text.toString().trim()
    var text: String = refTextID.text.toString().trim()

    if(existingNote.noteText == text && existingNote.noteTitle == title)
        finish()

    if(noteExisted)
    {
        if(TextUtils.isEmpty(title))
            title = "No title"


        existingNote.noteTitle = title
        existingNote.noteText = text
        existingNote.noteDate = System.currentTimeMillis().toString() //TODO TRY THIS


        dbHandler!!.updateNote(existingNote)

        var dataCreate = this.intent
        dataCreate.putExtra("isUpdated", true)
        dataCreate.putExtra("updatedTitle", title)
        dataCreate.putExtra("updatedText",text)
        dataCreate.putExtra("returningBack", true)
        setResult(Activity.RESULT_OK, dataCreate)


        finish()
    }
    else
    {
        if(TextUtils.isEmpty(title) && TextUtils.isEmpty(text))
        {
            finish()
        }
        else
        {
            if(TextUtils.isEmpty(title))
                title = "No title"

            note.noteTitle = title
            note.noteText = text
            note.noteDate = System.currentTimeMillis().toString()
           // note.noteID =

            dbHandler!!.createNote(note)

            var dataCreate = this.intent
            dataCreate.putExtra("isCreated", true)
            dataCreate.putExtra("returningBack", true)
            setResult(Activity.RESULT_OK, dataCreate)

            finish()
        }
    }
}


override fun onCreateOptionsMenu(menu: Menu?): Boolean {

    menuInflater.inflate(R.menu.top_menu, menu)
    val addItem: MenuItem = menu!!.findItem(R.id.add_note_menu)
    val delItem:MenuItem = menu.findItem(R.id.delete_note_menu)


    addItem.setVisible(false)
    delItem.setVisible(false)

    if(noteExisted)
        delItem.setVisible(true)

    return true
}

override fun onOptionsItemSelected(item: MenuItem?): Boolean {

    if(item!!.itemId == R.id.delete_note_menu)
    {
        val dialogMsg = SweetAlertDialog(this, SweetAlertDialog.WARNING_TYPE)
        dialogMsg.setTitleText("Are you sure?")
        dialogMsg.setContentText("You won`t be able to recover this note!")
        dialogMsg.setConfirmText("Yes, delete it!")

        dialogMsg.setConfirmClickListener(object: SweetAlertDialog.OnSweetClickListener {

            override fun onClick(sweetAlertDialog: SweetAlertDialog?) {
                dialogMsg.dismissWithAnimation()


                dbHandler!!.deleteNote(cardID)


                val successMsg = SweetAlertDialog(sweetAlertDialog!!.context, SweetAlertDialog.SUCCESS_TYPE)
                successMsg.setTitleText("Note deleted!")
                successMsg.setContentText("So long,note").show()
                successMsg.setCancelable(false)

                //TODO Disable 'OK' button on successMsg dialogbox

                Handler().postDelayed({
                    successMsg.dismissWithAnimation()
                    finish()
                }, 1200)

            }
        }).show()

    }
    return super.onOptionsItemSelected(item)
}

适配器

class PediaAdapter(private val context: Context,
               private var noteslist: ArrayList<UserNotes>): RecyclerView.Adapter<PediaAdapter.ViewHolder>() {

override fun onCreateViewHolder(p0: ViewGroup, p1: Int): ViewHolder
{
    val view = LayoutInflater.from(context).inflate(R.layout.list_row,p0,false)

    return ViewHolder(view, noteslist)
}

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

override fun onBindViewHolder(p0: ViewHolder, p1: Int)
{
    p0.bindItems(noteslist[p1])
}

inner class ViewHolder(itemView: View, list: ArrayList<UserNotes>): RecyclerView.ViewHolder(itemView), View.OnClickListener
{
    private var noteTitle = itemView.findViewById(R.id.listTitleID) as TextView
    private var noteText = itemView.findViewById(R.id.listTextID) as TextView

    var mList = list


    init
    {
        itemView.setOnClickListener(this)
    }

    fun bindItems(note: UserNotes)
    {
        //var id = note.noteID
        noteTitle.text = note.noteTitle
        noteText.text = note.noteText
    }

    override fun onClick(v: View?)
    {

        var mPosition: Int =  adapterPosition //For forwarding position to ref activity
        var note = mList[mPosition]
        adapPos = adapterPosition


        var cardID = Intent(itemView.context, ReferenceActivity::class.java)
        cardID.putExtra("cardPosition", mPosition)
        cardID.putExtra("cardID", note.noteID) //TODO THIS IS FETCHING NOTE_ID VALUES FROM DB

        Toast.makeText(itemView.context, "card id = " + note.noteID, Toast.LENGTH_SHORT).show()

        itemView.context.startActivity(cardID)
    }

}

fun updateResults(items: ArrayList<UserNotes>)
{
    this.noteslist = items
}

是的,我知道通过别人的代码很难。我试图修复它很多次,整天坐着试图弄清楚,但仍然没有运气。我请求你帮我解决这个问题。我不在乎你是否使用 Java,我只需要一种方法来修复它。

【问题讨论】:

  • 您在 MainActivity 中覆盖 onActivityResult(),但只有在您首先使用 startActivityForResult() 时才会调用它。我找不到任何与startActivityForResult() 相关的行,所以这可能是您的代码无法按预期工作的原因之一
  • @0X0nosugar 问题是,即使我改变了代码的逻辑,比如说,我在 onRestart() 中调用 notifyDataSetChanged(),也没有任何反应。为什么?即使使用“糟糕”的解决方案仍然没有任何效果。
  • 我会尝试通过复制您的代码并在我自己的机器上运行它来找出问题所在,但不幸的是缺少一些类,所以这不是一个选择。 onStart() 和 onRestart() 中的逻辑确实 看起来有点复杂(例如,如果 isReturning == true,你对旧的 Adapter 做一些事情,但几行之后你完全丢弃它并且只使用一个新的适配器实例),所以我真的很想使用我的调试器来找出发生了什么
  • @0X0nosugar 好的,我正在与您分享我的项目文件。您可以下载它并在您的机器上运行它。这是谷歌驱动器的链接:drive.google.com/open?id=1hsRLOJYYnBX7OlvLc7eY6VYYBBSYSpNZ
  • 看起来分享你的代码是个好主意——@sandip 终于可以帮助你了。但是请保持您的问题不变,甚至添加缺失的部分 - 未来的读者可能无法再在谷歌驱动器上找到您的代码,我们总是尝试不仅为 OP 提供问题和答案,而且为所有人提供问题和答案那些将来可能会遇到类似情况的人。

标签: android sqlite android-recyclerview kotlin


【解决方案1】:

像这样在AndroidManifest.xml 文件中声明您的 MainActivity。

android:launchMode="singleTask"

在完成“ReferenceActivity”(即调用 finish())之前,对您的“MainActivity”进行 Intent 调用。此外,覆盖“MainActivity”中的“onNewIntent()”方法。

@Override
protected void onNewIntent(Intent intent)

在“onNewIntent()”方法中,再次加载数据,就像在“onStart()”和“onRestart()”中所做的那样。

解释,我们所做的是在 Activity Stack 中添加我们的“MainActivity”的单个引用,因此每当对“MainActivity”进行意图调用而不是创建多个引用时,它只需创建一个引用并每次调用 newIntentMethod .

希望这能解决您的问题。

【讨论】:

  • 在完成创建/更新或删除笔记后,我尝试在参考活动上调用 startActivity(intent)。它只是不断堆积主要活动,这是一件坏事。
  • 你在AndroidManifest.xml文件中声明android:launchMode="singleTask"吗?
  • 我试过了,主要活动还在堆积。最重要的是,当再次调用主要活动时,适配器会丢失对卡片视图数据的引用,因此当我单击新创建的笔记或现有笔记时,它只会打开“新笔记”选项卡。数据已加载。我已经提供了我的项目的源代码。你能检查一下吗?
  • 嘿!在你的帮助下,我几乎把它修好了!现在有一个问题,例如当我创建一个新笔记时,回到主要活动并查看新创建的笔记。但是当我点击它时,应用程序认为我正在创建一个新笔记并且没有加载相应的数据。如何解决?
  • 嘿,我只是认为该解决方案会产生另一个问题。当应用程序暂停并通过再次单击启动器图标重新启动时,应用程序将重新启动。如何解决?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-12-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-10-21
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多