관리 메뉴

막내의 막무가내 프로그래밍 & 일상

[안드로이드] Jetpack Navigation Fragment to Fragment direction (젯팩 네비게이션 프래그먼트 화면 전환) + 값 주고받는 방법 본문

안드로이드/코틀린 & 아키텍처 & Recent

[안드로이드] Jetpack Navigation Fragment to Fragment direction (젯팩 네비게이션 프래그먼트 화면 전환) + 값 주고받는 방법

막무가내막내 2020. 6. 26. 17:49
728x90

 

[2021-04-13 업데이트]

 

 

이전에 Jetpack Navigation에 이어서 <action> 태그를 사용하여 프래그먼트끼리 화면전환하는 것을 프로젝트에 적용해봤습니다.

 

먼저 원리 및 <태그> 등 자세한 설명은 제가 쓰지 않고 밑 사이트들에 잘나와있으므로 참고용으로 남깁니다.

 

https://developer.android.com/guide/navigation/navigation-navigate?hl=ko

 

대상으로 이동  |  Android 개발자  |  Android Developers

대상으로 이동하는 것은 NavController 객체를 사용하여 실행되며 이 객체는 NavHost 내에서 앱 탐색을 관리합니다. 각 NavHost에는 그에 대응하는 NavController가 있습니다. NavController를 사용하면 몇 가지

developer.android.com

 

https://developer.android.com/guide/navigation/navigation-getting-started

 

탐색 구성요소 시작하기  |  Android 개발자  |  Android Developers

이 주제는 탐색 구성요소를 설정하고 사용하는 방법을 설명합니다. 탐색 구성요소의 대략적인 개요는 탐색 개요를 참조하세요. 환경 설정 참고: Android 스튜디오에서 탐색을 사용하려면 Android 스

developer.android.com

https://medium.com/harrythegreat/android-navigation-component-%EA%B0%9C%EB%85%90%EA%B3%BC-%ED%8A%9C%ED%86%A0%EB%A6%AC%EC%96%BC-1-5ac6ac081643

 

Android Navigation Component 개념과 튜토리얼 — 1

Jetpack과 함께 소개된 안드로이드 네비게이션은 기존 정말 복잡하고 난해하고 코드를 스파게티로 만들어줬던 Fragment와 Activity간 구현을 심플하고 안정적으로 이동할 수 있도록 도와주는 컴포넌��

medium.com

https://beomseok95.tistory.com/190

 

Jetpack - Navigation

Jetpack - Navigation 네비게이션은 앱의 목적지, 즉 사용자가 탐색 할 수있는 앱의 어느 곳에서나 발생합니다 . 이러한 대상은 작업을 통해 연결됩니다 . 네비게이션 그래프는 당신의 목적지�

beomseok95.tistory.com

 

https://brunch.co.kr/@oemilk/210

 

Android Navigation

Android Jetpack Navigation | 인앱 탐색에 필요한 모든 것을 처리합니다. Navigation은 앱 내의 화면 전환을 좀 더 쉽게 구현하고 화면 흐름을 시각화해서 볼 수 있도록 해주는 프레임워크입니다. 기존의 st

brunch.co.kr


 

[1. gradle 추가]

app 수준 gradle

 // navigation
    implementation 'androidx.navigation:navigation-fragment-ktx:2.2.2'
    implementation 'androidx.navigation:navigation-ui-ktx:2.2.2'
apply plugin: 'kotlin-kapt'
apply plugin: "androidx.navigation.safeargs"

맨 밑에거 추가(project 수준 gradle)

dependencies {
        classpath 'com.android.tools.build:gradle:3.6.3'
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
        classpath 'com.google.gms:google-services:4.2.0'
        classpath "androidx.navigation:navigation-safe-args-gradle-plugin:2.3.0-rc01"
        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
    }

 


[2. Fragment 생성]

전 바텀네비게이션이 적용된 상태에서 바텀네비게이션에 종속되어있는 프래그먼트에서 다른 프래그먼트를 띄워줄 용도로 사용했습니다.

HomeFragment -> SearchFragment 로 이동할 것 입니다.

 

HomeFragment 입니다.

