Навигация с помощью safeArgs в Kotlin выдает и выдает ошибку

#android #kotlin #android-safe-args

#Android #kotlin #android-safe-аргументы

Вопрос:

У меня есть фрагмент, к которому можно перейти либо через нижнюю панель навигации без аргументов, либо из другого фрагмента с аргументами. Сама навигация работает отлично, но как только я добавляю свои аргументы, она выходит из строя.

Я не уверен, сколько кода требуется, поэтому извините, если он не завершен:

Это мой фрагмент навигации:

 <navigation 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/navigation"
app:startDestination="@id/homeFragment">

<fragment
    android:id="@ id/homeFragment"
    android:name="fh.wfp2.flatlife.ui.views.HomeFragment"
    android:label="Flatlife"
    tools:layout="@layout/home_fragment" />
<fragment
    android:id="@ id/todoFragment"
    android:name="fh.wfp2.flatlife.ui.views.TodoFragment"
    android:label="Todos">
    <action
        android:id="@ id/action_todoFragment_to_addTodoFragment"
        app:destination="@id/addTodoFragment" />
    <argument
        android:name="taskname"
        app:argType="string" />
    <argument
        android:name="isImportant"
        app:argType="boolean" />
</fragment>
<fragment
    android:id="@ id/addTodoFragment"
    android:name="fh.wfp2.flatlife.ui.views.AddTodoFragment"
    android:label="AddTodoFragment">
    <action
        android:id="@ id/action_addTodoFragment_to_todoFragment"
        app:destination="@id/todoFragment" />


</fragment>
</navigation>
 

Это мой addTodoFragment:

 class AddTodoFragment : Fragment(R.layout.add_task_fragment) {

private lateinit var binding: AddTaskFragmentBinding

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)
 
    binding = AddTaskFragmentBinding.bind(view)
    binding.bAddTodo.setOnClickListener {
        if (binding.etAddTodo.text.isNotEmpty()) {
           // viewModel.onAddTodoClicked(binding.etAddTodo.text.toString(), 
binding.cbImportant.isChecked)
           findNavController().navigate(
                AddTodoFragmentDirections.actionAddTodoFragmentToTodoFragment(
                    binding.etAddTodo.text.toString(), binding.cbImportant.isChecked
                )
            )
        } else {
            Snackbar.make(it, "The task field can't be empty", Snackbar.LENGTH_SHORT).show()
            
        }
    }

}
}
 

Вот как я пытаюсь получить аргументы в TodoFragment.

 private val args: TodoFragmentArgs by navArgs()
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
//setting binding and other onClickListeners but they work fine

//reading args
//this i thought would work because then args only get read if not null
args?.let { //debugger stops here and app crashes
        if(args.taskname.isNotEmpty())
        viewModel.onAddTodoClick(Todo(name = args.taskname, isImportant = args.isImportant))
    }

/*second try which I took directly from developers.android but which doesn't make sense in my case i 
think because the args could be null I guess

val todoName = args.taskname
    val isImportant = args.isImportant
    viewModel.onAddTodoClick(Todo(name = todoName, isImportant = isImportant))
*/

}
 

Это сообщение об ошибке, которое я получаю:

введите описание изображения здесь

Надеюсь, понятно, что я имею в виду, в противном случае я обновлю вопрос. Вероятно, это будет что-то простое, но я не могу понять, в чем дело.

Комментарии:

1. «Это происходит только при переходе к TodoFragment без передачи аргументов» Я не понимаю, как это возможно. Код не будет компилироваться, потому что действие ожидает 2 аргумента.

2. @Onik упомянутое действие не отображается в сценарии без каких-либо аргументов. При навигации без аргументов я перехожу из HomeFragment -> TodoFragment (с нижней навигацией) При навигации с аргументами я перехожу из AddTodoFragment -> TodoFragment.

3. Я считаю, что это проблема. Когда args?.let вызывается при использовании нижней навигации, args инициализируется с задержкой и генерируется исключение.

4. @Onik хм, хорошо. Но с изменением PiyushMaheswari в приведенном ниже ответе это должно сработать, верно? Потому что это инициализируется немедленно, я полагаю? Я попробую это снова, но, к сожалению, раньше это не работало.

5. @Onik спасибо!! Это работает для меня! У меня есть пара других проблем, касающихся логики на моей стороне, но ваш tipp исправил эту проблему. Большое спасибо! Если вы хотите сформулировать ответ, я бы принял его, иначе я бы либо просто обновил свой вопрос, либо опубликовал ответ и отдал вам должное. Знаете ли вы, почему это работает или лучше сформулировано: почему TodoFragmentArgs этого не делает?

Ответ №1:

Так что спасибо @Onik за идею оставить SafeArgs подальше. Мне нужно было сбросить вызов класса SafeArgs для получения аргументов, и теперь это выглядит так. Я думаю, это определенно не самый чистый способ, но я пока не знаю, почему вызов SafeArgs не работает, и я слишком новичок в Kotlin, чтобы написать следующий код более чистым способом. Но пока это работает.

 arguments?.let {
        var myArg1: String? = null
        var myArg2: Boolean
        arguments?.getString("argument1")?.let { arg1->
            myArg1= arg1
        }
        arguments?.getBoolean("argument2")?.let { arg2->
            myArg2= arg2

            if (myArg1!= null)
                //do logis with args
        }

    }
 

Ответ №2:

 val args = arguments?.let {
    SecondFragmentArgs.fromBundle(
        it
    )
}
if (args != null) {
    firstDataList = args.taskName
    secondDataList = args.isImportant
}
 

Вот как должен выглядеть код принимающего фрагмента. Это должно сработать.

Комментарии:

1. findNavController().navigate( FirstFragmentDirections.actionFirstFragmentToSecondFragment(имя задачи, является простым)

2. я пробовал это, но это не сработало. Я все еще получаю тот же код ошибки. (я обновлю сообщение, чтобы код ошибки был виден)

3. Да, я это сделал. Я использую привязку, но синтаксис такой же, как и у меня. Приложение вылетает при переходе к фрагменту без установленных аргументов, поэтому я даже не могу добраться до фрагмента, который отправляет аргументы, если это имеет смысл.

4. Тогда я предполагаю, что причиной может быть логика привязки.

5. Я бы так не подумал, потому что я еще даже не перехожу к этому фрагменту. Если я оставлю принимающий код для аргументов, я смогу нормально перемещаться. Это происходит только при переходе к TodoFragment без передачи аргументов.