My List doesn't seem to be getting initialised and I'm not really sure what I should be doing here, everytime I run I get:
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.alarmclockproject, PID: 13493
java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.TextView.setText(java.lang.CharSequence)' on a null object reference
at com.example.alarmclockproject.fragments.AlarmListAdapter.onBindViewHolder(AlarmListAdapter.kt:27)
Removing the notifyDataSetChanged() stops the fatal crash, but then shows no alarms on fragment, despite multiple being in the database ( checked using DB Browser )
Here is my Adapter:
class AlarmListAdapter() :
RecyclerView.Adapter<RecyclerView.ViewHolder>() {
private var alarmList: List<Alarm> = ArrayList()
class ViewHolder(binding: FragmentHomeBinding) : RecyclerView.ViewHolder(binding.root)
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
val binding = FragmentHomeBinding.inflate(LayoutInflater.from(parent.context))
return ViewHolder(binding)
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
val currentItem = alarmList[position]
holder.itemView.findViewById<TextView>(R.id.tv_alarm_time).text =
"${currentItem.hour}:${currentItem.minute}"
//holder.itemView.findViewById<TextView>(R.id.tv_repeat_days)
}
override fun getItemCount(): Int {
return alarmList.size
}
fun setData(alarm: List<Alarm>){
this.alarmList = alarm
notifyDataSetChanged()
}
}
My HomeFragment where the recycler view is displayed:
class HomeFragment : Fragment() {
lateinit var binding: FragmentHomeBinding
private lateinit var alarmViewModel: AlarmViewModel
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
binding = FragmentHomeBinding.inflate(inflater, container, false)
// RecyclerView
val adapter = AlarmListAdapter()
val recyclerView = binding.recyclerView
recyclerView.adapter = adapter
recyclerView.layoutManager = LinearLayoutManager(requireContext())
//ViewModel
alarmViewModel = ViewModelProvider(this).get(AlarmViewModel::class.java)
alarmViewModel.readAlarmData.observe(viewLifecycleOwner, Observer { alarm ->
adapter.setData(alarm)
})
binding.btnAddAlarm.setOnClickListener{
Navigation.findNavController(requireView()).navigate(R.id.action_homeFragment_to_newAlarmFragment)
}
return binding.root
}
}
and it's layout:
<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:id="@ id/frameLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".fragments.HomeFragment">
<TextView
android:id="@ id/tv_next_alarm"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="64dp"
android:text="11:11"
android:textAppearance="@style/TextAppearance.AppCompat.Display3"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.498"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@ id/btn_add_alarm"
android:layout_width="57dp"
android:layout_height="57dp"
android:layout_marginBottom="52dp"
android:background="@drawable/round_button"
android:text=" "
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
<androidx.recyclerview.widget.RecyclerView
android:id="@ id/recycler_view"
android:layout_width="411dp"
android:layout_height="446dp"
android:layout_marginStart="1dp"
android:layout_marginTop="1dp"
android:layout_marginEnd="1dp"
android:layout_marginBottom="1dp"
app:layout_constraintBottom_toTopOf="@ id/btn_add_alarm"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@ id/tv_next_alarm" />
</androidx.constraintlayout.widget.ConstraintLayout>
ViewModel:
class AlarmViewModel(application: Application) : AndroidViewModel(application) {
val readAlarmData: LiveData<List<Alarm>>
private val repository: AlarmRepository
init {
val alarmDao = AlarmsDatabase.getDatabase(application).alarmDao()
repository = AlarmRepository(alarmDao)
readAlarmData = repository.readAlarmData
}
fun addAlarm(alarm: Alarm) {
viewModelScope.launch(Dispatchers.IO) {
repository.addAlarm(alarm)
}
}
}
Dao:
@Dao
interface AlarmDao {
@Insert()
suspend fun addAlarm(alarm: Alarm)
@Query("SELECT * FROM alarm_table ORDER BY id ASC")
fun readAlarmData(): LiveData<List<Alarm>>
@Update
fun updateAlarm(alarm: Alarm)
}
and the Alarm Class:
@Entity(tableName = "alarm_table")
data class Alarm (
@PrimaryKey(autoGenerate = true)
val id: Int,
val hour: Int,
val minute: Int,
val repeat: Boolean
)
CodePudding user response:
The following line in onCreateViewHolder()
is causing the crash:
val binding = FragmentHomeBinding.inflate(LayoutInflater.from(parent.context))
You are inflating the FragmentHomeBinding
, which has no TextView
with id R.id.tv_alarm_time. Use that of the RecyclerView
item instead.