package com.mtjin.nomoneytrip.views.home

import androidx.lifecycle.Observer
import androidx.navigation.NavDirections
import androidx.navigation.fragment.findNavController
import com.mtjin.nomoneytrip.R
import com.mtjin.nomoneytrip.base.BaseFragment
import com.mtjin.nomoneytrip.databinding.FragmentHomeBinding
import org.koin.androidx.viewmodel.ext.android.viewModel

class HomeFragment : BaseFragment<FragmentHomeBinding>(R.layout.fragment_home) {
    private val viewModel: HomeViewModel by viewModel()

    override fun init() {
        binding.vm = viewModel
        initViewModelCallback()
    }

    private fun initViewModelCallback() {
        with(viewModel) {
            goSearch.observe(this@HomeFragment, Observer {
                val direction: NavDirections =
                    HomeFragmentDirections.actionBottomNav1ToSearchFragment()
                findNavController().navigate(direction)
            })
        }
    }

}

 

 

SearchFragment 입니다.

package com.mtjin.nomoneytrip.views.search

import com.mtjin.nomoneytrip.R
import com.mtjin.nomoneytrip.base.BaseFragment
import com.mtjin.nomoneytrip.databinding.FragmentSearchBinding

class SearchFragment : BaseFragment<FragmentSearchBinding>(R.layout.fragment_search) {
    override fun init() {

    }
}

 

 


 

 

[3. Navigation 그래프 설정]

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

    <fragment
        android:id="@+id/bottom_nav_1"
        android:name="com.mtjin.nomoneytrip.views.home.HomeFragment"
        android:label="BottomNavFragment1"
        tools:layout="@layout/fragment_home">
        <action
            android:id="@+id/action_bottom_nav_1_to_search_fragment"
            app:destination="@id/search_fragment"
            app:launchSingleTop="true" />
    </fragment>
    <fragment
        android:id="@+id/bottom_nav_2"
        android:name="com.mtjin.nomoneytrip.views.community.CommunityFragment"
        android:label="BottomNavFragment2"
        tools:layout="@layout/fragment_community" />
    <fragment
        android:id="@+id/bottom_nav_3"
        android:name="com.mtjin.nomoneytrip.views.ticketoff.TicketOffFragment"
        android:label="BottomNavFragment3"
        tools:layout="@layout/fragment_ticket_off" />
    <fragment
        android:id="@+id/bottom_nav_4"
        android:name="com.mtjin.nomoneytrip.views.profile.ProfileFragment"
        android:label="BottomNavFragment4"
        tools:layout="@layout/fragment_profile" />
    <fragment
        android:id="@+id/search_fragment"
        android:name="com.mtjin.nomoneytrip.views.search.SearchFragment"
        android:label="SearchFragment"
        tools:layout="@layout/fragment_search" />
</navigation>

 

네비게이션에서 코드나 UI툴로 목적지를 정해주면됩니다. 인자 전달도 필요할 경우 <argument> 도 설정 가능하고 딥링크 기능도 있습니다. 이외에 다양한 옵션도(global , 백스택 등) 설정가능한데 해당 부분들은 맨위의 참고사이트에 가면 볼 수 있습니다.

 

저는 일단 프래그먼트 전환용으로만 사용했으므로 <action> 태그만 설정했고 singleTop 을 설정해주었습니다.

 

[프로젝트 진행하면서 arguments 나 global, popUpTo, popUpToIncursive, 트랜잭션애니메이션 등 다른 옵션들도 사용할텐데 지금은 사용할 이유가 없어 안했습니다. 상단 참고사이트가면 자세히 알 수 있습니다. 

간단하게만 설명하면 다음과 같습니다.]

 

한 대상에서 다른 대상으로 이동할 때 대상을 팝하려면 app:popUpTo 속성을 연결된 <action> 요소에 추가합니다. app:popUpTo는 navigate() 호출의 일부로 백 스택에서 몇 개의 대상을 팝하도록 탐색 라이브러리에 알려줍니다. 속성값은 스택에 남아 있어야 하는 가장 최근 대상의 ID입니다.

또한, app:popUpToInclusive="true"를 포함하여 app:popUpTo에 지정된 대상이 백 스택에서 삭제될 수도 있다는 것을 나타낼 수도 있습니다.

 

