Элемент списка RecyclerView не отображается при внесении записей в базу данных Room - PullRequest
2 голосов
/ 13 июня 2019

Я пытаюсь переписать существующее приложение в Kotlin с целью изучения и привыкания к языку.Приложение позволяет пользователю вводить и изменять записи, и каждая запись размещается в списке RecyclerView с пользовательским элементом списка.Хотя записи успешно добавлены в базу данных (подтверждая это с помощью Toast сообщений), для указанной записи отсутствует элемент списка.

Это мой адаптер:

class EntryAdapter : androidx.recyclerview.widget.ListAdapter<Entry, EntryAdapter.ViewHolder>(DIFF_CALLBACK){
    private var listener: OnItemLongClickListener? = null

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
        val view = LayoutInflater.from(parent.context).inflate(R.layout.recyclerview_item, parent, false)
        return ViewHolder(view)
    }

    override fun onBindViewHolder(holder: ViewHolder, position: Int){
        val currentEntry = getItem(position)
        holder.hint.text = currentEntry.hint
        holder.username.text = currentEntry.username
        holder.password.text = currentEntry.password
    }

    fun getEntryAt(position: Int): Entry{return getItem(position)}

    inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView){
        val username: TextView = itemView.findViewById(R.id.username_display)
        val password: TextView = itemView.findViewById(R.id.password_display)
        val hint: TextView = itemView.findViewById(R.id.hint_display)

        init {
            itemView.setOnLongClickListener{
                val position = adapterPosition
                if (listener != null && position != RecyclerView.NO_POSITION){listener!!.onItemLongClick(getItem(position))}
                true
            }
        }
    }

    interface OnItemLongClickListener{fun onItemLongClick(entry: Entry)}

    fun setOnItemLongClickListener(listener: OnItemLongClickListener){this.listener = listener}

    companion object{

        private val DIFF_CALLBACK = object : DiffUtil.ItemCallback<Entry>(){
            override fun areItemsTheSame(oldItem: Entry, newItem: Entry): Boolean{return oldItem.id == newItem.id}
            override fun areContentsTheSame(oldItem: Entry, newItem: Entry): Boolean{return oldItem.username == newItem.username && oldItem.hint == newItem.hint && oldItem.password == newItem.password}
        }
    }
}

Это моя AddEditEntry.kt активность.Это работает так, что, когда пользователь хочет сделать запись, он / она нажимает кнопку FAB, которая вызывает это действие.Это действие, когда пользователь вводит запись и добавляет ее в базу данных (и, соответственно, RecyclerView), нажимая кнопку saveEntry:

class AddEditEntryActivity : AppCompatActivity() {

    private var usernameEditText: EditText? = null
    private var passwordEditText: EditText? = null
    private var hintEditText: EditText? = null
    private var passwordABCD: CheckBox? = null
    private var passwordabcd: CheckBox? = null
    private var password0123: CheckBox? = null
    private var passwordSymbols: CheckBox? = null
    private var radio4: RadioButton? = null
    private var radio8: RadioButton? = null
    private var radio12: RadioButton? = null
    private var radio16: RadioButton? = null

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

        usernameEditText = findViewById(R.id.username_field)
        passwordEditText = findViewById(R.id.password_field)
        hintEditText = findViewById(R.id.hint_field)

        passwordABCD = findViewById(R.id.upp_checkbox)
        passwordabcd = findViewById(R.id.low_checkbox)
        password0123 = findViewById(R.id.num_checkbox)
        passwordSymbols = findViewById(R.id.sym_checkbox)

        radio4 = findViewById(R.id.four)
        radio8 = findViewById(R.id.eight)
        radio12 = findViewById(R.id.twelve)
        radio16 = findViewById(R.id.sixteen)

        val generatePassword = findViewById<Button>(R.id.btn_password_generate)
        val saveEntry = findViewById<Button>(R.id.btn_save)

        val intent = intent

        if (intent.hasExtra(EXTRA_ID)) {
            title = getString(R.string.edit_entry)
            saveEntry.setText(R.string.update_entry)

            usernameEditText!!.setText(getIntent().getStringExtra(EXTRA_USERNAME))
            passwordEditText!!.setText(getIntent().getStringExtra(EXTRA_PASSWORD))
            hintEditText!!.setText(getIntent().getStringExtra(EXTRA_HINT))
        }

        else {title = "Add Entry"}

        Objects.requireNonNull<ActionBar>(supportActionBar).setHomeAsUpIndicator(R.drawable.ic_close_white_24dp)

        generatePassword.setOnClickListener { passwordEditText!!.setText(generatedPassword()) }

