Компонент архитектуры навигации Android: как передать данные пакета в startDestination

У меня есть деятельность, в которой есть NavHostFragment. Деятельность получает определенные ценности в своем намерении. Я хочу передать эти данные первому фрагменту, то есть startDestination графа навигации. Я не смог найти никакой документации по этому поводу.

Я уже прошел через этот вопрос на SO, но я не могу найти метод addDefaultArguments для navController.getGraph().

Можно ли передать бандл на startDestination?

Я просто проверил 1.0.0-alpha07 и 1.0.0-alpha08, у нас есть addDefaultArguments(), и он отлично работает как на Java, так и на kotlin. Но для 1.0.0-alpha09 они удалили addDefaultArguments(), это могло быть временным и скоро должно быть исправлено. Так что пока вы можете использовать 1.0.0-alpha08.

Anmol 26.12.2018 07:37

@Anmol, да, похоже, это так. Я не понимаю причину удаления addDefaultArguments () в 1.0.0-alpha09. А пока я вернулся к 1.0.0-alpha08.

Praveen Singh 28.12.2018 07:32
stackoverflow.com/q/53928500/7972699, если у вас есть идеи, ответьте здесь
Anmol 28.12.2018 07:38

@Anmol Я добавил ответ согласно последней документации по навигации. stackoverflow.com/a/57607441/3036824

Praveen Singh 22.08.2019 12:42
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
14
4
13 587
9
Перейти к ответу Данный вопрос помечен как решенный

Ответы 9

Я тоже не могу найти этот метод. Его не существует в документации по компонентам архитектуры.

Но есть еще один способ установить аргументы для начального пункта назначения:

// Kotlin Code, in Fragment
with(findNavController().graph) {
    get(startDestination).addArgument(...)
}

Ну что ж, это документ Kotlin, я только что взглянул на стандартную (Java) документацию ... Но странно, что java и kotlin api не предлагают одинаковые функции.

the_dani 26.12.2018 00:16

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

Anmol 26.12.2018 06:42

Я просто проверяю 1.0.0-alpha07, у нас есть addDefaultArguments(), и он отлично работает как на Java, так и на kotlin @the_dani

Anmol 26.12.2018 07:35

Так они удалили это в alpha09 в java api?

the_dani 26.12.2018 16:30

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

Anmol 26.12.2018 16:50

я также столкнулся с той же проблемой,

Вот как я решил это:

  1. Удалять - настройка xml NavHostFragment из your_activity.xml: т.е. удалить app: navGraph = "@ navigation / nav_graph

Вот как должен выглядеть ваш XML.

        <fragment
        android:id = "@+id/nav_host"
        android:name = "androidx.navigation.fragment.NavHostFragment"
        android:layout_width = "match_parent"
        android:layout_height = "match_parent"
        app:defaultNavHost = "true"
        />
  1. Добавлять Настройка NavHostFragment Программно в onCreate() активности. И передать данные пакета с помощью NavGraph.addDefaultArguments(bundleData)api

        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContentView(R.layout.editor_layout)
            setupNavigation()
        }
    
        private fun setupNavigation() {
            val navHostFragment = nav_host as NavHostFragment
            val navController = navHostFragment.navController
            val navInflater = navController.navInflater
            val graph = navInflater.inflate(R.navigation.nav_graph)
            graph.addDefaultArguments(intent!!.extras!!) // This is where you pass the bundle data from Activity to StartDestination 
            navHostFragment.navController.graph = graph
        }
    

Обновлено:

Зависимости в моем файле Project Gradle:

dependencies {

    def nav_version = "1.0.0-alpha08"

    implementation "android.arch.navigation:navigation-fragment:$nav_version" // use -ktx for Kotlin
    implementation "android.arch.navigation:navigation-ui:$nav_version" // use -ktx for Kotlin}
}

ЗАМЕТКА: В версии 1.0.0-alpha09 компонента навигации по какой-то причине у Google нет метода, так как addDefaultArguments() может быть скоро исправлен. Но в более низких версиях есть метод addDefaultArguments(). Я проверил и в java, и в kotlin, поэтому попробуйте использовать 1.0.0-alpha07 или 1.0.0-alpha08.

