Kotlin - custom dialog in Android - android

I want to create a custom dialog in Kotlin. I looked through questions on this theme on Stack Overflow, but I could not find any useful information. How can I do it?

You can use below code for a custom Dialog. It's my working code.
private fun showDialog(title: String) {
val dialog = Dialog(activity)
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE)
dialog.setCancelable(false)
dialog.setContentView(R.layout.custom_layout)
val body = dialog.findViewById(R.id.body) as TextView
body.text = title
val yesBtn = dialog.findViewById(R.id.yesBtn) as Button
val noBtn = dialog.findViewById(R.id.noBtn) as Button
yesBtn.setOnClickListener {
dialog.dismiss()
}
noBtn.setOnClickListener {
dialog.dismiss()
}
dialog.show()
}

custom_dialog.xml
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#drawable/fitsdk_white_rectangle"
android:orientation="vertical">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="15dp"
android:layout_marginTop="30dp"
android:layout_marginRight="15dp"
android:layout_marginBottom="30dp"
android:orientation="vertical">
<TextView
android:id="#+id/tvTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/error_timeout_title"
android:textColor="#color/black" />
<TextView
android:id="#+id/tvBody"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="15dp"
android:text="#string/error_timeout_body"
android:textColor="#color/black" />
<Button
android:id="#+id/btn_yes"
android:layout_width="100dp"
android:layout_height="30dp"
android:background="#android:color/white"
android:clickable="true"
android:text="Yes"
android:textColor="#5DBCD2"
android:textStyle="bold" />
</LinearLayout>
</FrameLayout>
CustomDialogClass.kt
class CustomDialogClass(context: Context) : Dialog(context) {
init {
setCancelable(false)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
requestWindowFeature(Window.FEATURE_NO_TITLE)
setContentView(R.layout.custom_dialog)
}
}

Below my solution as a kind of "message box".
I have not implemented an "OK" button. The message box should close after clicking on it.
Here the layout element (*/layout/message_box.xml)
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="300dp"
android:orientation="vertical">
<TextView
android:id="#+id/message_box_header"
android:layout_width="match_parent"
android:layout_height="30dp"
android:textAlignment="center"
android:textSize="20sp" />
<TextView
android:id="#+id/message_box_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAlignment="center"
android:textSize="20sp" />
</LinearLayout>
</LinearLayout>
This function I've implement in a Fragment class. It is written in Kotlin.
fun showMessageBox(text: String){
//Inflate the dialog as custom view
val messageBoxView = LayoutInflater.from(activity).inflate(R.layout.message_box, null)
//AlertDialogBuilder
val messageBoxBuilder = AlertDialog.Builder(activity).setView(messageBoxView)
//setting text values
messageBoxView.message_box_header.text = "This is message header"
messageBoxView.message_box_content.text = "This is message content"
//show dialog
val messageBoxInstance = messageBoxBuilder.show()
//set Listener
messageBoxView.setOnClickListener(){
//close dialog
messageBoxInstance.dismiss()
}
}