        saveEntry.setOnClickListener {
            val data = Intent()
            data.putExtra(EXTRA_USERNAME, usernameEditText!!.text.toString())
            data.putExtra(EXTRA_HINT, hintEditText!!.text.toString())
            data.putExtra(EXTRA_PASSWORD, passwordEditText!!.text.toString())

            val id = getIntent().getIntExtra(EXTRA_ID, -1)

            if (id != -1) {data.putExtra(EXTRA_ID, id)}

            setResult(Activity.RESULT_OK, data)
            finish()

            Toast.makeText(this, "data.putExtra() from AddEditEntryActivity", Toast.LENGTH_SHORT).show()
            Toast.makeText(this, usernameEditText!!.text.toString(), Toast.LENGTH_SHORT).show()
            Toast.makeText(this, hintEditText!!.text.toString(), Toast.LENGTH_SHORT).show()
            Toast.makeText(this, passwordEditText!!.text.toString(), Toast.LENGTH_SHORT).show()
        }
    }

    private fun generatedPassword(): String? {

        var length = 0
        val generatedString = StringBuilder()
        val rand = Random()

        val capitalLetters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
        val lowercaseLetters = "abcdefghijklmnopqrstuvwxyz"
        val numbers = "0123456789"
        val characters = "!@#$%^&*()"

        if (radio4!!.isChecked) {length = 4}
        else if (radio8!!.isChecked) {length = 8}
        else if (radio12!!.isChecked) {length = 12}
        else if (radio16!!.isChecked) {length = 16}

        var totalCharacters = ""

        if (passwordABCD!!.isChecked) {totalCharacters += capitalLetters}

        if (passwordabcd!!.isChecked) {totalCharacters += lowercaseLetters}

        if (password0123!!.isChecked) {totalCharacters += numbers}

        if (passwordSymbols!!.isChecked) {totalCharacters += characters}

        if (!totalCharacters.trim { it <= ' ' }.isEmpty() && length > 0) {
            for (i in 0 until length) {generatedString.append(totalCharacters[rand.nextInt(totalCharacters.length)])}
            return generatedString.toString()
        }

        else {Toast.makeText(this, "Not a valid password!", Toast.LENGTH_SHORT).show()}

        return null
    }

    companion object {

        val EXTRA_USERNAME = "com.ozbek.cryptpass.EXTRA_USERNAME"
        val EXTRA_HINT = "com.ozbek.cryptpass.EXTRA_HINT"
        val EXTRA_PASSWORD = "com.ozbek.cryptpass.EXTRA_PASSWORD"
        val EXTRA_ID = "com.ozbek.cryptpass.EXTRA_ID"
    }
}

И это файл MainActivity.ktгде пользователь вводит новые записи.Первый блок if в onActivityResult() - это код, который извлекает записи из файла AddEditEntry.kt и добавляет его к классу сущностей:

class MainActivity : AppCompatActivity(), LifecycleOwner {
    private lateinit var recyclerView: RecyclerView
    internal lateinit var adapter: EntryAdapter
    private lateinit var floatingActionButton: FloatingActionButton
    private lateinit var layoutManager: RecyclerView.LayoutManager
    private lateinit var addEditEntryActivity: AddEditEntryActivity
    internal lateinit var entry: Entry
    private lateinit var viewModel: EntryViewModel

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

        val ctx = this.applicationContext

        val sentryDsn = "https://93f06d5090d646ac9443a3fc531fc5de@sentry.io/1454826:port/1?options"
        Sentry.init(sentryDsn, AndroidSentryClientFactory(ctx))
        Sentry.init(AndroidSentryClientFactory(ctx))

        viewModel = ViewModelProviders.of(this).get(EntryViewModel::class.java)
        viewModel.allEntries.observe(this, Observer { entries -> adapter.submitList(entries) })

        adapter = EntryAdapter()
        layoutManager = LinearLayoutManager(this)

        recyclerView = findViewById<RecyclerView>(R.id.userpass_recyclerview).apply{
            layoutManager = layoutManager
            adapter = adapter
        }

        addEditEntryActivity = AddEditEntryActivity()
        entry = Entry()

        floatingActionButton = findViewById<FloatingActionButton>(R.id.generate_fab)

        floatingActionButton.setOnClickListener {
            val intent = Intent(this@MainActivity, AddEditEntryActivity::class.java)
            Toast.makeText(this, "AddEditActivity started", Toast.LENGTH_SHORT).show()
            startActivityForResult(intent, ADD_ENTRY_REQUEST)
        }

