null cannot be cast to non-null type com.example.kotlindiary.MainActivity
Внутри фрагмента в главной активности при загрузке данных из FireBase проверяется, все ли необходимые данные имеет пользователь, если нет, то он отсылается к необходимой активности для ввода данных. Когда пользователь попадает в необходимую активити, он может переключаться между различными активити для ввода различной информации (школа->класс->расписание)
И почему-то в активити со школами при выборе школы, выскакивает ошибка, которая находится во фрагменте главной активити.
kotlin.TypeCastException: null cannot be cast to non-null type com.example.kotlindiary.MainActivity
at com.example.kotlindiary.MainFragment$downloadHomework$1$onDataChange$1.onDataChange(MainFragment.kt:210)
Жалуется на строчку с инициализацией Intent:
if(timetableisreal){...}
else{
val intent = Intent(activity, SetTimetableActivity::class.java)
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK.or(Intent.FLAG_ACTIVITY_CLEAR_TASK)
startActivity(intent)
}
Отмечу, что ошибка выскакивает именно при выборе школы, а ошибка отсылается к главному фрагменту. У меня есть предположение, что ValueEventListener прогоняет этот код несколько раз и в этот момент выходит ошибка. Но тогда странно, что после завершения работы главной активности, слушатель продолжает работу. Заранее спасибо
UPD: код фрагмента
class MainFragment : Fragment() {
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
...
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
...
downloadHomework()
}
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
super.onCreateOptionsMenu(menu, inflater)
}
fun downloadHomework(){
...
ref.addValueEventListener(object : ValueEventListener{
override fun onDataChange(p0: DataSnapshot) {
user = p0.getValue(User::class.java)
val schoolName = user?.school
val form = user?.form
if(user?.name == "" || user?.surname == ""){//проверка, есть ли имя, фамилия
val intent = Intent(activity, ProfileActivity::class.java)
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK.or(Intent.FLAG_ACTIVITY_CLEAR_TASK)
startActivity(intent)
(activity as MainActivity).finish()
}
else if(schoolName == ""){//выбрана ли школа
val intent = Intent(activity, ChooseSchoolActivity::class.java)
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK.or(Intent.FLAG_ACTIVITY_CLEAR_TASK)
startActivity(intent)
(activity as MainActivity).finish()
}
else if(form == ""){//выбран ли класс
val intent = Intent(activity, ChooseFormActivity::class.java)
intent.putExtra("schoolName", schoolName)
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK.or(Intent.FLAG_ACTIVITY_CLEAR_TASK)
startActivity(intent)
(activity as MainActivity).finish()
}
else{
val refTimetable = FirebaseDatabase.getInstance().getReference("/schools/$schoolName/$form/timetable")
refTimetable.addValueEventListener(object : ValueEventListener{
override fun onDataChange(p0: DataSnapshot) {
p0.children.forEach {
//проверка, есть ли расписание
}
if(timetableisreal){...}
else{
val intent = Intent(activity, SetTimetableActivity::class.java)//если нет, отправляем на активити с установкой расписания
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK.or(Intent.FLAG_ACTIVITY_CLEAR_TASK)
startActivity(intent)
}
}
override fun onCancelled(p0: DatabaseError) {}
})
}
}
override fun onCancelled(p0: DatabaseError) {}
})
}
}
Ответы (1 шт):
Ваши предположения оказались верны. Слушатель изменений в удалённой БД продолжает реагировать на изменения в ней даже после покидания активити. В итоге активити и становится null, когда идёт к ней обращение.
Чтобы этого избежать, вам надо явно отписываться от изменений в БД. Для этого сохраните ваш слушатель в отдельную переменную и перед покиданием активити - удалите его. Примерно так:
val listener = object : ValueEventListener ...
ref.addValueEventListener(listener)
ref.removeValueEventListener(listener)