you have a clean codes on an extension function of context in kotlin and use it on
all of your codes
fun Context.showDialog(
title: String,
description: String,
titleOfPositiveButton: String? = null,
titleOfNegativeButton: String? = null,
positiveButtonFunction: (() -> Unit)? = null,
negativeButtonFunction: (() -> Unit)? = null
) {
val dialog = Dialog(this, R.style.Theme_Dialog)
dialog.window?.requestFeature(Window.FEATURE_NO_TITLE) // if you have blue line on top of your dialog, you need use this code
dialog.window?.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
dialog.setCancelable(false)
dialog.setContentView(R.layout.dialog_custom_layout)
val dialogTitle = dialog.findViewById(R.id.title) as TextView
val dialogDescription = dialog.findViewById(R.id.description) as TextView
val dialogPositiveButton = dialog.findViewById(R.id.positiveButton) as TextView
val dialogNegativeButton = dialog.findViewById(R.id.negativeButton) as TextView
dialogTitle.text = title
dialogDescription.text = description
titleOfPositiveButton?.let { dialogPositiveButton.text = it } ?: dialogPositiveButton.makeGone()
titleOfNegativeButton?.let { dialogNegativeButton.text = it } ?: dialogNegativeButton.makeGone()
dialogPositiveButton.setOnClickListener {
positiveButtonFunction?.invoke()
dialog.dismiss()
}
dialogNegativeButton.setOnClickListener {
negativeButtonFunction?.invoke()
dialog.dismiss()
}
dialog.show()
}
and this is a sample of use this function
requireContext().showDialog(
title = "Your Title",
description = "Your Description",
titleOfPositiveButton = "yes",
titleOfNegativeButton = "No",
positiveButtonFunction = { // Run codes after click on positive button },
negativeButtonFunction = { // Run codes after click on negative button }
)
and you need to have style for constant with on design of your dialog
<style name="Theme_Dialog" parent="android:Theme.Holo.Dialog">
<item name="android:windowMinWidthMajor">90%</item>
<item name="android:windowMinWidthMinor">90%</item>
</style>

This is the way by which you can create your own dialog with custom layout.
val dialogBuilder = AlertDialog.Builder(context, R.style.AlertDialogTheme)
val inflater = this.layoutInflater
val dialogView = inflater.inflate(R.layout.layout_chat_type_selection, null)
dialogBuilder.setView(dialogView)
val radioGroupChat = dialogView.radio_group_chat
dialogView.radioButton_user_chat.isChecked = true
dialogBuilder.setPositiveButton(getString(R.string.ok_text), object : DialogInterface.OnClickListener {
override fun onClick(dialog: DialogInterface, id: Int) {
when (radioGroupChat.checkedRadioButtonId) {
R.id.radioButton_user_chat -> {
(activity as HomeActivity).replaceFragment(MySkippersFragment.getInstance(isFromChat = true))
}
R.id.radioButton_circle_chat -> {
(activity as HomeActivity).replaceFragment(PickCircleFragment.getInstance(
PickCircleFragment.NEW_CIRCLE_CHAT), true)
}
}
}
})
dialogBuilder.setNegativeButton(getString(R.string.cancel_text), object : DialogInterface.OnClickListener {
override fun onClick(dialog: DialogInterface?, which: Int) {
}
})
val alertDialog = dialogBuilder.create()
alertDialog.show()

Works fine. You can also customize it the way you want.
Main class:
class CustomAlertDialogOneButton( activity: Activity?,
private val alertOneButtonClickListener: OnAlertOneButtonClickListener):Dialog(activity!!) {
private var title = ""
private var text = ""
private var dialogId = -1
private var buttonName = ""
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.custom_alert_one_button_dialog)
setCancelable(false)
this.window?.setBackgroundDrawable(ColorDrawable(android.graphics.Color.TRANSPARENT))
viewsClickListenerInit()
}
override fun onStart() {
initDialog()
super.onStart()
}
private fun fillFields(title: String, text: String?, dialogId: Int, buttonName: String) {
clearDialog()
this.title = title
this.text = text ?: ""
this.dialogId = dialogId
this.buttonName = buttonName
}
private fun clearDialog() {
title = ""
text = ""
}
private fun initDialog() {
if (title.isNotBlank()) {
tvAlertTitle.text = title
}
if (text.isNotBlank()) {
tvAlertText.text = text
}
tvAlertButtonOk.text = buttonName
}
fun show(title: String, text: String?, dialogId: Int = -1, buttonName: String = ResourcesRepository.resources.getString(R.string.ok)) {
fillFields(title, text, dialogId, buttonName)
super.show()
}
private fun viewsClickListenerInit() {
tvAlertButtonOk.setOnClickListener {
alertOneButtonClickListener.okClickListener(dialogId)
dismiss()
}
}}
XML for it: name it likes - custom_alert_one_button_dialog.xml
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="280dp"
android:layout_height="145dp"
android:background="#color/colorWhite"
android:orientation="vertical">
<androidx.constraintlayout.widget.Guideline
android:id="#+id/center_vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_percent="0.5" />
<TextView
android:id="#+id/tvAlertTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingStart="24dp"
android:paddingTop="22dp"
android:textAlignment="center"
android:textColor="#color/colorDarkGrey"
android:textSize="20sp"
android:textStyle="bold"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="#+id/tvAlertText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingStart="24dp"
android:paddingTop="13dp"
android:paddingEnd="24dp"
android:paddingBottom="10dp"
android:textColor="#color/colorGrey"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#id/tvAlertTitle" />
<TextView
android:id="#+id/tvAlertButtonOk"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingStart="10dp"
android:paddingTop="10dp"
android:paddingEnd="34dp"
android:paddingBottom="18dp"
android:text="#string/ok"
android:textColor="#color/colorDarkGrey"
android:textSize="14sp"
android:textStyle="bold"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
Interface for button click listener:
interface OnAlertOneButtonClickListener {
fun okClickListener(dialogId: Int = -1)}
Implementation:
class SomeActivity : AppCompatActivity(), OnAlertOneButtonClickListener {
****
private var customDialogOneButton by lazy {
CustomAlertDialogOneButton(this, this)
}
****
customDialogOneButton.show(
title = "some title",
text = "some text",
dialogId = some int constant,
buttonName = "some button name"
)
****
override fun okClickListener(dialogId: Int) {
when (dialogId) {
some int constant -> {
// call method
}
}
}

My custom dialog xml file:
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#color/dialogWindowBackground">
<TextView
android:id="#+id/popup_dialog"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="16sp"
android:layout_marginTop="16dp"
android:layout_marginEnd="16sp"
android:layout_marginBottom="10dp"
android:text="#string/body"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
<LinearLayout
android:id="#+id/linearLayoutOpt"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="16sp"
android:layout_marginTop="16dp"
android:layout_marginEnd="16sp"
android:layout_marginBottom="10dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/popup_dialog">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="right"
android:orientation="horizontal">
<TextView
android:id="#+id/no_opt"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:gravity="center_vertical"
android:paddingLeft="8dp"
android:paddingTop="8dp"
android:paddingRight="8dp"
android:paddingBottom="18dp"
android:text="No"
android:textAllCaps="false"
android:textColor="#color/colorAccent" />
<Space
android:layout_width="32sp"
android:layout_height="12sp" />
<TextView
android:id="#+id/yes_opt"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:gravity="center_vertical"
android:paddingLeft="8dp"
android:paddingTop="8dp"
android:paddingRight="8dp"
android:paddingBottom="18dp"
android:text="Yes"
android:textAllCaps="false"
android:textColor="#color/colorAccent" />
</LinearLayout>
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
My Kotlin code:
private fun showDialog() {
val customDialog = Dialog(requireActivity())
customDialog.setContentView(R.layout.custom_dialog)
customDialog.window?.setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
val yesBtn = customDialog.findViewById(R.id.yes_opt) as TextView
val noBtn = customDialog.findViewById(R.id.no_opt) as TextView
yesBtn.setOnClickListener {
//Do something here
customDialog.dismiss()
}
noBtn.setOnClickListener {
customDialog.dismiss()
}
customDialog.show()
}

If someone wants to show 2 buttons on dialog ( GENERIC SOLUTION ) KOTLIN
fun createCustomTwoButtonDialog(
msg: String, context: Context?
, positiveButtonText: String, negativeButtonText: String,
isCancellable: Boolean,
dialogListener: DialogListener
) {
context?.let { context ->
val builder =
AlertDialog.Builder(context)
builder.setTitle("Your desired title")
builder.setMessage(msg)
builder.setCancelable(isCancellable)
builder.setPositiveButton(positiveButtonText) { dialogInterface: DialogInterface?, i: Int ->
dialogListener.onPositiveClick()
dialogInterface?.dismiss()
}
builder.setNegativeButton(negativeButtonText)
{ dialogInterface: DialogInterface?, i: Int ->
dialogListener.onNegativeClick()
dialogInterface?.dismiss()
}
val alertDialog = builder.create()
alertDialog.show()
}
}
DialogListener is interface with 2 methods onNegativeClick() and onPositiveClick()

I created this Kotlin Class :
class AnimDialog(private val context: Context) {
private val dialog = Dialog(context)
fun test(s: String) {
Log.i("TAG", "test: $s")
}
init{
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE)
dialog.window?.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE)
dialog.window?.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
}
fun one(headerImage :Int?=null,
description: String,
titleOfPositiveButton: String? = null,
titleOfNegativeButton: String? = null,
positiveButtonFunction: (() -> Unit)? = null,
negativeButtonFunction: (() -> Unit)? = null
) :Dialog{
dialog.setCancelable(false)
dialog.setContentView(R.layout.dialog_one)
val dialogHeaderImage=dialog.findViewById(R.id.imageHead_dia) as ImageView
val dialogDescription = dialog.findViewById(R.id.description) as TextView
val dialogPositiveButton = dialog.findViewById(R.id.positiveButton) as Button
val dialogNegativeButton = dialog.findViewById(R.id.negativeButton) as Button
headerImage?.let { dialogHeaderImage.setImageResource(it) }
dialogHeaderImage.
startAnimation(
AnimationUtils.loadAnimation(
context,
R.anim.bounce
)
)
dialogDescription.text = description
titleOfPositiveButton?.let { dialogPositiveButton.text = it } ?: dialogPositiveButton.text
titleOfNegativeButton?.let { dialogNegativeButton.text = it } ?: dialogNegativeButton.text
dialogPositiveButton.setOnClickListener {
positiveButtonFunction?.invoke()
dialog.dismiss()
}
dialogNegativeButton.setOnClickListener {
negativeButtonFunction?.invoke()
dialog.dismiss()
}
return dialog
}
Where you must define :
1- Layout <dialog_one> include positive btn, negative btn, image view, text view
2- Animation <bounce> if you would like add anim to the header image
Now in Activity:
val animDialog = AnimDialog(this)
animDialog.one(
headerImage = android.R.drawable.ic_delete,
description = "Sometimes we looking for new dialog to fill better \n ",
titleOfPositiveButton = "Accept it",
titleOfNegativeButton = "Not now",
positiveButtonFunction = {
animDialog.test("OK")
},
negativeButtonFunction = {
animDialog.test("NO")
}).show()

Related

Create a popup menu with edit/delete functions using recycler view