Я пытаюсь сделать это на Java. Я выполнил ваши шаги, проблема в graph.addDefaultArguments, такого метода под названием addDefaultArguments не существует.

Praveen Singh 25.12.2018 16:44

@PraveenSingh проверьте, можете ли вы импортировать класс NavDestination в свой проект. Ссылка: developer.android.com/reference/kotlin/androidx/navigation/…

Anmol 25.12.2018 17:40

Я проверил исходный код и увидел, что есть много изменений, касающихся пункта назначения и аргументов навигации. Я думаю, что правильный способ передать аргументы для начала назначения - использовать метод addArgument, примерно так:

val argument1 = 1 //First value
val argument2 = "Value" //Second value
val navArgument1=NavArgument.Builder().setDefaultValue(argument1).build()
val navArgument2=NavArgument.Builder().setDefaultValue(argument2).build()
navController.getGraph().addArgument("Key1",navArgument1)
navController.getGraph().addArgument("Key2",navArgument2)

Может быть, есть способ получше, но я его не нашел.

class MainActivity : BaseActivity()  {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val navHostFragment = container as NavHostFragment
        val inflater = navHostFragment.navController.navInflater
        val graph = inflater.inflate(R.navigation.main_nav)

        var data : Data  = intent.getParcelableExtra("DATA") as Data
        var bundle : Bundle = Bundle()
        bundle.putParcelable("DATA", data)
        graph.addDefaultArguments(bundle)
        graph.addDefaultArguments(intent!!.extras!!)
        navHostFragment.navController.graph = graph

    }
}

Добавьте приведенный выше код в Activity для отправки данных с помощью навигации

override fun onActivityCreated(savedInstanceState: Bundle?) {
        super.onActivityCreated(savedInstanceState)

        var data = NavHostFragment.findNavController(this).graph.defaultArguments.getParcelable("DATA") as Booking

}

Добавьте приведенный выше код в сторону фрагмента

вы можете добавить аргументы в свой график следующим образом

<fragment
  android:id = "@+id/exampleFragment"
  android:label = "example_fragment"
  android:name = "com.example.yourapp.ui.ExampleFragment"
  tools:layout = "@layout/example_fragment">
<argument
  android:name = "exampleArgs"
  app:argType = "reference"
  android:defaultValue = "@string/example"/>
</fragment>

https://developer.android.com/guide/navigation/navigation-pass-data

Навигация 1.0.0

        val navHostFragment = root_nav_host_fragment as NavHostFragment
        val navController = navHostFragment.navController
        val navInflater = navController.navInflater
        val graph = navInflater.inflate(R.navigation.navigation)
        val sectionId = intent.getIntExtra(KEY_SECTION_ID, -1)
        val bundle = bundleOf(KEY_SECTION_ID to sectionId)
        navHostFragment.navController.setGraph(graph, bundle)
Ответ принят как подходящий

Отвечая на свой вопрос, я нашел правильный подход в обновленной документации по навигации.

На момент написания этого ответа я использую Navigation 2.2.0-alpha01

Если вы хотите передать некоторые данные в начальную точку назначения непосредственно в качестве аргументов активности хоста, вам необходимо вручную установить график навигации хоста внутри метода onCreate () активности хоста, как показано ниже:

Получите navController:

val navController by lazy { findNavController(R.id.<your_nav_host_id>) }

Затем в onCreate() активности хоста

val bundle = Bundle()
bundle.putString("some_argument", "some_value")
navController.setGraph(R.navigation.<you_nav_graph_xml>, bundle)

Или, если вы хотите передать все дополнительные функции намерения, как и в startDestination:

navController.setGraph(R.navigation.<you_nav_graph_xml>, intent.extras)

Поскольку intent.extras вернет только Bundle

When you are setting the navGraph using setGraph() method, you should avoid setting the app:NavGraph attribute in the NavHostFragment definition, because doing so results in inflating and setting the navigation graph twice.

Читая эти аргументы во фрагменте startDestination:

