My data class:
data class HallData(
var name:String,
var mobile:String,
var isAddInfoChecked:Boolean,
var isFanDetailChecked:Boolean,
var fanNumber:String,
var isPompDetailChecked:Boolean,
var pompNumber:String,
var isHeaterDetailChecked:Boolean,
var heaterNumber:String,
var isCircularFanDetailChecked:Boolean,
var circularFanNumber:String
)
UserAdapter:
class UserAdapter(val c: Context, val userList: MutableList<HallData>) :
RecyclerView.Adapter<UserAdapter.UserViewHolder>() {
inner class UserViewHolder(val v: View) : RecyclerView.ViewHolder(v) {
var name: TextView
var mbNum: TextView
var mMenus: ImageView
var fanText: TextView
var pompText: TextView
var heaterText: TextView
var circularFanText: TextView
var fanNum: TextView
var pompNum: TextView
var heaterNum: TextView
var circularFanNum: TextView
init {
name = v.findViewById<TextView>(R.id.mTitle)
mbNum = v.findViewById<TextView>(R.id.mSubTitle)
mMenus = v.findViewById(R.id.mMenus)
mMenus.setOnClickListener { popupMenus(it) }
fanText = v.findViewById(R.id.fan_text)
pompText = v.findViewById(R.id.pomp_text)
heaterText = v.findViewById(R.id.heater_text)
circularFanText = v.findViewById(R.id.circular_text)
fanNum = v.findViewById(R.id.fan_number)
pompNum = v.findViewById(R.id.pomp_number)
heaterNum = v.findViewById(R.id.heater_number)
circularFanNum = v.findViewById(R.id.circular_number)
fanText.visibility = View.GONE
pompText.visibility = View.GONE
heaterText.visibility = View.GONE
circularFanText.visibility = View.GONE
fanNum.visibility = View.GONE
pompNum.visibility = View.GONE
heaterNum.visibility = View.GONE
circularFanNum.visibility = View.GONE
}
private fun popupMenus(v: View) {
val position = userList[adapterPosition]
val popupMenus = PopupMenu(c, v)
popupMenus.inflate(R.menu.show_menu)
popupMenus.setOnMenuItemClickListener {
when (it.itemId) {
R.id.editText -> {
val v = LayoutInflater.from(c).inflate(R.layout.add_hall, null)
val name = v.findViewById<EditText>(R.id.userName)
val number = v.findViewById<EditText>(R.id.userNo)
val addInfoCheckBox = v.findViewById<CheckBox>(R.id.add_info_checkBox)
val fanCheckBox = v.findViewById<CheckBox>(R.id.fan_checkbox)
val pompCheckBox = v.findViewById<CheckBox>(R.id.pomp_checkbox)
val heaterCheckBox = v.findViewById<CheckBox>(R.id.heater_checkbox)
val circularFanCheckBox = v.findViewById<CheckBox>(R.id.circular_checkbox)
val fanNumberPicker = v.findViewById<NumberPicker>(R.id.fan_number_picker)
val pompNumberPicker = v.findViewById<NumberPicker>(R.id.pomp_number_picker)
val heaterNumberPicker =
v.findViewById<NumberPicker>(R.id.heater_number_picker)
val circularFanNumberPicker =
v.findViewById<NumberPicker>(R.id.circular_number_picker)
val fanLayout = v.findViewById<ConstraintLayout>(R.id.fan_layout)
val pompLayout = v.findViewById<ConstraintLayout>(R.id.pomp_layout)
val heaterLayout = v.findViewById<ConstraintLayout>(R.id.heater_layout)
val circularFanLayout = v.findViewById<ConstraintLayout>(R.id.circular_layout)
val fanNumberPreview = v.findViewById<TextView>(R.id.fan_number_preview)
val pompNumberPreview = v.findViewById<TextView>(R.id.pomp_number_preview)
val heaterNumberPreview = v.findViewById<TextView>(R.id.heater_number_preview)
val circularFanNumberPreview = v.findViewById<TextView>(R.id.circular_number_preview)
var fanNumber = 0
var pompNumber = 0
var heaterNumber = 0
var circularFanNumber = 0
addInfoCheckBox.setOnCheckedChangeListener { buttonView, isChecked ->
if (addInfoCheckBox.isChecked) {
Toast.makeText(c, "Checked", Toast.LENGTH_SHORT).show()
fanLayout.visibility = View.VISIBLE
pompLayout.visibility = View.VISIBLE
heaterLayout.visibility = View.VISIBLE
circularFanLayout.visibility = View.VISIBLE
fanNumberPicker.visibility = View.GONE
fanNumberPreview.visibility = View.GONE
pompNumberPicker.visibility = View.GONE
pompNumberPreview.visibility = View.GONE
heaterNumberPicker.visibility = View.GONE
heaterNumberPreview.visibility = View.GONE
circularFanNumberPicker.visibility = View.GONE
circularFanNumberPreview.visibility = View.GONE
//Fan Setting:
fanCheckBox.setOnCheckedChangeListener { buttonView, isChecked ->
if (fanCheckBox.isChecked) {
fanCheckBox.setBackgroundResource(R.drawable.green_stroke)
fanNumberPicker.visibility = View.VISIBLE
fanNumberPreview.visibility = View.VISIBLE
fanNumberPicker.minValue = 0
fanNumberPicker.maxValue = maxNumberPickerValue
fanNumberPicker.setOnValueChangedListener { picker, oldVal, newVal ->
fanNumberPreview.text = "تعداد فن : $newVal"
fanNumber = newVal
}
} else {
fanNumberPicker.visibility = View.GONE
fanNumberPreview.visibility = View.GONE
fanCheckBox.setBackgroundResource(R.drawable.red_stroke)
}
}
//Pomp Setting:
pompCheckBox.setOnCheckedChangeListener { buttonView, isChecked ->
if (pompCheckBox.isChecked) {
pompCheckBox.setBackgroundResource(R.drawable.green_stroke)
pompNumberPicker.visibility = View.VISIBLE
pompNumberPreview.visibility = View.VISIBLE
pompNumberPicker.minValue = 0
pompNumberPicker.maxValue = maxNumberPickerValue
pompNumberPicker.setOnValueChangedListener { picker, oldVal, newVal ->
pompNumberPreview.text = "تعداد پمپ : $newVal"
pompNumber = newVal
}
} else {
pompCheckBox.setBackgroundResource(R.drawable.red_stroke)
pompNumberPicker.visibility = View.GONE
pompNumberPreview.visibility = View.GONE
}
}
//Heater Setting:
heaterCheckBox.setOnCheckedChangeListener { buttonView, isChecked ->
if (heaterCheckBox.isChecked) {
heaterCheckBox.setBackgroundResource(R.drawable.green_stroke)
heaterNumberPicker.visibility = View.VISIBLE
heaterNumberPreview.visibility = View.VISIBLE
heaterNumberPicker.minValue = 0
heaterNumberPicker.maxValue = maxNumberPickerValue
heaterNumberPicker.setOnValueChangedListener { picker, oldVal, newVal ->
heaterNumberPreview.text = "تعداد هیتر : $newVal"
heaterNumber = newVal
}
} else {
heaterCheckBox.setBackgroundResource(R.drawable.red_stroke)
heaterNumberPicker.visibility = View.GONE
heaterNumberPreview.visibility = View.GONE
}
}
//CircularFan Setting:
circularFanCheckBox.setOnCheckedChangeListener { buttonView, isChecked ->
if (circularFanCheckBox.isChecked) {
circularFanCheckBox.setBackgroundResource(R.drawable.green_stroke)
circularFanNumberPicker.visibility = View.VISIBLE
circularFanNumberPreview.visibility = View.VISIBLE
circularFanNumberPicker.minValue = 0
circularFanNumberPicker.maxValue = maxNumberPickerValue
circularFanNumberPicker.setOnValueChangedListener { picker, oldVal, newVal ->
circularFanNumberPreview.text = "تعداد فن : $newVal"
circularFanNumber = newVal
}
} else {
circularFanCheckBox.setBackgroundResource(R.drawable.red_stroke)
circularFanNumberPicker.visibility = View.GONE
circularFanNumberPreview.visibility = View.GONE
}
}
} else {
Toast.makeText(c, "Unchecked", Toast.LENGTH_SHORT).show()
fanLayout.visibility = View.GONE
pompLayout.visibility = View.GONE
heaterLayout.visibility = View.GONE
circularFanLayout.visibility = View.GONE
}
}
name.setText(hallData[adapterPosition].name)
number.setText(hallData[adapterPosition].mobile)
AlertDialog.Builder(c)
.setView(v)
.setPositiveButton("ویرایش") { dialog, _ ->
position.name = name.text.toString()
position.mobile = number.text.toString()
Names[adapterPosition] = name.text.toString()
Phones[adapterPosition] = number.text.toString()
hallData[adapterPosition] = HallData(name.text.toString(),number.text.toString(),addInfoCheckBox.isChecked,fanCheckBox.isChecked,fanNumber.toString(),pompCheckBox.isChecked,pompNumber.toString(),heaterCheckBox.isChecked,heaterNumber.toString(),circularFanCheckBox.isChecked,circularFanNumber.toString())
notifyDataSetChanged()
Toast.makeText(c, "داده مورد نظر ویرایش شد", Toast.LENGTH_SHORT)
.show()
dialog.dismiss()
}
.setNegativeButton("لغو") { dialog, _ ->
dialog.dismiss()
}
.create()
.show()
true
}
R.id.delete -> {
/**set delete*/
AlertDialog.Builder(c)
.setTitle("حذف «${Names[adapterPosition]}»")
.setIcon(R.drawable.ic_warning)
.setMessage("آیا از حذف این داده مطمئن هستید؟")
.setPositiveButton("بله") { dialog, _ ->
userList.removeAt(adapterPosition)
//Log.d("TAG","Names -> "+Data.Phones)
Data.number--
Names.removeAt(adapterPosition)
Phones.removeAt(adapterPosition)
hallData.removeAt(adapterPosition)
//Log.d("TAG","Message -> Removed")
notifyDataSetChanged()
Toast.makeText(c, "داده مورد نظر حذف شد", Toast.LENGTH_SHORT).show()
dialog.dismiss()
}
.setNegativeButton("خیر") { dialog, _ ->
dialog.dismiss()
}
.create()
.show()
true
}
else -> true
}
}
popupMenus.show()
val popup = PopupMenu::class.java.getDeclaredField("mPopup")
popup.isAccessible = true
val menu = popup.get(popupMenus)
menu.javaClass.getDeclaredMethod("setForceShowIcon", Boolean::class.java)
.invoke(menu, true)
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): UserViewHolder {
val inflater = LayoutInflater.from(parent.context)
val v = inflater.inflate(R.layout.hall_item, parent, false)
return UserViewHolder(v)
}
override fun onBindViewHolder(holder: UserViewHolder, position: Int) {
val newList = userList[position]
holder.name.text = newList.name
holder.mbNum.text = newList.mobile
if(Data.hallData[position].isAddInfoChecked){
holder.fanNum.text = newList.fanNumber.toString()
holder.pompNum.text = newList.pompNumber.toString()
holder.heaterNum.text = newList.heaterNumber.toString()
holder.circularFanNum.text = newList.circularFanNumber.toString()
holder.fanText.visibility = View.VISIBLE
holder.pompText.visibility = View.VISIBLE
holder.heaterText.visibility = View.VISIBLE
holder.circularFanText.visibility = View.VISIBLE
holder.fanNum.visibility = View.VISIBLE
holder.pompNum.visibility = View.VISIBLE
holder.heaterNum.visibility = View.VISIBLE
holder.circularFanNum.visibility = View.VISIBLE
}else{
holder.fanText.visibility = View.GONE
holder.pompText.visibility = View.GONE
holder.heaterText.visibility = View.GONE
holder.circularFanText.visibility = View.GONE
holder.fanNum.visibility = View.GONE
holder.pompNum.visibility = View.GONE
holder.heaterNum.visibility = View.GONE
holder.circularFanNum.visibility = View.GONE
}
}
override fun getItemCount(): Int {
return userList.size
}
}
MainActivity:
class MainActivity : AppCompatActivity() {
private lateinit var addsBtn: FloatingActionButton
private lateinit var recv: RecyclerView
private lateinit var userList: MutableList<HallData>
private lateinit var userAdapter: UserAdapter
private lateinit var addInfoCheckBox: CheckBox
private var backPressedTime = 0L
lateinit var jsonString:String
var gson = Gson()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
/**set List*/
userList = ArrayList()
/**set find Id*/
addsBtn = findViewById(R.id.addingBtn)
recv = findViewById(R.id.mRecycler)
/**set Adapter*/
userAdapter = UserAdapter(this,userList)
/**setRecycler view Adapter*/
recv.layoutManager = LinearLayoutManager(this)
recv.adapter = userAdapter
/**set Dialog*/
addsBtn.setOnClickListener { addInfo() }
Data.hallData.clear()
Data.number=0
Data.Names.clear()
Data.Phones.clear()
val sharedPrefsMain = getSharedPreferences("my_prefs", MODE_PRIVATE)
val json_saved = sharedPrefsMain.getString("JsonHallData",null)
val after_json_saved = gson.fromJson(json_saved, mutableListOf<HallData>()::class.java)
if(!after_json_saved.isNullOrEmpty()){
for (i in 0 until after_json_saved.size){
try }
userList.add(after_json_saved[i])
Data.hallData.add(after_json_saved[i])
} catch (e:Exception){
Log.e("ERROR",e.message.toString())
}
}
}
}
private fun addInfo() {
val inflter = LayoutInflater.from(this)
val v = inflter.inflate(R.layout.add_hall,null)
/**set view*/
val userName = v.findViewById<EditText>(R.id.userName)
val userNo = v.findViewById<EditText>(R.id.userNo)
val addInfoCheckBox = v.findViewById<CheckBox>(R.id.add_info_checkBox)
val fanCheckBox = v.findViewById<CheckBox>(R.id.fan_checkbox)
val pompCheckBox = v.findViewById<CheckBox>(R.id.pomp_checkbox)
val heaterCheckBox = v.findViewById<CheckBox>(R.id.heater_checkbox)
val circularFanCheckBox = v.findViewById<CheckBox>(R.id.circular_checkbox)
val fanNumberPicker = v.findViewById<NumberPicker>(R.id.fan_number_picker)
val pompNumberPicker = v.findViewById<NumberPicker>(R.id.pomp_number_picker)
val heaterNumberPicker =
v.findViewById<NumberPicker>(R.id.heater_number_picker)
val circularFanNumberPicker =
v.findViewById<NumberPicker>(R.id.circular_number_picker)
val fanLayout = v.findViewById<ConstraintLayout>(R.id.fan_layout)
val pompLayout = v.findViewById<ConstraintLayout>(R.id.pomp_layout)
val heaterLayout = v.findViewById<ConstraintLayout>(R.id.heater_layout)
val circularFanLayout = v.findViewById<ConstraintLayout>(R.id.circular_layout)
val fanNumberPreview = v.findViewById<TextView>(R.id.fan_number_preview)
val pompNumberPreview = v.findViewById<TextView>(R.id.pomp_number_preview)
val heaterNumberPreview = v.findViewById<TextView>(R.id.heater_number_preview)
val circularFanNumberPreview = v.findViewById<TextView>(R.id.circular_number_preview)
var fanNumber = 0
var pompNumber = 0
var heaterNumber = 0
var circularFanNumber = 0
addInfoCheckBox.setOnCheckedChangeListener { buttonView, isChecked ->
if (addInfoCheckBox.isChecked) {
fanLayout.visibility = View.VISIBLE
pompLayout.visibility = View.VISIBLE
heaterLayout.visibility = View.VISIBLE
circularFanLayout.visibility = View.VISIBLE
fanNumberPicker.visibility = View.GONE
fanNumberPreview.visibility = View.GONE
pompNumberPicker.visibility = View.GONE
pompNumberPreview.visibility = View.GONE
heaterNumberPicker.visibility = View.GONE
heaterNumberPreview.visibility = View.GONE
circularFanNumberPicker.visibility = View.GONE
circularFanNumberPreview.visibility = View.GONE
//Fan Setting:
fanCheckBox.setOnCheckedChangeListener { buttonView, isChecked ->
if (fanCheckBox.isChecked) {
fanCheckBox.setBackgroundResource(R.drawable.green_stroke)
fanNumberPicker.visibility = View.VISIBLE
fanNumberPreview.visibility = View.VISIBLE
fanNumberPicker.minValue = 0
fanNumberPicker.maxValue = Data.maxNumberPickerValue
fanNumberPicker.setOnValueChangedListener { picker, oldVal, newVal -> fanNumberPreview.text = "تعداد فن : $newVal"
fanNumber = newVal
}
} else {
fanNumberPicker.visibility = View.GONE
fanNumberPreview.visibility = View.GONE
fanCheckBox.setBackgroundResource(R.drawable.red_stroke)
}
}
//Pomp Setting:
...
//Heater Setting:
...
//CircularFan Setting:
...
} else {
fanLayout.visibility = View.GONE
pompLayout.visibility = View.GONE
heaterLayout.visibility = View.GONE
circularFanLayout.visibility = View.GONE
}
}
val addDialog = AlertDialog.Builder(this)
addDialog.setView(v)
addDialog.setPositiveButton("افزودن"){
dialog,_->
val names = userName.text.toString()
val number = userNo.text.toString()
userList.add(HallData(
names,
number,
addInfoCheckBox.isChecked,
fanCheckBox.isChecked,
fanNumber.toString(),
pompCheckBox.isChecked,
pompNumber.toString(),
heaterCheckBox.isChecked,
heaterNumber.toString(),
circularFanCheckBox.isChecked,
circularFanNumber.toString()
))
userAdapter.notifyDataSetChanged()
Data.number++
Data.Names.add(names)
Data.Phones.add(number)
Data.hallData.add(HallData(
names,
number,
addInfoCheckBox.isChecked,
fanCheckBox.isChecked,
fanNumber.toString(),
pompCheckBox.isChecked,
pompNumber.toString(),
heaterCheckBox.isChecked,
heaterNumber.toString(),
circularFanCheckBox.isChecked,
circularFanNumber.toString()
))
Toast.makeText(this,"داده مورد نظر با موفقیت اضافه شد", Toast.LENGTH_SHORT).show()
dialog.dismiss()
}
addDialog.setNegativeButton("لغو"){
dialog,_->
dialog.dismiss()
Toast.makeText(this,"افزودن داده مورد نظر لغو شد", Toast.LENGTH_SHORT).show()
}
addDialog.create()
addDialog.show()
}
/**ok now run this */
override fun onPause() {
super.onPause()
val sharedPrefsOnPause = getSharedPreferences("my_prefs", MODE_PRIVATE)
val mEditor = sharedPrefsOnPause.edit()
mEditor.remove("Names")
mEditor.remove("Phone")
mEditor.remove("JsonHallData")
jsonString = gson.toJson(Data.hallData)
Log.d("JSON TAG","OnPause jsonString -> $jsonString")
mEditor.putString("JsonHallData",jsonString)
mEditor.apply()
}
override fun onBackPressed() {
if(backPressedTime + 2000 > System.currentTimeMillis()){
super.onBackPressed()
} else{
Toast.makeText(this, "برای خروج از برنامه، دوباره دکمه بازگشت را فشار دهید\n", Toast.LENGTH_SHORT).show()
}
backPressedTime = System.currentTimeMillis()
}
}
In onPause, users’ hall details are to be saved in sharedpreferences
First, hall details convert to Json (String) and after that jsonString will be saved in sharedpreferences:
jsonString = gson.toJson(Data.hallData)
mEditor.putString("JsonHallData",jsonString)
mEditor.apply()
Now, When user opens the app, I have a variable "json_saved" that receive jsonString from sharedpreferences
And, a variable "after_json_saved" that uses gson to convert json to my data class mutableList
val after_json_saved = gson.fromJson(json_saved, mutableListOf<HallData>()::class.java)
When I log this variable, after reopening app my saved data is correctly shown in this variable but the app crashes!
And this variable should be added to userList (and to my hallData variable in my object "Data" -> unimportant)
But the app crashes with this error:
java.lang.ClassCastException: com.google.gson.internal.LinkedTreeMap cannot be cast to com.example.phonetest2.model.HallData
And the error contains these lines of UserAdapter (Error is related to onBindViewHolder):
class UserAdapter(val c: Context, val userList: MutableList<HallData>) :
val newList = userList[position]
I have read possible answers related to this error but my problem has not been solved
Your help will be appreciated
>Solution :
It’s because of the type erasure in mutableListOf<HallData>()::class.java
. It loses the information that it was HallData
and deserializes it as LinkedTreeMap
Please try replacing val after_json_saved = gson.fromJson(json_saved, mutableListOf<HallData>()::class.java)
with val after_json_saved = gson.fromJson(json_saved, object : TypeToken<MutableList<HallData>>() {})