So I want to make a function which opens a popup menu using Recycler view, I've got the card and icons ready but im not sure how to implement into my
StudentAdapter.kt class.
Im new to Kotlin so popup windows are new to me.
I have the code to edit/delete but first of all how do I get the popup menu to work in my recyclerview?
card_items_rec (row for recyclerview)
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#color/white"
android:padding="1dp"
android:layout_margin="1dp"
android:weightSum="1">
<TextView
android:id="#+id/tvId"
android:layout_width="wrap_content"
android:layout_height="1dp"
tools:text="Id"
tools:visibility="invisible"
tools:ignore="MissingConstraints" />
<TextView
android:id="#+id/tvEmail"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="4dp"
android:textAlignment="center"
android:textSize="17dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="#+id/tvBuyAmount"
app:layout_constraintHorizontal_bias="0.135"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.533"
tools:text="Date" />
<TextView
android:id="#+id/tvName"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:padding="4dp"
android:textAlignment="center"
android:textSize="17dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="#+id/tvBuyAmount"
app:layout_constraintHorizontal_bias="0.94"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:text="Name" />
<TextView
android:id="#+id/tvBuyAmount"
android:layout_width="59dp"
android:layout_height="wrap_content"
android:padding="7dp"
android:textAlignment="center"
android:textSize="15dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="#+id/tvUseAmount"
app:layout_constraintHorizontal_bias="0.885"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:text="aaa" />
<TextView
android:id="#+id/tvUseAmount"
android:layout_width="49dp"
android:layout_height="wrap_content"
android:layout_marginStart="248dp"
android:padding="7dp"
android:textAlignment="center"
android:textSize="15dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="#+id/deleteBtn"
app:layout_constraintHorizontal_bias="0.269"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:text="aaa" />
<ImageView
android:id="#+id/popupButton"
android:layout_width="67dp"
android:layout_height="28dp"
android:layout_marginStart="28dp"
android:src="#drawable/ic_menu_more"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="1.0"
app:layout_constraintStart_toStartOf="#+id/tvUseAmount"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="#+id/deleteBtn"
android:layout_width="67dp"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:text="削除"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.982"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="1.0"
/>
</androidx.constraintlayout.widget.ConstraintLayout>
show_menu.xml
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="#+id/editText"
android:title="編集"
android:icon="#drawable/ic_edit" />
<item
android:id="#+id/delete"
android:title="削除"
android:icon="#drawable/ic_delete" />
</menu>
Student.adapter.kt
class StudentAdapter: RecyclerView.Adapter<StudentAdapter.StudentViewHolder>() {
private var stdList: ArrayList<StudentModel> = ArrayList()
private var onClickItem: ((StudentModel) -> Unit)?=null
private var onClickDeleteItem: ((StudentModel) -> Unit)?=null
fun addItems(items: ArrayList<StudentModel>){
this.stdList=items
notifyDataSetChanged()
}
fun setOnClickItem(callback:(StudentModel)->Unit){
this.onClickItem = callback
}
fun setOnClickDeleteItem(callback: (StudentModel) -> Unit){
this.onClickDeleteItem = callback
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int)= StudentViewHolder (
LayoutInflater.from(parent.context).inflate(R.layout.card_items_rec,parent,false)
)
override fun onBindViewHolder(holder: StudentViewHolder, position: Int) {
val std = stdList[position]
holder.bindView(std)
holder.itemView.setOnClickListener{onClickItem?.invoke(std)}
holder.btnDelete.setOnClickListener{onClickDeleteItem?.invoke(std)}
}
override fun getItemCount(): Int {
return stdList.size
}
class StudentViewHolder(var view: View):RecyclerView.ViewHolder(view){
var id:TextView = view.findViewById<TextView>(R.id.tvId)
var name:TextView = view.findViewById<TextView>(R.id.tvName)
var email:TextView = view.findViewById<TextView>(R.id.tvEmail)
var buyAmount:TextView = view.findViewById<TextView>(R.id.tvBuyAmount)
var useAmount:TextView = view.findViewById<TextView>(R.id.tvUseAmount)
var btnDelete:Button = view.findViewById<Button>(R.id.deleteBtn)
var popupButton: ImageView = view.findViewById(R.id.popupButton)
fun bindView(std:StudentModel){
id.text = std.id.toString()
name.text = std.name
email.text = std.email
buyAmount.text = std.buyamount.toString()
useAmount.text = std.useamount.toString()
}
}
}
allRecordPage.kt
class allRecordpage : AppCompatActivity() {
private lateinit var edName: EditText
private lateinit var edEmail: Button
private lateinit var edBuyAmount: EditText
private lateinit var edUseAmount: EditText
private lateinit var edReason: EditText
private lateinit var btnAdd: Button
private lateinit var btnView: Button
private lateinit var btnUpdate: Button
private lateinit var sqLiteHelper: SQLiteHelper
private lateinit var recyclerView: RecyclerView
private var adapter: StudentAdapter?=null
private var std:StudentModel?=null
val dataHolder = "DataHolder"
#RequiresApi(Build.VERSION_CODES.N)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_all_recordpage)
val textView: TextView =findViewById(R.id.DateText)
val simpleDateFormat= SimpleDateFormat("yyyy/MM/dd\n HH:mm", Locale.getDefault()).format(
Date()
)
val currentDateAndTime: String = simpleDateFormat.format(Date())
textView.text = currentDateAndTime
val button = findViewById<Button>(R.id.goBackToHome)
button.setOnClickListener{
val intent = Intent(this,MainMenu::class.java)
startActivity(intent)
}
initView()
initRecyclerView()
sqLiteHelper= SQLiteHelper(this)
//Show recycler view
val stdList = sqLiteHelper.getAllStudent()
Log.e("おっけ","${stdList.size}")
adapter?.setOnClickItem {
//購入・使用編集画面に遷移
if(it.buyamount > 0){
val intent = Intent(this,buyDetailsScreen::class.java)
intent.putExtra("date",it.email)
intent.putExtra("name", it.name)
intent.putExtra("buyAmount", it.buyamount)
startActivity(intent)
}else if (it.useamount > 0){
val intent = Intent(this,useDetailsScreen::class.java)
intent.putExtra("date",it.email)
intent.putExtra("name",it.name)
intent.putExtra("useAmount",it.useamount)
intent.putExtra("reason",it.reason)
startActivity(intent)
}else{
Toast.makeText(this,"エラーが発生しました",Toast.LENGTH_LONG).show()
}
}
adapter?.addItems(stdList)
adapter?.setOnClickDeleteItem{
deleteStudent(it.id)
}
}
private fun deleteStudent(id:Int){
val builder = AlertDialog.Builder(this)
builder.setMessage("データを削除してよろしいですか")
builder.setCancelable(true)
builder.setNegativeButton("いいえ"){dialog, _ ->
dialog.dismiss()
}
builder.setPositiveButton("はい"){dialog, _ ->
sqLiteHelper.deleteStudentById(id)
getStudents()
dialog.dismiss()
}
val alert = builder.create()
alert.show()
}
private fun updateStudent(){
val name = edName.text.toString()
val email = edEmail.text.toString()
val buyAmount = edBuyAmount.text.toString().toInt()
val useAmount = edUseAmount.text.toString().toInt()
val reason = edReason.text.toString()
//Check record not changed
if(name == std?.name && email == std?.email && buyAmount == std?.buyamount && useAmount == std?.useamount && reason == std?.reason){
Toast.makeText(this,"データが変更されてない", Toast.LENGTH_SHORT).show()
return
}
if(std == null) return
val std = StudentModel(id=std!!.id,name = name,email = email, buyamount = buyAmount, useamount = useAmount, reason = reason)
val status = sqLiteHelper.updateStudent(std)
if(status > -1){
clearEditText()
getStudents()
}else{
Toast.makeText(this,"更新失敗した", Toast.LENGTH_SHORT).show()
}
}
private fun getStudents(){
val stdList = sqLiteHelper.getAllStudent()
Log.e("おっけ","${stdList.size}")
adapter?.addItems(stdList)
}
private fun addStudent(){
val name = edName.text.toString()
val email = edEmail.text.toString()
val buyAmount = edBuyAmount.text.toString().toInt()
val useAmount = edUseAmount.text.toString().toInt()
val reason = edReason.text.toString()
if(name.isEmpty()||email.isEmpty()|| buyAmount.toString().isEmpty() ||useAmount.toString().isEmpty() || reason.toString().isEmpty()){
Toast.makeText(this,"データを入力してください", Toast.LENGTH_SHORT).show()
}else{
val std = StudentModel(name = name, email=email, buyamount=buyAmount, useamount=useAmount, reason = reason)
val status = sqLiteHelper.insertStudent(std)
//Check Insert success or not success
if(status > -2){
Toast.makeText(this,"データを追加しました。", Toast.LENGTH_SHORT).show()
clearEditText()
}else{
Toast.makeText(this,"データが保存されてないようです。", Toast.LENGTH_SHORT).show()
}
}
}
private fun clearEditText(){
edName.setText("")
edEmail.text = ""
edBuyAmount.setText("")
edUseAmount.setText("")
edReason.setText("")
edName.requestFocus()
}
private fun initRecyclerView(){
recyclerView.layoutManager=LinearLayoutManager(this)
adapter = StudentAdapter()
recyclerView.adapter=adapter
}
private fun initView(){
recyclerView=findViewById(R.id.recyclerView)
}
}
I have the code to edit/delete but first of all how do I get the popup menu to work in my recyclerview?

How can I update the UI without skipping frames