HomeFragment -> SearchFragment

 

이렇게 네비게이션 설정을 하고 클린 후 빌드하면 데이터바인딩 할때처럼 다음과 같이 클래스를 자동으로 만들어줍니다. ( 꼭 빌드를 해주어야합니다 주의!!)

  val direction: NavDirections =
                    HomeFragmentDirections.actionBottomNav1ToSearchFragment()

 

 

[4. HomeFragment에 이동하는 코드 추가]

HomeFragment 코드입니다.

navigation 설정에 의해 HomeFragmentDirections 라는 코드를 자동으로 만들어주었고 <action> 태그 아이디 값에 맞게 actionBottomNav1ToSearchFragment() 라는 메소드도 만들어주었습니다.

만약 arguments 가 있다면 매개변수를 인자로 넘깁니다. 그리고 받는쪽에서도 arguments 를 받는 코드가 있게될겁니다.

 

이동관련된 정보 NavDircetions 를 정했다면

findNavController().navigate(direction) 로 해당 정보를 실행합니다. 

 

자세한 사용법은 가장 상단에 첨부한 참고사이트 참고!

package com.mtjin.nomoneytrip.views.home

import androidx.lifecycle.Observer
import androidx.navigation.NavDirections
import androidx.navigation.fragment.findNavController
import com.mtjin.nomoneytrip.R
import com.mtjin.nomoneytrip.base.BaseFragment
import com.mtjin.nomoneytrip.databinding.FragmentHomeBinding
import org.koin.androidx.viewmodel.ext.android.viewModel

class HomeFragment : BaseFragment<FragmentHomeBinding>(R.layout.fragment_home) {
    private val viewModel: HomeViewModel by viewModel()

    override fun init() {
        binding.vm = viewModel
        initViewModelCallback()
    }

    private fun initViewModelCallback() {
        with(viewModel) {
            goSearch.observe(this@HomeFragment, Observer {
                val direction: NavDirections =
                    HomeFragmentDirections.actionBottomNav1ToSearchFragment()
                findNavController().navigate(direction)
            })
        }
    }

}

 

 

이렇게 하면 이제 프래그먼트에서 프래그먼트로 전환이 가능해집니다. 

그리고 저는 goSearch 를 SingleLiveEvent를 사용하였는데 MutableLiveData 사용시 무한 옵저빙이되어 네비게이션을 활용한 프래그먼트 화면전환에 에러사항이 생길 수 있으니 주의해야합니다. (제가 그렇게 삽질했거든요..ㅋㅋㅋ)

 

백스택 관리와 유지보수면에서 유용한 것 같습니다 ㅎㅎ

간단하게 한 것들을 참고용으로 포스팅해보았는데요. 다른 기능 사용시 추가로 더 남겨보도록 하겠습니다.

 

 

 


[2020-08-29 업데이트]

추가로 프래그먼트 이동하면서 값을 주고받을때는 다음과 같이 action과 arguments 를 설정하시면 됩니다.

String 값을 주고받는 예시입니다.

<fragment
        android:id="@+id/search_fragment"
        android:name="com.mtjin.nomoneytrip.views.search.SearchFragment"
        android:label="SearchFragment"
        tools:layout="@layout/fragment_search" >
        <action
            android:id="@+id/action_search_fragment_to_localpage_fragment"
            app:destination="@id/localpage_fragment"
            app:launchSingleTop="true" />
    </fragment>

    <fragment
        android:id="@+id/localpage_fragment"
        android:name="com.mtjin.nomoneytrip.views.localpage.LocalPageFragment"
        android:label="LocalPageFragment"
        tools:layout="@layout/fragment_local_page" >
        <argument
            android:name="local"
            app:argType="string" />
    </fragment>

 

[Sender]

findNavController().navigate(
                    SearchFragmentDirections.actionSearchFragmentToLocalpageFragment(local)
                )

[Receiver]

val safeArgs: LocalPageFragmentArgs by navArgs()
safeArgs.local

 

 

댓글과 공감은 큰 힘이 됩니다. 감사합니다!!

728x90
Comments