Items in one of my dropdown lists are starting to double themselves after orientation change for some reason.
Here are two pictures: one with the bug (after changing to horizontal and back) and one without it.
Here's my code:
Activity class:
class ScheduleActivity : AppCompatActivity(), GroupPickerActivity {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_lessons_list)
val groupPickerFragment = GroupPickerFragment()
fragmentManager.beginTransaction()
.add(R.id.central_frame, groupPickerFragment)
.commit()
}
override fun finishPicking() {
Toast.makeText(applicationContext, "Finished picking", Toast.LENGTH_SHORT).show()
}
}
Fragment class:
class GroupPickerFragment : MvpFragment(), GroupPickerView {
val TAG = "GroupPickerFragment"
@InjectPresenter
lateinit var groupPickerPresenter: GroupPickerPresenter
var noCitySelected = true
var noSchoolSelected = true
var noGroupSelected = true
override fun onCreateView(inflater: LayoutInflater?, container: ViewGroup?,
savedInstanceState: Bundle?): View? {
return inflater!!.inflate(R.layout.fragment_group_picker, container, false)
}
override fun onStart() {
super.onStart()
groupPickerPresenter.start(activity.applicationContext)
makeCitySpinnerClickable()
}
private fun makeCitySpinnerClickable() {
/*
* Set onItemSelectedListener on City picker spinner
* */
pick_your_city_tv.visibility = View.VISIBLE
city_picker_spinner.visibility = View.VISIBLE
city_picker_spinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
override fun onItemSelected(parentView: AdapterView<*>, selectedItemView: View?, pos: Int, id: Long) {
if (!noCitySelected) {
val selectedItem = parentView.getItemAtPosition(pos)
if (pos != 0) {
onCitySelected(selectedItem.toString())
} else {
onCreateNewCitySelected()
}
} else {
noCitySelected = false
}
}
override fun onNothingSelected(parentView: AdapterView<*>?) {}
}
}
private fun onCreateNewCitySelected() {
val textbox = EditText(activity.applicationContext)
val alertDialogBuilder = AlertDialog.Builder(activity,
R.style.AppTheme_myDialogueWindow)
alertDialogBuilder.setTitle(R.string.enter_new_city_name)
.setCancelable(true)
.setView(textbox)
.setPositiveButton(R.string.create_new, { _, _ ->
val newCityName = textbox.text.toString()
if (newCityName != "") {
groupPickerPresenter.createNewCity(newCityName)
} else {
Toast.makeText(activity.applicationContext,
R.string.city_name_cannot_be_empty,
Toast.LENGTH_SHORT).show()
}
})
.show()
}
override fun onCitiesDownloaded(cityList: ArrayAdapter<String>) {
val spinner = city_picker_spinner
val adapter = cityList
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
spinner.adapter = adapter
}
fun onCitySelected(cityName: String) {
Log.v(TAG, "Get cities by name")
groupPickerPresenter.onCitySelected(cityName)
makeSchoolSpinnerClickable()
}
override fun onCityAdded(newCityId: String) {
groupPickerPresenter.start(activity.applicationContext)
}
override fun onSchoolsDownloaded(schoolsList: ArrayAdapter<String>) {
val spinner = school_picker_spinner
val adapter = schoolsList
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
spinner.adapter = adapter
}
private fun makeSchoolSpinnerClickable() {
/*
* Set onItemSelectedListener on School picker spinner
* */
pick_your_school_tv.visibility = View.VISIBLE
school_picker_spinner.visibility = View.VISIBLE
school_picker_spinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
override fun onItemSelected(parentView: AdapterView<*>, selectedItemView: View?, pos: Int, id: Long) {
if (!noSchoolSelected) {
val selectedItem = parentView.getItemAtPosition(pos)
if (pos != 0) {
onSchoolSelected(selectedItem.toString())
} else {
onCreateNewSchoolSelected()
}
} else {
noSchoolSelected = false
}
}
override fun onNothingSelected(parentView: AdapterView<*>?) {}
}
}
private fun onCreateNewSchoolSelected() {
val textbox = EditText(activity.applicationContext)
val alertDialogBuilder = AlertDialog.Builder(activity,
R.style.AppTheme_myDialogueWindow)
alertDialogBuilder.setTitle(R.string.enter_new_school_name)
.setCancelable(true)
.setView(textbox)
.setPositiveButton(R.string.create_new, { _, _ ->
val newSchoolName = textbox.text.toString()
if (newSchoolName != "") {
val cityName = city_picker_spinner.selectedItem.toString()
groupPickerPresenter.createNewSchool(newSchoolName, cityName)
} else {
Toast.makeText(activity.applicationContext,
R.string.school_name_cannot_be_empty,
Toast.LENGTH_SHORT).show()
}
})
.show()
}
private fun onSchoolSelected(schoolName: String) {
Log.v(TAG, "Get schools by name")
groupPickerPresenter.onSchoolSelected(schoolName)
makeGroupSpinnerClickable()
}
override fun onSchoolAdded(newCityId: String) {
//todo Когда новая школа добавлена, надо обновить список школ
}
override fun onGroupsDownloaded(groupsList: ArrayAdapter<String>) {
val spinner = group_picker_spinner
val adapter = groupsList
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
spinner.adapter = adapter
}
private fun makeGroupSpinnerClickable() {
/*
* Set onItemSelectedListener on School picker spinner
* */
pick_your_group_tv.visibility = View.VISIBLE
group_picker_spinner.visibility = View.VISIBLE
group_picker_spinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
override fun onItemSelected(parentView: AdapterView<*>, selectedItemView: View?, pos: Int, id: Long) {
if (!noGroupSelected) {
val selectedItem = parentView.getItemAtPosition(pos)
if (pos != 0) {
onGroupSelected(selectedItem.toString())
} else {
onCreateNewGroupSelected()
}
} else {
noGroupSelected = false
}
}
override fun onNothingSelected(parentView: AdapterView<*>?) {}
}
}
private fun onGroupSelected(groupName: String) {
groupPickerPresenter.onGroupSelected(groupName)
}
private fun onCreateNewGroupSelected() {
val textbox = EditText(activity.applicationContext)
val alertDialogBuilder = AlertDialog.Builder(activity,
R.style.AppTheme_myDialogueWindow)
alertDialogBuilder.setTitle(R.string.enter_new_group_name)
.setCancelable(true)
.setView(textbox)
.setPositiveButton(R.string.create_new, { _, _ ->
val newGroupName = textbox.text.toString()
if (newGroupName != "") {
val schoolName = school_picker_spinner.selectedItem.toString()
groupPickerPresenter.createNewGroup(newGroupName, schoolName)
} else {
Toast.makeText(activity.applicationContext,
R.string.group_name_cannot_be_empty,
Toast.LENGTH_SHORT).show()
}
})
.show()
}
override fun onGroupAdded(updatedSchoolId: String) {
//todo обновить список групп
}
override fun letUserContinue() {
group_picker_next_btn.isEnabled = true
group_picker_next_btn.setOnClickListener({
val selectedSchoolName = school_picker_spinner.selectedItem.toString()
val selectedGroupName = group_picker_spinner.selectedItem.toString()
groupPickerPresenter.pick(selectedSchoolName, selectedGroupName)
group_picker_progressbar.visibility = View.VISIBLE
})
}
override fun finishPicking() {
group_picker_progressbar.visibility = View.GONE
(activity as GroupPickerActivity).finishPicking()
}
}
Fragment controller class:
@InjectViewState
class GroupPickerPresenter : MvpPresenter<GroupPickerView>() {
val TAG = "GroupPickerPresenter"
val cityModel = CityFirestoreModel()
val schoolModel = SchoolFirestoreModel()
lateinit var context: Context
init {
}
fun start(context: Context) {
this.context = context
getCities()
}
private fun getCities() {
cityModel.getAllCities {
val cityTitlesList = mutableListOf<String>()
// Adding 'Create new'
cityTitlesList.add(this.context.resources.getString(R.string.create_new))
it.forEach {
cityTitlesList.add(it.title)
}
val arrayAdapter = ArrayAdapter<String>(this.context,
android.R.layout.simple_spinner_item, cityTitlesList)
viewState.onCitiesDownloaded(arrayAdapter)
}
}
fun createNewCity(newCityName: String) {
cityModel.addCity(newCityName, { newCityId ->
if (newCityId != null)
viewState.onCityAdded(newCityId)
})
}
fun onCitySelected(cityName: String) {
val cityModel = CityFirestoreModel()
cityModel.getCitiesByName(cityName, {
getSchoolsByCity(it)
})
}
private fun getSchoolsByCity(cities: MutableList<City>) {
val schoolModel = SchoolFirestoreModel()
if (cities.size > 0) {
val city = cities[0]
schoolModel.getSchoolsByCityName(city.title, {
val schoolTitlesList = mutableListOf<String>()
// Adding 'Create new'
schoolTitlesList.add(this.context.resources.getString(R.string.create_new))
it.forEach {
schoolTitlesList.add(it.title)
}
val arrayAdapter = ArrayAdapter<String>(this.context,
android.R.layout.simple_spinner_item, schoolTitlesList)
viewState.onSchoolsDownloaded(arrayAdapter)
})
} else {
Log.e(TAG, "Cities list is empty")
val schoolTitlesList = mutableListOf<String>()
// Adding 'Create new'
schoolTitlesList.add(this.context.resources.getString(R.string.create_new))
val arrayAdapter = ArrayAdapter<String>(this.context,
android.R.layout.simple_spinner_item, schoolTitlesList)
viewState.onSchoolsDownloaded(arrayAdapter)
}
}
fun onSchoolSelected(schoolName: String) {
val schoolModel = SchoolFirestoreModel()
schoolModel.getSchoolGroups(schoolName, {
val groupTitlesList = mutableListOf<String>()
// Adding 'Create new'
groupTitlesList.add(this.context.resources.getString(R.string.create_new))
it.forEach {
groupTitlesList.add(it.title)
}
val arrayAdapter = ArrayAdapter<String>(this.context,
android.R.layout.simple_spinner_item, groupTitlesList)
viewState.onGroupsDownloaded(arrayAdapter)
})
}
fun createNewSchool(newSchoolName: String, cityName: String) {
val city = City()
city.title = cityName
val teachers = mutableListOf<Teacher>()
val subjects = mutableListOf<Subject>()
val groups = mutableListOf<Group>()
schoolModel.addSchool(newSchoolName, city, teachers, subjects, groups, { newCityId ->
if (newCityId != null)
viewState.onSchoolAdded(newCityId)
})
}
fun onGroupSelected(groupName: String) {
viewState.letUserContinue()
}
fun createNewGroup(newGroupName: String, schoolName: String) {
schoolModel.getSchoolsByName(schoolName, {
val school = it[0] //todo сделать какую-то проверку на уникальность, чтоб не было проблем
val group = Group()
group.title = newGroupName
school.groups.add(group)
schoolModel.updateSchool(school.school_id, school, {updatedSchoolId ->
if (updatedSchoolId != null) {
viewState.onGroupAdded(updatedSchoolId)
}
})
})
}
fun pick(schoolName: String, groupName: String) {
val schoolModel = SchoolFirestoreModel()
schoolModel.getSchoolGroup(schoolName, groupName, {group ->
if (group != null) {
val userFirestoreModel = UserFirestoreModel()
val currentUserId = FirebaseAuth.getInstance().currentUser!!.uid
userFirestoreModel.setGroup(currentUserId, group, {
viewState.finishPicking()
})
}
})
}
}
Before that I tried to use Fragment instead of FrameLayout in my activity xml file, but when I was using .commit()
on fragmentManager, my application crashed on orientation change and also showed the same bug as here every time I entered it.
But everything was okay when I didn't call .commit()
. Orientation change worked fine (besides the fact it was reseting chosen values) and there was no item doubling.
My former activity code:
class ScheduleActivity : AppCompatActivity(), GroupPickerActivity {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_lessons_list)
val groupPickerFragment = GroupPickerFragment()
fragmentManager.beginTransaction()
.replace(R.id.group_picker_fragment, groupPickerFragment)
}
}
My guess is when you change your orientation you are adding same fragment twice; In your code
fragmentManager.beginTransaction()
.add(R.id.central_frame, groupPickerFragment)
.commit()
change the add method with replace like this
fragmentManager.beginTransaction()
.replace(R.id.central_frame, groupPickerFragment)
.commit()