So I am developing and android app in Kotlin with coroutines and no matter what change I make, I still keep getting the message:
I/Choreographer: Skipped 59 frames! The application may be doing too much work on its main thread.
How can I get rid of it. I mean like I am only displaying nine photos... Below is my code
Model:
data class Food (
val id: String,
val name: String,
val price: String,
#Json(name = "img_url") val imgSrcUrl: String,
val type: String,
val description: String,
val average_rating: String,
val number_of_raters: String,
val special_price: String
)
data class FoodCategory(
val id: String,
val title: String,
val foods: List<Food>
)
ViewModel:
enum class NetworkStatus {LOADING, DONE, FAILED}
enum class FontFamily (#FontRes val fontRes: Int) {
POPPINS_BOLD(R.font.poppins_bold),
POPPINS(R.font.poppins)
}
class FoodOverviewViewModel(private val foodRepository: FoodRepository): ViewModel() {
private lateinit var foodProducts: List<Food>
//This is the data that is gonna be exposed to the viewmodel
//It will be submitted to a ListAdapter
private val _foodCategory = MutableLiveData<List<FoodCategory>>()
val foodCategory: LiveData<List<FoodCategory>>
get() = _foodCategory
//Used to display a progress bar for network status
private val _status = MutableLiveData<NetworkStatus>()
val status: LiveData<NetworkStatus>
get() = _status
init {
getOverviewProducts()
}
private fun getOverviewProducts() {
viewModelScope.launch(Dispatchers.Default) {
_status.postValue(NetworkStatus.LOADING)
try {
getUpdatedFood()
Log.i("getOverviewProducts","I am running on tread: $coroutineContext")
_status.postValue(NetworkStatus.DONE)
}catch (e: Exception) {
_status.postValue(NetworkStatus.FAILED)
}
}
}
private suspend fun getUpdatedFood() {
//withContext(Dispatchers.Default) {
val limiter = 6 //Number of items I want to get from the server
val foodCategory = arrayListOf<FoodCategory>()
Log.i("getUpdatedFood","I am running on tread: $coroutineContext")
val getRecommended = foodRepository.getRecommendedFood(limiter.toString())
foodCategory += FoodCategory(id = 0.toString(), title = "Recommended for you", foods = getRecommended)
val getSpecials = foodRepository.getSpecials(limiter.toString())
foodCategory += FoodCategory(id = 1.toString(), title = "Specials", foods = getSpecials)
_foodCategory.postValue(foodCategory)
//}
}
}
Repository:
class FoodRepository {
suspend fun getRecommendedFood(limiter: String) = withContext(Dispatchers.IO) {
Log.i("Resp-getRecommended","I am running on tread: $coroutineContext")
return#withContext ProductApi.retrofitService.getRecommended(limiter)
}
suspend fun getSpecials(limiter: String) = withContext(Dispatchers.IO) {
Log.i("Resp-getSpecials","I am running on tread: $coroutineContext")
return#withContext ProductApi.retrofitService.getSpecials(limiter)
}
}
BindingAdapters:
//Load image using Glide (in Food item recycleview)
#BindingAdapter("imageUrl")
fun bindImage(imgView: ImageView , imgUrl: String?) {
imgUrl?.let {
val imgUri = imgUrl.toUri().buildUpon().scheme("http").build()
Glide.with(imgView.context)
.load(imgUri)
.apply(
RequestOptions()
.placeholder(R.drawable.loading_animation)
.error(R.drawable.ic_broken_image))
.into(imgView)
}
}
//set raters count (in Food item recycleview)
#BindingAdapter("ratersCount")
fun bindText(txtView: TextView, number_of_raters: String?) {
number_of_raters?.let {
val ratersCount = "(${number_of_raters})"
txtView.text = ratersCount
}
}
//update the progressbar visibilty (in outer-parent recycleview)
#BindingAdapter("updateStatus")
fun ProgressBar.updateStatus(status: NetworkStatus?) {
visibility = when (status) {
NetworkStatus.LOADING -> View.VISIBLE
NetworkStatus.DONE -> View.GONE
else -> View.GONE
}
}
//Hide or view an imageview based in the network Status. When network Error, an error image
//will show (in outer-parent recycleview)
#BindingAdapter("setNoInternet")
fun ImageView.setNoInternet(status: NetworkStatus?) {
when(status) {
NetworkStatus.LOADING -> {
visibility = View.GONE
}
NetworkStatus.DONE -> {
visibility = View.GONE
}
NetworkStatus.FAILED -> {
visibility = View.VISIBLE
setImageResource(R.drawable.ic_connection_error)
}
}
}
//Submit the list of FoodCatergory item to the outer-parent recycleview
#BindingAdapter("listData")
fun bindRecyclerView(recyclerView: RecyclerView, data: List<FoodCategory>?) {
(recyclerView.adapter as FoodCategoryAdapter).submitList(data)
}
//Submit list the the Food item recyclew view (child recycleView)
#BindingAdapter("setProducts")
fun RecyclerView.setProducts(foods: List<Food>?) {
if (foods != null) {
val foodAdapter = FoodItemAdapter()
foodAdapter.submitList(foods)
adapter = foodAdapter
}
}
I have a Recycleview of Food Item and a Recycleview Pool of FoodCategory. If I comment out
_foodCategory.postValue(foodCategory)
in ViewModel: getUpdatedFood() than I do not get the message. However, when I submit the list to the outer recycleview (The one the hold the viewpool), than I get this answer. Please help. I been stuck on it for a while tryna get rid of that message.
Thank you..
Updated
Below is the adapeters and its view holders
FoodItem layout
<layout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<data>
<import type="android.view.View"/>
<variable
name="foodItem"
type="com.example.e_commerceapp.models.Food"/>
<variable
name="font"
type="com.example.e_commerceapp.products.overview.FontFamily"/>
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:id="#+id/child_item_main_layout"
android:background="#drawable/search_background"
android:layout_marginTop="10dp"
android:layout_marginStart="10dp"
android:layout_marginBottom="10dp"
android:layout_width="150dp"
android:layout_height="250dp">
<ImageView
android:layout_width="120dp"
android:layout_marginStart="10dp"
android:layout_marginEnd="10dp"
android:id="#+id/burger_image"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
android:layout_height="160dp"
/>
<!-- app:imageUrl="#{foodItem.imgSrcUrl}"-->
<TextView
android:layout_width="match_parent"
android:layout_height="34dp"
android:layout_marginStart="5dp"
android:id="#+id/burger_title"
app:layout_constraintStart_toStartOf="parent"
android:layout_marginEnd="5dp"
android:singleLine="true"
android:textColor="#B4000000"
app:layout_constraintTop_toBottomOf="#id/burger_image"
android:text="#{foodItem.name}"
android:textSize="12sp"
android:fontFamily="#font/poppins"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="35dp"
app:layout_constraintTop_toBottomOf="#id/burger_title"
android:layout_marginEnd="5dp"
android:gravity="center"
android:id="#+id/burger_price"
android:layout_marginStart="5dp"
app:layout_constraintStart_toEndOf="#id/special_price"
android:textColor="#D0000000"/>
<!-- app:price="#{foodItem.price}"-->
<!-- app:specialPrice="#{foodItem.special_price}"-->
<!-- app:fontRes="#{foodItem.special ? font.POPPINS : font.POPPINS_BOLD}"-->
<TextView
android:layout_width="wrap_content"
android:layout_height="35dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#id/burger_title"
android:layout_marginEnd="5dp"
android:gravity="center_vertical"
android:layout_marginStart="5dp"
android:id="#+id/special_price"
android:textColor="#D0000000"
android:visibility="gone"
android:textStyle="normal"
android:fontFamily="#font/poppins_bold"/>
<!-- app:setSpecialPrice="#{foodItem.special_price}"-->
<ImageView
android:layout_width="15dp"
android:layout_height="15dp"
app:layout_constraintTop_toBottomOf="#id/burger_price"
android:src="#drawable/ic_baseline_star_24"
android:visibility="#{foodItem.hasRating ? View.GONE : View.VISIBLE}"
android:id="#+id/rating_star"
app:layout_constraintStart_toStartOf="parent"
android:layout_marginStart="5dp"
android:layout_marginBottom="10dp"
app:layout_constraintBottom_toBottomOf="parent"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="15dp"
android:layout_marginStart="5dp"
android:gravity="center"
android:textSize="12sp"
android:visibility="#{foodItem.hasRating ? View.GONE : View.VISIBLE}"
android:id="#+id/rating_count"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toBottomOf="#id/burger_price"
android:text="#{foodItem.average_rating}"
android:layout_marginBottom="10dp"
app:layout_constraintStart_toEndOf="#id/rating_star"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="15dp"
android:id="#+id/number_of_raters"
android:textSize="12sp"
android:visibility="#{foodItem.hasRating ? View.GONE : View.VISIBLE}"
android:layout_marginStart="2dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toEndOf="#id/rating_count"
app:ratersCount="#{foodItem.number_of_raters}"
android:layout_marginBottom="10dp"
app:layout_constraintTop_toBottomOf="#id/burger_price"/>
<ImageView android:layout_width="20dp"
android:layout_height="20dp"
android:layout_marginEnd="10dp"
android:layout_marginTop="10dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
FoodItem Adapter
class FoodItemAdapter: ListAdapter<Food ,
FoodItemAdapter.ItemFoodViewHolder>(DiffCallback) {
override fun onCreateViewHolder(parent: ViewGroup , viewType: Int): ItemFoodViewHolder {
return ItemFoodViewHolder(
FoodItemBinding.inflate(LayoutInflater.from(parent.context),
parent, false))
}
override fun onBindViewHolder(holder: ItemFoodViewHolder , position: Int) {
val currentFood = getItem(position)
holder.bind(currentFood)
}
class ItemFoodViewHolder(private var binding: FoodItemBinding): RecyclerView.ViewHolder(binding.root) {
fun bind(food: Food) {
binding.foodItem = food
binding.executePendingBindings()
}
}
object DiffCallback: DiffUtil.ItemCallback<Food>() {
override fun areItemsTheSame(oldItem: Food , newItem: Food): Boolean {
return oldItem === newItem
}
override fun areContentsTheSame(oldItem: Food , newItem: Food): Boolean {
return oldItem.id == newItem.id
}
}
}
FoodCategory layout
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<data>
<variable
name="foodCategory"
type="com.example.e_commerceapp.models.FoodCategory"/>
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:background="#fff"
android:layout_marginTop="5dp"
android:layout_marginBottom="5dp"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:id="#+id/category_title"
android:layout_marginTop="16dp"
android:text="#{foodCategory.title}"
android:textColor="#2B2A2A"
android:fontFamily="#font/poppins_bold"
android:textSize="16sp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/nestedRecyclerView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
app:setProducts="#{foodCategory.foods}"
android:orientation="horizontal"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/category_title"
tools:itemCount="4"
tools:listitem="#layout/food_item"/>
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
FoodCategory Adapter
class FoodCategoryAdapter: ListAdapter<FoodCategory,
FoodCategoryAdapter.CategoryFoodViewHolder>(Companion) {
private val viewPool = RecyclerView.RecycledViewPool()
override fun onCreateViewHolder(parent: ViewGroup , viewType: Int): CategoryFoodViewHolder {
return CategoryFoodViewHolder(FoodCategoryBinding.inflate(LayoutInflater.from(parent.context),
parent, false))
}
override fun onBindViewHolder(holder: CategoryFoodViewHolder , position: Int) {
val currentFoodCategory = getItem(position)
holder.bind(currentFoodCategory)
}
inner class CategoryFoodViewHolder(private var binding: FoodCategoryBinding): RecyclerView.ViewHolder(binding.root) {
fun bind(currentFoodCategory: FoodCategory?) {
binding.foodCategory = currentFoodCategory
binding.nestedRecyclerView.setRecycledViewPool(viewPool)
binding.executePendingBindings()
}
}
companion object: DiffUtil.ItemCallback<FoodCategory>() {
override fun areItemsTheSame(oldItem: FoodCategory , newItem: FoodCategory): Boolean {
return oldItem === newItem
}
override fun areContentsTheSame(oldItem: FoodCategory, newItem: FoodCategory): Boolean {
return oldItem.id == newItem.id
}
}
}
The parent recycleView
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
tools:context=".products.overview.FoodOverviewFragment">
<data>
<variable
name="foodOverview"
type="com.example.e_commerceapp.products.overview.FoodOverviewViewModel"/>
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:background="#color/grey"
android:layout_width="match_parent"
android:layout_height="match_parent">
<RelativeLayout
android:layout_width="match_parent"
android:id="#+id/relative_layout"
android:layout_height="105dp"
android:elevation="8dp"
android:layout_marginBottom="5dp"
android:background="#fff"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintEnd_toEndOf="parent">
<ImageView
android:layout_width="200dp"
android:layout_marginTop="10dp"
android:layout_height="35dp"
android:id="#+id/logo_and_name"
android:src="#drawable/compony_logo_and_name"
android:layout_alignParentStart="true"/>
<ImageView
android:layout_width="wrap_content"
android:layout_height="35dp"
android:layout_marginTop="10dp"
android:id="#+id/notifications"
android:src="#drawable/ic_baseline_notifications_24"
android:layout_alignParentEnd="true"
android:paddingEnd="20dp"
android:paddingStart="20dp"/>
<TextView
android:layout_width="match_parent"
android:id="#+id/search"
android:layout_marginTop="10dp"
android:layout_marginStart="20dp"
android:layout_marginEnd="20dp"
android:background="#drawable/search_background"
android:layout_below="#id/logo_and_name"
android:gravity="center_vertical"
android:layout_height="match_parent"
android:layout_marginBottom="10dp"
android:paddingEnd="10dp"
android:paddingStart="10dp"
android:text="#string/search_text"
tools:ignore="RtlSymmetry"
app:drawableEndCompat="#drawable/ic_baseline_search_24"/>
</RelativeLayout>
<ProgressBar
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:updateStatus="#{foodOverview.status}"
app:layout_constraintTop_toBottomOf="#id/relative_layout"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:id="#+id/progressbar"/>
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="#id/relative_layout"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:id="#+id/noInternetImage"/>
<androidx.recyclerview.widget.RecyclerView
android:layout_width="0dp"
android:id="#+id/foodCategory"
android:clipToPadding="false"
tools:itemCount="4"
tools:listitem="#layout/food_category"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
android:layout_height="0dp"
app:listData="#{foodOverview.foodCategory}"
app:layout_constraintTop_toBottomOf="#id/relative_layout"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toBottomOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
The skipping frames likely has nothing to do with the code you posted: it sounds like a misconfiguration of RecyclerViews / Adapters to me. You'll need to post that code for it be more clear though.
However, even though what you posted likely isn't the culprit you can still optimize the coroutines code you have:
class FoodOverviewViewModel(private val foodRepository: FoodRepository): ViewModel() {
private lateinit var foodProducts: List<Food>
private val _foodCategory = MutableLiveData<List<FoodCategory>>()
val foodCategory: LiveData<List<FoodCategory>>
get() = _foodCategory
private val _status = MutableLiveData<NetworkStatus>()
val status: LiveData<NetworkStatus>
get() = _status
init {
getOverviewProducts()
}
private fun getOverviewProducts() {
viewModelScope.launch { // <------- Don't apply a custom scope here
_status.value = NetworkStatus.LOADING // <--- Don't call "postValue" here
try {
val food = getUpdatedFood() // <------ This is already using a background dispatcher
_foodCategory.value = food // <------- Emit this value here
_status.value = NetworkStatus.DONE
} catch (e: Exception) {
_status.value = NetworkStatus.FAILED
}
}
}
private suspend fun getUpdatedFood(): List<FoodCategory> { // <---- Return a value here
val limiter = 6 //Number of items I want to get from the server
val foodCategory = arrayListOf<FoodCategory>()
Log.i("getUpdatedFood","I am running on tread: $coroutineContext")
val getRecommended = foodRepository.getRecommendedFood(limiter.toString())
foodCategory += FoodCategory(id = 0.toString(), title = "Recommended for you", foods = getRecommended)
val getSpecials = foodRepository.getSpecials(limiter.toString())
foodCategory += FoodCategory(id = 1.toString(), title = "Specials", foods = getSpecials)
return foodCategories
}
}
The key ideas here:
Use viewModelScope.launch { ... } rather than applying a scope. You want everything in there that is not a coroutine to run on the main thread. See, for example, https://developer.android.com/kotlin/coroutines/coroutines-best-practices#main-safe
Return a value from getUpdatedFood so you can just update the _foodCategory value on the main thread in the viewModelScope

