[Android kotlin] 심리테스트 어플 만들기 (Jetpack navigation/Binding/Bundle)

김민주·2022년 10월 13일
0

Android

목록 보기
1/21
post-thumbnail



Activity를 여러 개 만드는 것보다
하나의 Activity와 여러 개의 Fragment로 만들면 좋은 점

👍 화면전환 navigation이 처리해줘서 편리하다.
👍 구글이 밀고 있다.

기존의 화면 전환은 FragmentManager를 이용해서 트랜잭션 add,replace,commit 를 통해 이루어졌지만, Jetpack의 navigation을 이용하도록 권장했다.

  • NavHost
    Fragment 네비게이션을 위한 빈 창. = NavigationHostFragment
  • NavController
    NavHostFragment는 개별적으로 NavController를 가짐.
    네비게이션 그래프 정보를 이용하여 Fragment 간 action을 담당.
  • NavGraph
    Fragment들의 이동을 한 눈에 볼 수 있는 xml.
    Navigation Resource file.



Android developer 사이트 참고

이미지 다운 및 참고한 영상



안드로이드 navigation Jetpack 사용법




1. dependencies 추가

2. 네비게이션 directory 생성

3. Navigation Resource File 생성

GUI 한 눈에 확인 가능

4. 액티비티 xml에 NavHostFragment 추가

 3에서 만든 네브리소스파일을 app:navGraph="@navigation/nav_graph" 로 연결

5. fragment 사이의 관계 정해주기

   에뮬레이터 새로깔기 귀찮아서 xml 대충 맞췄으니 못본척하기..

   Xcode 스토리보드처럼 한 눈에 보이는 기능이 있었다니...내졸작다시할래요....



<fragment
        android:id="@+id/mainFragment"
        android:name="com.example.lovetest.Fragment.MainFragment"
        android:label="fragment_main"
        tools:layout="@layout/fragment_main" >
        <action
            android:id="@+id/action_mainFragment_to_questionFragment"
            app:destination="@id/questionFragment" />

프래그먼트에 action이 들어간 것을 확인할 수 있다.
액션 id 생성과 목적지는 다음 프래그먼트라는 것을 지정해준다.



🧐 Build error

One or more issues found when checking AAR metadata values:

The minCompileSdk (33) specified in a
dependency's AAR metadata (META-INF/com/android/build/gradle/aar-metadata.properties)
is greater than this module's compileSdkVersion (android-32).
Dependency: androidx.core:core:1.9.0.
AAR metadata file: C:\Users\minju.gradle\caches\transforms-3\3a73d4c1cdf65c14c4dc712518275464\transformed\core-1.9.0\META-INF\com\android\build\gradle\aar-metadata.properties.


급 빌드 오류

현재 사용하는 라이브러리의 최소 sdk가 33은 필요하다고 하는 것이니

Build.gradle 에서 compileSdk 와 targetSdk를 32로 높여주도록 하자.


6. MainActivity에 NavController 연결

class MainActivity : AppCompatActivity() {

  //지금 아니라 나중에 정의할 것임 lateinit
  lateinit var navController : NavController

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

      val navHostController = supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as NavHostFragment
      navController = navHostController.navController

  }
}

lateinit : 지금 아니라 나중에 정의하겠다는 예약어
꼭 타입을 명시해주어야 한다!


7. MainFragment에서 호스트프래그먼트 연결



🧐 Runtime error

Caused by: java.lang.IllegalStateException: Activity com.example.lovetest.MainActivity@a6961e1 does not have a NavController set on

알고보니 Fragment는 주석처리된 문장이 잘 작동하지만
androidx.fragment.app.FragmentContainerView 는
supportFragmentManager의 findFragmentById 함수를 통해 id를 지정해줘야했다

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        //뷰가 만들어지고 나서 생성되는 함수
        super.onViewCreated(view, savedInstanceState)

        //navController = Navigation.findNavController(view)
        val navHostFragment =
            requireActivity().supportFragmentManager.
            findFragmentById(R.id.nav_host_fragment) as NavHostFragment
        val navController = navHostFragment.navController
        
    }

이렇게 supportFragmentManager를 통해 id를 typecasting 하고 연결시켜준다.
왜인지 support가 뜨지 않아 액티비티가 있다는 것을 보장해주는
requireActivity() 를 적어주었다.

View Binding

Build.gradle에서 buildFeatures 안에 뷰 바인딩 true 후 Sync.

lateinit var binding : FragmentMainBinding

override fun onCreateView(

        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {

        //바인딩 초기화
        binding = FragmentMainBinding.inflate(inflater, container,false)
        // 원래 레이아웃뷰 반환은 이거지만 바인딩 사용하므로 바꿔줌
        //return inflater.inflate(R.layout.fragment_main, container, false)
        return binding.root
    }

프래그먼트이름Binding.inflate 함수를 통해 Fragment에서의 바인딩 초기화


8. navigate함수를 이용하여 액션넣기



뷰바인딩으로 버튼 접근하여 버튼에 navController 액션 이동달기

🎇 Action에 Animations 추가

그냥 프래그먼트가 전환되면 너무 인위적이니까 애니메이션을 추가해주자
nav_graph에서 화살표누르고 애니메이션들을 추가해줌


👆 OnClickLister 인터페이스 상속받아 사용하기

그냥 객체의 setOnClickListener 함수를 이용해도 되지만,

Activity에 View.OnClickLister 인터페이스를 상속받아 사용하면
여러 개의 버튼들도 한 번에 처리할 수 있고 훨씬 간편해진다🥰

class SelectionFragment : Fragment() , View.OnClickListener{

프래그먼트에 상속을 받으면,

override fun onClick(v: View?) {

함수를 오버라이딩 하라고 나온다.

R.id.btn_pre ->{
               navController.popBackStack()
            }

Fragment는 이동할 때마다 Back stack에 쌓인다.
⬅️ 뒤로가기를 누를 시 하나씩 pop 시키는 것이므로 popBackStack 메소드를 이용한다.

🔁 Fragment 간의 데이터 전달

  • Bundle 클래스
    번들은 Map형태의 데이터 묶음. Key 값은 String, value는 Any? 이다.

    - bundleOf()는 Bundle을 만들어서 리턴해주는 함수

    fun navigateWithIndex(idx: Int) {
        // val bundle2:Bundle= bundleOf("index" to i)

        val bundle = Bundle()
        bundle.putInt("index",idx)

        navController.navigate(R.id.action_selectionFragment_to_resultFragment, bundle)
    }

index를 번들로 담아 result프래그먼트에게 이동 시 함께 전달한다.


to가 자꾸 빨간색떠서 다들 잘 되는데 왜 나만...?
putInt 함수로 넣어주었다!!^^

😓추가 : anko 라이브러리 설치안해서 그런거였음...!
..근데 19년도에 없어졌다고 한다



그러면 data를 받아야하는 ResultFragment에서는

class ResultFragment : Fragment() {

    var option = -1
    
    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {

        option = arguments?.getInt("index")?:-1 //만약null이 전달되면 -1

        // Inflate the layout for this fragment
        return inflater.inflate(R.layout.fragment_result, container, false)

    }
}

arguments로 key값 인덱스를 통해 getInt 함수로 value를 받아오면 된다.

엘비스 연산자를 통해 null일 경우를 대비하자








만든 어플의 최종 심리테스트 결과 AVD 캡처화면

끝!

profile
𝐃𝐨𝐧'𝐭 𝐛𝐞 𝐚 𝐩𝐫𝐨𝐜𝐫𝐚𝐬𝐭𝐢𝐧𝐚𝐭𝐨𝐫💫

0개의 댓글