NavArgs 返回 RuntimeException
NavArgs returning a RuntimeException
NavArgs 没有 returning 一个值,当我尝试通过更新片段中的 setOnClickListener 进行更新时,我才得到这个值:
java.lang.RuntimeException: java.lang.reflect.InvocationTargetException
Caused by: java.lang.IllegalArgumentException: Required argument "currentAlarm" is missing and does not have an android:defaultValue
我需要 return 在 RecyclerView 中选择的警报的 ID,因此默认值在这里没有意义。
NavArgs 在导航视图中正确设置,没有默认值。 model 和 ID 会不会用 autoGenerate 设置错了?还是通过适配器进行这里的问题?
更新片段:
class UpdateFragment : Fragment() {
private val timePickerUtil = TimePickerUtil()
lateinit var binding: FragmentUpdateBinding
private lateinit var alarmViewModel: AlarmViewModel
private val args by navArgs<UpdateFragmentArgs>()
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
binding = FragmentUpdateBinding.inflate(inflater, container, false)
alarmViewModel = ViewModelProvider(this)[AlarmViewModel::class.java]
binding.fragmentBtnUpdateAlarm.setOnClickListener {
updateAlarm()
Navigation.findNavController(requireView())
.navigate(R.id.action_updateFragment_to_homeFragment)
}
return binding.root
}
private fun updateDatabase(id: Int, hour: Int, minute: Int, repeat: Boolean) {
val alarm = Alarm(id, hour, minute, repeat)
alarmViewModel.update(alarm)
}
private fun updateAlarm() {
val timePicker = binding.fragmentUpdateAlarmTimePicker
val id = args.currentAlarm.id
val hour = timePickerUtil.getTimePickerHour(timePicker)
val minute = timePickerUtil.getTimePickerMinute(timePicker)
val repeat = binding.fragmentUpdateAlarmRecurring.isChecked
val alarmManager = AlarmManager(
id,
hour,
minute,
true,
binding.fragmentUpdateAlarmRecurring.isChecked
)
updateDatabase(id, hour, minute, repeat)
alarmManager.cancel(requireContext())
alarmManager.schedule(requireContext())
}
}
适配器:
class AlarmListAdapter() :
RecyclerView.Adapter<RecyclerView.ViewHolder>() {
class MyViewHolder(binding: LayoutAlarmBinding) : RecyclerView.ViewHolder(binding.root)
private var alarmList = ArrayList<Alarm>()
private var onItemClickListener: OnItemClickListener? = null
interface OnItemClickListener{
fun onClick(alarm: Alarm)
fun onLongClick(alarm: Alarm)
}
fun setOnItemClickListener(listener: OnItemClickListener){
onItemClickListener = listener
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
val binding = LayoutAlarmBinding.inflate(LayoutInflater.from(parent.context))
return MyViewHolder(binding)
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
val currentItem = alarmList[position]
val minute = currentItem.minute
holder.itemView.findViewById<TextView>(R.id.tv_alarm_time).text =
if (minute >= 10) {
"${currentItem.hour}:${currentItem.minute}"
} else {
"${currentItem.hour}:0${currentItem.minute}"
}
holder.itemView.setOnClickListener{
if(onItemClickListener != null){
onItemClickListener?.onClick(currentItem)
}
}
holder.itemView.setOnLongClickListener {
if(onItemClickListener != null){
onItemClickListener?.onLongClick(currentItem)
}
true
}
}
override fun getItemCount(): Int {
return alarmList.size
}
fun setData(alarm: List<Alarm>) {
alarmList.clear()
alarmList.addAll(alarm)
notifyDataSetChanged()
}
}
主页片段:
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)
}
adapter.setOnItemClickListener(object : AlarmListAdapter.OnItemClickListener {
override fun onClick(alarm: Alarm) {
Navigation.findNavController(requireView())
.navigate(R.id.action_homeFragment_to_updateFragment)
}
override fun onLongClick(alarm: Alarm) {
val deleteBuilder = AlertDialog.Builder(requireContext())
deleteBuilder.setPositiveButton("Delete") { _, _ ->
alarmViewModel.delete(alarm)
Toast.makeText(context, "Alarm Deleted", Toast.LENGTH_SHORT)
.show()
}
deleteBuilder.setNegativeButton("Cancel") { _, _ ->
}
deleteBuilder.setTitle("Delete Alarm?")
deleteBuilder.create().show()
}
})
return binding.root
}
}
我的闹钟型号:
@Parcelize
@Entity(tableName = "alarm_table")
data class Alarm(
@PrimaryKey(autoGenerate = true)
val id: Int,
val hour: Int,
val minute: Int,
val repeat: Boolean
): Parcelable
Safe args 创建自己的 类(就像这里的 HomeFragmentDirections
)。因此,在 homeFragment
中,您要为适配器设置 onclick
侦听器,您应该使用->
adapter.setOnItemClickListener(object : AlarmListAdapter.OnItemClickListener {
override fun onClick(alarm: Alarm) {
Navigation.findNavController(requireView())
.navigate(HomeFragmentDirections.actionHomeFragmentToUpdateFragment(params))
}
override fun onLongClick(alarm: Alarm) {
// preform longclick action here
}
})
并在相应导航图中的UpdateFragment
中添加所需类型的参数(在您的情况下,id
可能是int或String类型)。
我希望你明白我的意思,如果没有,请不要犹豫发表评论。
您可以在 android 开发者网站 here.
上阅读相关内容
NavArgs 没有 returning 一个值,当我尝试通过更新片段中的 setOnClickListener 进行更新时,我才得到这个值:
java.lang.RuntimeException: java.lang.reflect.InvocationTargetException
Caused by: java.lang.IllegalArgumentException: Required argument "currentAlarm" is missing and does not have an android:defaultValue
我需要 return 在 RecyclerView 中选择的警报的 ID,因此默认值在这里没有意义。
NavArgs 在导航视图中正确设置,没有默认值。 model 和 ID 会不会用 autoGenerate 设置错了?还是通过适配器进行这里的问题?
更新片段:
class UpdateFragment : Fragment() {
private val timePickerUtil = TimePickerUtil()
lateinit var binding: FragmentUpdateBinding
private lateinit var alarmViewModel: AlarmViewModel
private val args by navArgs<UpdateFragmentArgs>()
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
binding = FragmentUpdateBinding.inflate(inflater, container, false)
alarmViewModel = ViewModelProvider(this)[AlarmViewModel::class.java]
binding.fragmentBtnUpdateAlarm.setOnClickListener {
updateAlarm()
Navigation.findNavController(requireView())
.navigate(R.id.action_updateFragment_to_homeFragment)
}
return binding.root
}
private fun updateDatabase(id: Int, hour: Int, minute: Int, repeat: Boolean) {
val alarm = Alarm(id, hour, minute, repeat)
alarmViewModel.update(alarm)
}
private fun updateAlarm() {
val timePicker = binding.fragmentUpdateAlarmTimePicker
val id = args.currentAlarm.id
val hour = timePickerUtil.getTimePickerHour(timePicker)
val minute = timePickerUtil.getTimePickerMinute(timePicker)
val repeat = binding.fragmentUpdateAlarmRecurring.isChecked
val alarmManager = AlarmManager(
id,
hour,
minute,
true,
binding.fragmentUpdateAlarmRecurring.isChecked
)
updateDatabase(id, hour, minute, repeat)
alarmManager.cancel(requireContext())
alarmManager.schedule(requireContext())
}
}
适配器:
class AlarmListAdapter() :
RecyclerView.Adapter<RecyclerView.ViewHolder>() {
class MyViewHolder(binding: LayoutAlarmBinding) : RecyclerView.ViewHolder(binding.root)
private var alarmList = ArrayList<Alarm>()
private var onItemClickListener: OnItemClickListener? = null
interface OnItemClickListener{
fun onClick(alarm: Alarm)
fun onLongClick(alarm: Alarm)
}
fun setOnItemClickListener(listener: OnItemClickListener){
onItemClickListener = listener
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
val binding = LayoutAlarmBinding.inflate(LayoutInflater.from(parent.context))
return MyViewHolder(binding)
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
val currentItem = alarmList[position]
val minute = currentItem.minute
holder.itemView.findViewById<TextView>(R.id.tv_alarm_time).text =
if (minute >= 10) {
"${currentItem.hour}:${currentItem.minute}"
} else {
"${currentItem.hour}:0${currentItem.minute}"
}
holder.itemView.setOnClickListener{
if(onItemClickListener != null){
onItemClickListener?.onClick(currentItem)
}
}
holder.itemView.setOnLongClickListener {
if(onItemClickListener != null){
onItemClickListener?.onLongClick(currentItem)
}
true
}
}
override fun getItemCount(): Int {
return alarmList.size
}
fun setData(alarm: List<Alarm>) {
alarmList.clear()
alarmList.addAll(alarm)
notifyDataSetChanged()
}
}
主页片段:
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)
}
adapter.setOnItemClickListener(object : AlarmListAdapter.OnItemClickListener {
override fun onClick(alarm: Alarm) {
Navigation.findNavController(requireView())
.navigate(R.id.action_homeFragment_to_updateFragment)
}
override fun onLongClick(alarm: Alarm) {
val deleteBuilder = AlertDialog.Builder(requireContext())
deleteBuilder.setPositiveButton("Delete") { _, _ ->
alarmViewModel.delete(alarm)
Toast.makeText(context, "Alarm Deleted", Toast.LENGTH_SHORT)
.show()
}
deleteBuilder.setNegativeButton("Cancel") { _, _ ->
}
deleteBuilder.setTitle("Delete Alarm?")
deleteBuilder.create().show()
}
})
return binding.root
}
}
我的闹钟型号:
@Parcelize
@Entity(tableName = "alarm_table")
data class Alarm(
@PrimaryKey(autoGenerate = true)
val id: Int,
val hour: Int,
val minute: Int,
val repeat: Boolean
): Parcelable
Safe args 创建自己的 类(就像这里的 HomeFragmentDirections
)。因此,在 homeFragment
中,您要为适配器设置 onclick
侦听器,您应该使用->
adapter.setOnItemClickListener(object : AlarmListAdapter.OnItemClickListener {
override fun onClick(alarm: Alarm) {
Navigation.findNavController(requireView())
.navigate(HomeFragmentDirections.actionHomeFragmentToUpdateFragment(params))
}
override fun onLongClick(alarm: Alarm) {
// preform longclick action here
}
})
并在相应导航图中的UpdateFragment
中添加所需类型的参数(在您的情况下,id
可能是int或String类型)。
我希望你明白我的意思,如果没有,请不要犹豫发表评论。 您可以在 android 开发者网站 here.
上阅读相关内容