Получить аргумент из графика навигации - PullRequest
0 голосов
/ 11 октября 2018

У меня есть график навигации следующим образом:

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

    <fragment
        android:id="@+id/jobsFragment"
        android:name=".JobsFragment"
        android:label="JobsFragment">

        <action
            android:id="@+id/action_jobsFragment_to_newJobDetailsActivity"
            app:destination="@id/newJobDetailsActivity" />

    </fragment>

    <fragment
        android:id="@+id/historyFragment"
        android:name=".HistoryFragment"
        android:label="HistoryFragment" />

    <fragment
        android:id="@+id/profileFragment"
        android:name=".ProfileFragment"
        android:label="ProfileFragment" />

    <activity
        android:id="@+id/newJobDetailsActivity"
        android:name=".NewJobDetailsActivity"
        android:label="activity_new_job_details"
        tools:layout="@layout/activity_new_job_details">

        <!-- This is what I want a reference to -->
        <argument
            android:name="jobId"
            app:argType="string" />

    </activity>

</navigation>

Цель : получить значение newJobDetailsActivity 'argument name, jobId, программно безнужна ссылка на action.С текущим API я могу установить jobId через action без необходимости знать литерал имени строки.Это хорошо, но не идеально для случаев, когда я хочу, чтобы вызывающий абонент мог перемещаться к месту назначения, не зная, к какому компоненту подключен вызывающий.Это легче объяснить с помощью кода.Давайте рассмотрим два сценария, которые я пытаюсь решить.

Сценарий A

Предположим, у меня есть RecyclerView.ViewHolder, в котором есть некоторый кодкоторый перемещается от Fragment с именем JobsFragment к Activity с именем NewJobDetailsActivity при нажатии.

itemView.setOnClickListener {
    itemView.findNavController().navigate(
        JobsFragmentDirections.ActionJobsFragmentToNewJobDetailsActivity(jobId)
    )
}

Это замечательно, если RecyclerView.ViewHolder существует только в JobsFragment,но если я захочу повторно использовать его из дополнительных Fragment или Activity в будущем, мой код перестанет работать, потому что держатель представления должен ссылаться на JobsFragmentDirections action, чтобы передать аргумент jobId.

Сценарий B

Предположим, мне нужно создать PendingIntent для уведомления, и я хочу сделать это с помощью API архитектуры навигации.

NavDeepLinkBuilder(context)
    .setGraph(R.navigation.main_graph)
    .setDestination(R.id.newJobDetailsActivity)
    .setArguments(Bundle().apply {
        putString("jobId", jobId)
    })
    .createPendingIntent()

В этом случае мне не нужна ссылка на action, но на самом деле ситуация еще хуже, потому что я не могу найти ссылку на argument name в main_graph, поэтомуЯ вынужден указать это, используя строковый литерал.Гадость.

tl; dr: Кто-нибудь знает способ улучшить эти два сценария?Есть ли способ программно получить ссылку на argument из графика навигации?

Зависимости : android.arch.navigation:navigation-fragment-ktx:1.0.0-alpha06, android.arch.navigation:navigation-ui-ktx:1.0.0-alpha06

Плагин: androidx.navigation.safeargs

Ответы [ 2 ]

0 голосов
/ 11 октября 2018

Как упоминал Эмре в своем ответе, есть конструктор args, который можно вызывать из сгенерированного класса назначения *Args, который затем можно построить с аргументом (аргументами) и преобразовать в Bundle.Путь к этому не самый красивый, но он добивается того, чего я пытаюсь достичь.Обновленные реализации:

Сценарий A

itemView.setOnClickListener {
    itemView.findNavController().navigate(
        R.id.newJobDetailsActivity,
        NewJobDetailsActivityArgs.Builder(jobId)
            .build()
            .toBundle()
    )
}

Сценарий B

NavDeepLinkBuilder(context)
    .setGraph(R.navigation.main_graph)
    .setDestination(R.id.newJobDetailsActivity)
    .setArguments(
        NewJobDetailsActivityArgs.Builder(jobId)
            .build()
            .toBundle()
    )
    .createPendingIntent()

Обновление : Касание уведомления с помощью PendingIntent, созданного с помощью NavDeepLinkBuilder, на самом деле не работает.Аргумент не передается в пункт назначения Activity.Хотите знать, если это ошибка в структуре навигации.Отслеживание этого вопроса здесь .

0 голосов
/ 11 октября 2018

Для второго сценария вы можете использовать что-то вроде этого:

val args = JobsFragmentArgs.Builder(id).build().toBundle()
NavDeepLinkBuilder(context)
    .setGraph(R.navigation.main_graph)
    .setDestination(R.id.newJobDetailsActivity)
    .setArguments(args)
    .createPendingIntent()

Лично для первого сценария я бы рекомендовал передать прослушиватель по щелчку из фрагмента / действия, которое создает адаптер, и установитьслушатель держателя представления на привязке.Затем вы можете по-другому реализовать на клик для других фрагментов / действий.

...