        ItemTouchHelper(object : ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.LEFT or ItemTouchHelper.RIGHT) {
            override fun onMove(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder, target: RecyclerView.ViewHolder): Boolean {return false}
            override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {viewModel.delete(adapter.getEntryAt(viewHolder.adapterPosition))}

        }).attachToRecyclerView(recyclerView)

        adapter.setOnItemLongClickListener (object: EntryAdapter.OnItemLongClickListener {
            override fun onItemLongClick(entry: Entry){
                val intent = Intent(this@MainActivity, AddEditEntryActivity::class.java)

                intent.putExtra(AddEditEntryActivity.EXTRA_ID, entry.id)
                intent.putExtra(AddEditEntryActivity.EXTRA_USERNAME, entry.username)
                intent.putExtra(AddEditEntryActivity.EXTRA_HINT, entry.hint)
                intent.putExtra(AddEditEntryActivity.EXTRA_PASSWORD, entry.password)
                startActivityForResult(intent, EDIT_ENTRY_REQUEST)
            }
        })
    }

    override fun onCreateOptionsMenu(menu: Menu): Boolean {
        menuInflater.inflate(R.menu.menu, menu)
        return true
    }

    override fun onOptionsItemSelected(item: MenuItem): Boolean {
        val itemId = item.itemId

        if (itemId == R.id.delete_all) {viewModel.deleteAll()}

        return super.onOptionsItemSelected(item)
    }

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

        if (requestCode == ADD_ENTRY_REQUEST && resultCode == Activity.RESULT_OK) {
            Toast.makeText(this, data?.getStringExtra(AddEditEntryActivity.EXTRA_USERNAME), Toast.LENGTH_SHORT).show()
            Toast.makeText(this, data?.getStringExtra(AddEditEntryActivity.EXTRA_PASSWORD), Toast.LENGTH_SHORT).show()
            Toast.makeText(this, data?.getStringExtra(AddEditEntryActivity.EXTRA_HINT), Toast.LENGTH_SHORT).show()

            val username = Objects.requireNonNull<Intent>(data).getStringExtra(AddEditEntryActivity.EXTRA_USERNAME)
            val password = Objects.requireNonNull<Intent>(data).getStringExtra(AddEditEntryActivity.EXTRA_PASSWORD)
            val hint = Objects.requireNonNull<Intent>(data).getStringExtra(AddEditEntryActivity.EXTRA_HINT)

            val entry = Entry(username, hint, password)
            viewModel.insert(entry)

            Toast.makeText(this, "Entry added!", Toast.LENGTH_SHORT).show()

        } else if (requestCode == EDIT_ENTRY_REQUEST && resultCode == Activity.RESULT_OK) {
            Toast.makeText(this, data!!.getIntExtra(AddEditEntryActivity.EXTRA_ID, -1), Toast.LENGTH_SHORT).show()
            Toast.makeText(this, data.getStringExtra(AddEditEntryActivity.EXTRA_USERNAME), Toast.LENGTH_SHORT).show()
            Toast.makeText(this, data.getStringExtra(AddEditEntryActivity.EXTRA_PASSWORD), Toast.LENGTH_SHORT).show()
            Toast.makeText(this, data.getStringExtra(AddEditEntryActivity.EXTRA_HINT), Toast.LENGTH_SHORT).show()

            val id = Objects.requireNonNull<Intent>(data).getIntExtra(AddEditEntryActivity.EXTRA_ID, -1)

            if (id == -1) {
                Toast.makeText(this, "Something went wrong", Toast.LENGTH_SHORT).show()
                return
            }

            val username = Objects.requireNonNull<Intent>(data).getStringExtra(AddEditEntryActivity.EXTRA_USERNAME)
            val password = Objects.requireNonNull<Intent>(data).getStringExtra(AddEditEntryActivity.EXTRA_PASSWORD)
            val hint = Objects.requireNonNull<Intent>(data).getStringExtra(AddEditEntryActivity.EXTRA_HINT)

            val entry = Entry(username, hint, password, id)
            entry.id = id
            viewModel.update(entry)

            Toast.makeText(this, "Entry updated", Toast.LENGTH_SHORT).show()

        } else {Toast.makeText(this, "Entry not added!", Toast.LENGTH_SHORT).show()}
    }

    companion object {
        const val ADD_ENTRY_REQUEST = 1
        const val EDIT_ENTRY_REQUEST = 2
    }
}

Я могу добавить больше кода для каждого запроса. Это - полный репозиторий Github.

1 Ответ

1 голос
/ 13 июня 2019

Вот проблема:

    recyclerView = findViewById<RecyclerView>(R.id.userpass_recyclerview).apply{
        layoutManager = layoutManager
        adapter = adapter
    }

Ищите, что происходит, но кажется, что вы инициализируете их сами.Не делай этого.Рекомендуется хранить разные имена переменных.Рефакторинг объектов следующим образом:

internal lateinit var entryAdapter: EntryAdapter
private lateinit var linearLayoutManager: RecyclerView.LayoutManager

И внесите следующие изменения в ваш onCreate():

    recyclerView = findViewById<RecyclerView>(R.id.userpass_recyclerview).apply{
        adapter = entryAdapter
        layoutManager = linearLayoutManager
    }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...