Problem with saving data of a profile in Firebase database

I want to create a profile in my app, where I can edit or add some information when logged in. It already works with the checkbox but not with the other editText items. Also I want to show the saved information after I closed the app in the profile. Any idea how I could do this? Like changing an editText to a textView or is there any other way?
Here is my code of the fragment Profile:
(I tried several options to save data in the firebase database)
package com.example.discoverme
import android.annotation.SuppressLint
import android.app.AlertDialog
import android.content.ContentValues.TAG
import android.content.Context
import android.content.Intent
import android.net.Uri
import android.os.Bundle
import android.util.Log
import android.view.*
import android.widget.*
import androidx.fragment.app.Fragment
import com.google.firebase.auth.FirebaseAuth
import com.google.firebase.auth.UserProfileChangeRequest
import com.google.firebase.database.*
import java.util.*
import java.util.Calendar.*
class ProfilFoto : Fragment() {
lateinit var mDatabase : DatabaseReference
var mAuth = FirebaseAuth.getInstance()
var user = FirebaseAuth.getInstance().currentUser
var DISPLAY_NAME : String? = null
#SuppressLint("SetTextI18n", "ResourceType")
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// setContentView(R.layout.fragment_notifications)
val rootView: View = inflater.inflate(R.layout.fragment_profil_foto, container, false)
Toast.makeText(this.requireContext(), "Profil", Toast.LENGTH_LONG)
Log.e("Halllo", "Hat toll geklapptttt")
val telefon = rootView.findViewById<View>(R.id.telnummer) as EditText
val geburtstag = rootView.findViewById<View>(R.id.geburtsdatum) as EditText
val location = rootView.findViewById<View>(R.id.locationPerson) as EditText
val stundenlohn = rootView.findViewById<View>(R.id.stundenlohn) as EditText
var tele = telefon.text.toString()
var gebi = geburtstag.text.toString()
var loc = location.text.toString()
var stundenl = stundenlohn.text.toString()
val nameTxt: TextView = rootView.findViewById(R.id.textName1)
val emailTxt: TextView = rootView.findViewById(R.id.emailemail)
val spezi = rootView.findViewById<TextView>(R.id.spezialisierungen)
var uid = user!!.uid
val userHashMap = HashMap<String, Any>()
mDatabase = FirebaseDatabase.getInstance().getReference("User").child(uid)
val speicherButton = rootView.findViewById<Button>(R.id.speichern)
speicherButton.setOnClickListener {
Log.e("Speichern", "speichert")
Log.e("Telefon", tele)
//userHashMap["Telefon"] = tele
//mDatabase.child("Telefon").setValue(tele)
mDatabase.child("Telefon").setValue(tele)
.addOnSuccessListener {
Log.e("Telefon", tele)
}
.addOnFailureListener {
Log.e("Telefon2", "failed")
}
if (!gebi.isEmpty()) {
Log.e("Geburtstag", gebi)
userHashMap["Geburtsdatum"] = gebi
// mDatabase.updateChildren(userHashMap)
}
if (!loc.isEmpty()) {
userHashMap["Adresse"] = loc
// mDatabase.updateChildren(userHashMap)
}
if (!stundenl.isEmpty()) {
userHashMap["Stundenlohn"] = stundenl
// mDatabase.updateChildren(userHashMap)
}
mDatabase.updateChildren(userHashMap)
}
mDatabase.addValueEventListener(object : ValueEventListener {
override fun onCancelled(error: DatabaseError) {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}
override fun onDataChange(snapshot: DataSnapshot) {
nameTxt.text = snapshot.child("Name").value.toString()
emailTxt.text = snapshot.child("Email").value.toString()
if (snapshot.child("Spezialisierung").exists()) {
Log.e("Spez", "Ist anscheinend da")
spezi.text = snapshot.child("Spezialisierung").value.toString()
}
/* if (snapshot.child("Telefon").exists()) {
telefon.text = snapshot.child("Telefon").value.toString()
}
*/
}
})
val buttonSignOut : ImageButton? = rootView.findViewById(R.id.signOut_button1)
if (buttonSignOut != null) {
buttonSignOut.setOnClickListener{
mAuth.signOut()
Toast.makeText(this.context, "Signed Out", Toast.LENGTH_LONG).show()
startActivity(Intent(this.context, Start::class.java))
}
}
val buttonspezi = rootView.findViewById<Button>(R.id.buttonspez)
buttonspezi.setOnClickListener { view ->
var dialog: AlertDialog
// Initialize an array of colors
val arrayColors = arrayOf("Hochzeit", "Portrait", "Familien", "Architektur", "Passfotos", "Lebensmittel", "Film", "Interior", " Kinder/Babies", "Landschaft", "Mode", "People und Lifestyle", "Werbung", "Sport", "Produkte", "Akt")
// Initialize a boolean array of checked items
val arrayChecked = booleanArrayOf(false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false)
var stringArray = arrayOf<String>()
// Initialize a new instance of alert dialog builder object
val builder = AlertDialog.Builder(this.context)
// Set a title for alert dialog
builder.setTitle("Gib seine Spezialisierung an.")
// Define multiple choice items for alert dialog
builder.setMultiChoiceItems(arrayColors, arrayChecked) { dialog, which, isChecked ->
// Update the clicked item checked status
arrayChecked[which] = isChecked
// Get the clicked item
val color = arrayColors[which]
}
// Set the positive/yes button click listener
builder.setPositiveButton("OK") { _, _ ->
// Do something when click positive button
spezi.text = "Deine Spezialisierungen sind.. \n"
for (i in 0 until arrayColors.size) {
val checked = arrayChecked[i]
if (checked) {
stringArray += arrayOf(arrayColors[i])
spezi.text = "${spezi.text}" + stringArray.toString()
}
}
userHashMap["Spezialisierung"] = stringArray.asList()
Log.e("Liste", stringArray.asList().toString())
mDatabase.updateChildren(userHashMap)
}
// Initialize the AlertDialog using builder object
dialog = builder.create()
// Finally, display the alert dialog
dialog.show()
}
return rootView
}
// Method to show an alert dialog with multiple choice list items
// Extension function to show toast message
fun Context.toast(message: String) {
Toast.makeText(this, message, Toast.LENGTH_SHORT).show()
}
}
and here is the xml
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:id="#+id/profil_foto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#ffff"
android:orientation="vertical"
tools:context=".ProfilFoto">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="259dp"
android:background="#9C27B0"
android:orientation="vertical"
android:visibility="visible">
<ImageButton
android:id="#+id/signOut_button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="320dp"
android:layout_marginLeft="350dp"
android:background="#9C27B0"
android:contentDescription="TODO"
android:paddingTop="20dp"
android:paddingEnd="20dp"
android:paddingRight="20dp"
android:src="#drawable/ic_baseline_logout_24"
android:title="#string/sign_out"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:showAsAction="ifRoom"
app:tint="#FFFFFF"
tools:ignore="RtlSymmetry"
tools:visibility="visible" />
<ImageView
android:id="#+id/logo4"
android:layout_width="match_parent"
android:layout_height="120dp"
android:layout_gravity="center"
android:layout_margin="10dp"
android:contentDescription="#string/todo"
android:src="#drawable/ic_profil_wei_" />
<TextView
android:id="#+id/textName1"
android:layout_width="wrap_content"
android:layout_height="39dp"
android:layout_gravity="center_horizontal"
android:textColor="#fff"
android:textSize="21sp"
android:textStyle="bold" />
<Space
android:layout_width="match_parent"
android:layout_height="50dp" />
</LinearLayout>
<LinearLayout
android:layout_width="360dp"
android:layout_height="700dp"
android:layout_gravity="center"
android:layout_marginTop="45dp"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:paddingLeft="25dp">
<EditText
android:id="#+id/infotext"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="center_vertical"
android:hint="Erzähle etwas über dich..."
android:paddingLeft="20dp">
</EditText>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="25dp"
android:orientation="horizontal"
android:paddingLeft="25dp">
<ImageView
android:layout_width="36dp"
android:layout_height="36dp"
android:src="#drawable/ic_baseline_location_on_24"
app:tint="#9C27B0" />
<EditText
android:id="#+id/locationPerson"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:hint="Adresse"
android:paddingLeft="20dp" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="25dp"
android:orientation="horizontal"
android:paddingLeft="25dp">
<ImageView
android:layout_width="36dp"
android:layout_height="36dp"
android:background="#00FFFFFF"
android:src="#drawable/ic_baseline_cake_24"
app:tint="#9C27B0" />
<EditText
android:id="#+id/geburtsdatum"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:hint="Geburtsdatum"
android:paddingLeft="20dp" />
</LinearLayout>
<EditText
android:id="#+id/telnummer"
android:layout_width="300dp"
android:layout_height="35dp"
android:background="#drawable/button_register_background"
android:drawableLeft="#drawable/ic_baseline_call_24"
android:drawablePadding="10dp"
android:ems="10"
android:hint="Telefonnummer"
android:paddingLeft="20dp" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="25dp"
android:orientation="horizontal"
android:paddingLeft="25dp">
<ImageView
android:layout_width="36dp"
android:layout_height="36dp"
android:src="#drawable/ic_mail_full"
app:tint="#9C27B0" />
<TextView
android:id="#+id/emailemail"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:paddingLeft="20dp" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="25dp"
android:orientation="horizontal"
android:paddingLeft="25dp">
<Button
android:id="#+id/buttonspez"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Spezialisierungen"
android:textAllCaps="false"
android:background="#drawable/buttom_rounded_corner_lila"
android:textColor="#FFFFFF"
android:layout_gravity="center_vertical|center_horizontal"
android:gravity="center"
/>
<TextView
android:id="#+id/spezialisierungen"
android:layout_width="match_parent"
android:layout_height="wrap_content"
style="#style/Base.TextAppearance.AppCompat.Large"
android:layout_margin="25dp"
/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="25dp"
android:orientation="horizontal"
android:paddingLeft="25dp">
<ImageView
android:layout_width="36dp"
android:layout_height="36dp"
android:src="#drawable/ic_baseline_attach_money_24"
app:tint="#9C27B0" />
<EditText
android:id="#+id/stundenlohn"
android:hint="Stundenlohn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:paddingLeft="20dp" />
</LinearLayout>
<Button
android:id="#+id/speichern"
android:layout_width="160dp"
android:layout_height="50dp"
android:layout_gravity="center"
android:layout_marginTop="25dp"
android:background="#drawable/buttom_rounded_corner_lila"
android:text="Änderungen speichern"
android:textColor="#FFFFFF"
app:cornerRadius="20dp">
</Button>
</LinearLayout>
<Space
android:layout_width="match_parent"
android:layout_height="17dp" />
</LinearLayout>
</ScrollView>
I solved it. I just had to move the findViewById declaration inside the setOnClickListener and not only in the onCreate. Now I'm getting the ediText information and can save it in my firebase database.
Like so:
class ProfilFoto : Fragment() {
lateinit var mDatabase : DatabaseReference
var mAuth = FirebaseAuth.getInstance()
var user = FirebaseAuth.getInstance().currentUser
var DISPLAY_NAME : String? = null
#SuppressLint("SetTextI18n", "ResourceType")
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// setContentView(R.layout.fragment_notifications)
val rootView: View = inflater.inflate(R.layout.fragment_profil_foto, container, false)
Toast.makeText(this.requireContext(), "Profil", Toast.LENGTH_LONG)
Log.e("Halllo", "Hat toll geklapptttt")
val nameTxt: TextView = rootView.findViewById(R.id.textName1)
val emailTxt: TextView = rootView.findViewById(R.id.emailemail)
val spezi = rootView.findViewById<TextView>(R.id.spezialisierungen)
var uid = user!!.uid
val userHashMap = HashMap<String, Any>()
mDatabase = FirebaseDatabase.getInstance().getReference("User").child(uid)
val speicherButton = rootView.findViewById<Button>(R.id.speichern)
speicherButton.setOnClickListener {
val telefon = rootView.findViewById<View>(R.id.telnummer) as EditText
val geburtstag = rootView.findViewById<View>(R.id.geburtsdatum) as EditText
val location = rootView.findViewById<View>(R.id.locationPerson) as EditText
val stundenlohn = rootView.findViewById<View>(R.id.stundenlohn) as EditText
val tele = telefon.text.toString()
val gebi = geburtstag.text.toString()
val loc = location.text.toString()
val stundenl = stundenlohn.text.toString()
Log.e("Speichern", "speichert")
if (!gebi.isEmpty()) {
Log.e("Telefon", tele)
//userHashMap["Telefon"] = tele
//mDatabase.child("Telefon").setValue(tele)
mDatabase.child("Telefon").setValue(tele)
.addOnSuccessListener {
Log.e("Telefon", tele)
}
.addOnFailureListener {
Log.e("Telefon2", "failed")
}
}
if (!gebi.isEmpty()) {
Log.e("Geburtstag", gebi)
//userHashMap["Geburtsdatum"] = gebi
mDatabase.child("Geburtstag").setValue(gebi)
.addOnSuccessListener {
Log.e("Telefon", gebi)
}
.addOnFailureListener {
Log.e("Telefon2", "failed")
}
// mDatabase.updateChildren(userHashMap)
}
if (!loc.isEmpty()) {
Log.e("Location", loc)
//userHashMap["Adresse"] = loc
mDatabase.child("Adresse").setValue(loc)
.addOnSuccessListener {
Log.e("Telefon", loc)
}
.addOnFailureListener {
Log.e("Telefon2", "failed")
}
// mDatabase.updateChildren(userHashMap)
}
if (!stundenl.isEmpty()) {
// userHashMap["Stundenlohn"] = stundenl
mDatabase.child("Stundenlohn").setValue(stundenl)
.addOnSuccessListener {
Log.e("Telefon", stundenl)
}
.addOnFailureListener {
Log.e("Telefon2", "failed")
}
// mDatabase.updateChildren(userHashMap)
}
}
mDatabase.addValueEventListener(object : ValueEventListener {
override fun onCancelled(error: DatabaseError) {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}
override fun onDataChange(snapshot: DataSnapshot) {
nameTxt.text = snapshot.child("Name").value.toString()
emailTxt.text = snapshot.child("Email").value.toString()
if (snapshot.child("Spezialisierung").exists()) {
Log.e("Spez", "Ist anscheinend da")
spezi.text = snapshot.child("Spezialisierung").value.toString()
}
/* if (snapshot.child("Telefon").exists()) {
telefon.text = snapshot.child("Telefon").value.toString()
}
*/
}
})
val buttonSignOut : ImageButton? = rootView.findViewById(R.id.signOut_button1)
if (buttonSignOut != null) {
buttonSignOut.setOnClickListener{
mAuth.signOut()
Toast.makeText(this.context, "Signed Out", Toast.LENGTH_LONG).show()
startActivity(Intent(this.context, Start::class.java))
}
}
I just need to figure out how to show the saved information, in the profile after saving it once.

How to display data in RecyclerView using Retrofit2 API?

First of all, I'm new to Android/Java/Kotlin development. I'm using Retrofit2 to retrieve data from Udacity API. I can see the response in the Logcat, but when I try to display it in RecyclerView there is just a blank screen. I think the error is in the MainActivity, but I'm still clueless and need help.
My model classes
class Course(var title: String,
var subtitle: String,
var key: String,
var instructors: List<Instructor>,
var expected_learning: String,
var required_knowledge: String)
class Instructor(var name: String,
var bio: String)
My interface
interface ApiServiceInterface {
#GET("courses")
fun list() : Call<UdacityCatalog>
}
My adapter
class CourseAdapter(val listCourses: ArrayList<Course?>, val context: Context) : RecyclerView.Adapter<CourseAdapter.CourseViewHolder>() {
class CourseViewHolder(viewItem: View) : RecyclerView.ViewHolder(viewItem) {
val courseTitle = viewItem.findViewById<TextView?>(R.id.tv_title) as TextView
val courseSubtitle = viewItem.findViewById<TextView?>(R.id.tv_subtitle) as TextView
val courseKey = viewItem.findViewById<TextView?>(R.id.tv_course_key) as TextView
val instructorName = viewItem.findViewById<TextView?>(R.id.tv_instructor_name) as TextView
}
override fun onCreateViewHolder(parent: ViewGroup?, viewType: Int): CourseViewHolder {
val viewHolder = LayoutInflater.from(parent?.context).inflate(R.layout.activity_item_list, parent, false)
val itemViewHolder = CourseViewHolder(viewHolder)
return itemViewHolder
}
override fun onBindViewHolder(holder: CourseViewHolder?, position: Int) {
holder?.courseTitle?.text = listCourses[position].title
holder?.courseSubtitle?.text = listCourses[position].subtitle
holder?.courseKey?.text = listCourses[position].key
holder?.instructorName?.text = listCourses[position].instructors.toString()
}
override fun getItemCount(): Int = listCourses.size
}
My MainActivity -- I think the error is in here, but I haven't figured it out yet
class MainActivity : AppCompatActivity() {
internal val TAG = "Testing Retrofit2 API"
lateinit var mRecyclerView: RecyclerView
lateinit var mCourseAdapter: RecyclerView.Adapter<CourseAdapter.CourseViewHolder>
val listCourse = arrayListOf<Course?>()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main_recyclerview)
mRecyclerView = findViewById<RecyclerView?>(R.id.id_recycler_view) as RecyclerView
val mLayoutManager = LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false)
mRecyclerView.layoutManager = mLayoutManager
mRecyclerView.setHasFixedSize(true)
mCourseAdapter = CourseAdapter(listCourse, applicationContext)
mRecyclerView.adapter = mCourseAdapter
mCourseAdapter.notifyDataSetChanged()
val call = RetrofitInitializer().createService().list()
call.enqueue(object : Callback<UdacityCatalog> {
override fun onResponse(call: Call<UdacityCatalog>, response: Response<UdacityCatalog>) {
response.body()
if (!response.isSuccessful) {
Log.i(TAG, "[ ERROR ] " + response.code())
} else {
if (listCourse.isEmpty()) {
Toast.makeText(applicationContext, "Empty list!", Toast.LENGTH_LONG).show()
} else {
Toast.makeText(applicationContext, "Full list!", Toast.LENGTH_LONG).show()
}
val catalog = response.body()
for (c in catalog!!.courses!!) {
Log.i(TAG, String.format("%s: %s", c.title, c.subtitle, c.key, c.required_knowledge, c.expected_learning))
for (i in c.instructors!!) {
Log.i(TAG, i.name)
}
Log.i(TAG, "\n****************************************************************************************************\n")
}
}
}
override fun onFailure(call: Call<UdacityCatalog>?, t: Throwable?) {
Log.d(TAG, "onFailure() : " + t?.message)
}
})
}
}
An initializer class for Retrofit instance
class RetrofitInitializer {
companion object Factory {
val BASE_URL = "https://www.udacity.com/public-api/v0/"
}
private val retrofit = Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build()
fun createService(): ApiServiceInterface = retrofit.create(ApiServiceInterface::class.java)
}
My RecyclerView xml file
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingBottom="16dp"
android:paddingLeft="16dp"
android:paddingRight="16dp"
android:paddingTop="16dp"
tools:context="activities.MainActivity">
<android.support.v7.widget.RecyclerView
android:id="#+id/id_recycler_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
</android.support.v7.widget.RecyclerView>
</LinearLayout>
My CardView xml file
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="16dp"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:paddingBottom="16dp"
android:paddingLeft="16dp"
android:paddingRight="16dp"
android:paddingTop="16dp">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:text="#string/udacity_catalog"
android:textAppearance="?android:textAppearanceLarge"
android:textColor="#9C27B0"
android:textStyle="bold" />
<TextView
android:id="#+id/tv_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:gravity="start"
android:hint="#string/hint_title"
android:textAppearance="?android:textAppearanceMedium"
android:textColor="#000000" />
<TextView
android:id="#+id/tv_subtitle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:gravity="start"
android:hint="#string/hint_subtitle"
android:textAppearance="?android:textAppearanceMedium"
android:textColor="#000000" />
<TextView
android:id="#+id/tv_course_key"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:gravity="start"
android:hint="#string/hint_key"
android:textAppearance="?android:textAppearanceMedium"
android:textColor="#000000" />
<TextView
android:id="#+id/tv_instructor_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:gravity="start"
android:hint="#string/hint_name"
android:textAppearance="?android:textAppearanceMedium"
android:textColor="#000000" />
</LinearLayout>
</android.support.v7.widget.CardView>
You have an empty list of courses (listCourse) in your Activity. You pass that empty list to the adapter via it's constructor.
That list stays empty even after you fetched the courses. So the adapter / RecyclerView stays empty.
Try creating the adapter after you fetched the courses, with
mCourseAdapter = CourseAdapter(catalog!!.courses!!, applicationContext)
or have a courses property in your adapter lile
YourAdapter(...) {
var courses = listOf(Course)
}
and then in your Activity (after fetching the courses):
adapter.courses = catalog!!.courses!!
adapter.notifyDataSetChanged()