Если вы используете Плагин Safe Args (что очень рекомендуется), то в вашем фрагменте:

private val args by navArgs<DummyFragmentArgs>()

Плагин Safe Args сгенерирует класс Args, добавив Args к имени вашего фрагмента. Например, если ваш фрагмент называется DummyFragment, тогда Safe Args сгенерирует класс с именем DummyFragmentArgs.

где navArgs<> - это функция расширения, определенная в Android KTX

Если вы не используете Android KTX, вы можете получить объект args, например:

val args = DummyFragmentArgs.fromBundle(arguments!!)

После того, как вы получили объект arguments, вы можете просто получить свои аргументы:

args.someArgument

Обратите внимание, как мы передали "some_argument" в качестве аргумента и читаем его как someArgument, используя Safe Args

Если вы не используете Safe Args (хотя нет причин не использовать его), вы можете получить доступ к своим аргументам следующим образом:

arguments?.getString("some_argument")

Все это задокументировано в документации по переходу на компонент навигации здесь: https://developer.android.com/guide/navigation/navigation-migrate#pass_activity_destination_args_to_a_start_destination_fragment

Я нашел решение после некоторого исследования. Он работает с последней версией библиотеки навигации. См. Приведенный ниже код:

  1. Добавьте это в свой макет занятий. Примечание. Мы не устанавливаем аргумент приложение: navGraph в XML-файле. Мы установим его динамически.

    <fragment
        android:id = "@+id/fragment"
        android:name = "androidx.navigation.fragment.NavHostFragment"
        android:layout_width = "match_parent"
        android:layout_height = "0dp"
        android:layout_weight = "1"
        app:defaultNavHost = "true" />
    
  2. В java-файле активности напишите приведенный ниже код и внесите соответствующие изменения. Используйте NavArgument, чтобы передать значение аргумента и добавить аргумент в свой пользовательский Navgraph, а затем установить график.

    public class YourActivity extends AppCompatActivity {
         private NavArgument nameArg, mailArg;
    
         @Override
         protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.profile);
            nameArg = new NavArgument.Builder().setDefaultValue("your name").build();
            mailArg = new NavArgument.Builder().setDefaultValue("your email id").build();
            NavController navController = Navigation.findNavController(this, R.id.fragment);
            NavInflater navInflater = navController.getNavInflater();
            NavGraph navGraph = navInflater.inflate(R.navigation.nav_profile_graph);
            navGraph.addArgument("your name key", nameArg);
            navGraph.addArgument("your mail key", mailArg);
            navController.setGraph(navGraph);
        }
    }
    
  3. Напишите график навигации ниже и добавьте те же ключи аргументов в начальный фрагмент.

    <?xml version = "1.0" encoding = "utf-8"?>
    <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/nav_graph"
       app:startDestination = "@+id/profile_basic">
    
       <fragment
          android:id = "@+id/profile_basic"
          android:name = "com.yourpackage.ProfileBasicFragment"
          android:label = "Profile Basic"
          tools:layout = "@layout/fragment_profile_basic">
    
          <argument android:name = "your name key"
              app:argType = "string"/>
    
          <argument android:name = "your mail key"
              app:argType = "string"/>
    
       </fragment>
    </navigation>
    
  4. В вашем фрагменте просто выберите значения с помощью функции getArguments ().

    String name = getArguments().getString("your name key");
    String mail = getArguments().getString("your mail key");
    

Хотя это поздний ответ, существует очень простой способ передачи пакетов с помощью контроллера навигации / архитектуры навигации:

Фрагмент, который отправит данные

//Best to put in onViewCreated
val navController = findNavController()

//Put in code where you want to start navigation
val b = Bundle()
b.putString("key_1", "Data 1")
b.putString("key_2", "Data 2")

navController.navigate(R.id.action_signupFragment_to_signinFragment,b)

Фрагмент, который получит данные

val data_1: String = arguments?.getString("key_1")?:""
val data_1: String = arguments?.getString("key_2")?:"" 

В зависимости от типа данных, которые вы отправляете, вам необходимо обновить безопасный вызов или сделать переменные обнуляемыми.

Другие вопросы по теме