livedata recyclerview with checkbox

I am implementing android architecture component to view buyers list and select one.
Here is my Buyer entity
#Entity
data class Buyer(#PrimaryKey var id: Long = 0, var name: String = "", var photo: String = "", var address: String = "",
#Ignore var isSelected: Boolean = false,
#SerializedName("last_update_time") var lastUpdateTime: Long = 0L) {
}
I have inserted and displayed it in recyclerview.
What I want is to know how can I display particular buyer is selected, when click on one buyer.
If I click on one buyer previous selected buyer must deselect.
Please help me to implement this.
EDIT
class BuyerAdapter(private var buyers: ArrayList<Buyer>, private val listener: View.OnClickListener) : RecyclerView.Adapter<BuyerViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BuyerViewHolder {
val v = LayoutInflater.from(parent.context).inflate(
R.layout.item_buyer, parent, false)
return BuyerViewHolder(v)
}
override fun onBindViewHolder(holder: BuyerViewHolder, position: Int) {
bindView(holder, position)
}
private fun bindView(holder: BuyerViewHolder, position: Int) {
val buyer = buyers[position]
holder.setName(buyer.name)
holder.setAddress(buyer.address)
holder.loadImage(ServiceHandler.BASE_URL + buyer.photo)
if (buyer.isSelected) {
holder.setCardColor(R.color.waveBlue)
holder.setNameColor(R.color.white)
holder.setAddressColor(R.color.white)
} else {
holder.setCardColor(R.color.white)
holder.setNameColor(R.color.contentGrey)
holder.setAddressColor(R.color.contentGreyDesc)
}
holder.itemView.tag = buyer
holder.itemView.setOnClickListener(listener)
}
override fun getItemCount(): Int = buyers.size
fun refresh(newBuyers: ArrayList<Buyer>) {
this.buyers = newBuyers
notifyDataSetChanged()
}
}
And here is my adapter xml item
<?xml version="1.0" encoding="utf-8"?><!--<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"--><!--xmlns:card_view="http://schemas.android.com/apk/res-auto"--><!--android:layout_width="match_parent"--><!--android:layout_height="191dp"--><!--android:paddingTop="13dp"--><!-->-->
<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:card_view="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/buyer_card"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="8dp"
android:layout_marginRight="8dp"
android:layout_marginTop="4dp"
android:clickable="true"
card_view:cardCornerRadius="2dp"
card_view:cardElevation="4dp"
card_view:cardPreventCornerOverlap="true">
<android.support.constraint.ConstraintLayout
android:id="#+id/rlBuyerBack"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="4dp">
​
<de.hdodenhof.circleimageview.CircleImageView
android:id="#+id/ivLogo"
android:layout_width="40dp"
android:layout_height="40dp"
android:scaleType="centerCrop"
android:src="#drawable/placeholder_profile_photo"
card_view:layout_constraintBottom_toBottomOf="parent"
card_view:layout_constraintLeft_toLeftOf="parent"
card_view:layout_constraintTop_toTopOf="parent" />
<in.motiontech.wave.helper.WaveTextView
android:id="#+id/tvName"
style="#style/semiBoldFont"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="8dp"
android:text="Name"
android:textColor="#color/contentGrey"
android:textSize="#dimen/tSizeHeader"
card_view:layout_constraintLeft_toRightOf="#+id/ivLogo"
card_view:layout_constraintTop_toTopOf="#+id/ivLogo" />
<in.motiontech.wave.helper.WaveTextView
android:id="#+id/tvAddress"
style="#style/regularFont"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignStart="#id/tvName"
android:layout_below="#+id/tvName"
android:layout_marginLeft="8dp"
android:layout_marginTop="2dp"
android:text="Address"
android:textColor="#color/contentGrey"
android:textSize="#dimen/tSizeDesc"
card_view:layout_constraintLeft_toRightOf="#+id/ivLogo"
card_view:layout_constraintTop_toBottomOf="#+id/tvName" />
</android.support.constraint.ConstraintLayout>
</android.support.v7.widget.CardView>
Edit 2
Here how I added data in recyclerview
viewModel.getBuyers().observe(this, Observer<List<Buyer>> {
if (it != null) {
if (it.isEmpty()) {
showProgress()
if (CommonUtils.isInNetwork(this)) {
viewModel.getBuyerList()
} else {
CommonUtils.showNoInternetDialog(this)
}
} else {
hideProgress()
buyerAdapter?.refresh(ArrayList(it))
}
}
})
What I have done is I have updated value of livedata. You can see below code:
fun selectBuyer(buyer: Buyer?) {
if (buyer == null)
return
buyers.value?.filter { it != buyer }?.forEach { it.isSelected = false }
buyers.value?.get(buyers.value!!.indexOf(buyer))?.isSelected = true
newBuyer = buyer
}
I notice there is no need to notifyupdate, as I am using observer pattern

Categories

Resources