2주차. FLO 앱 클론 코딩 - Activity & Fragment 전환

변현섭·2023년 9월 27일
0

5th UMC Android Study

목록 보기
2/10

✅ 2주차 목표

  • Activity 전환과 Fragment 전환을 구현할 수 있다.
  • 전환 과정에서 데이터를 전달하고 이를 활용할 수 있다.
  • Toast 메시지를 출력할 수 있다.

>> 실습 코드 링크

1. Activity 전환 및 데이터 전달

① data binding을 사용하기 위해 activity_song.xml 파일의 내용을 layout 컨테이너로 감싼다.

  • 루트 컨테이너에 우클릭 > Show Context Actions를 클릭한 후 Convert to data binding layout을 클릭하면 된다.

② SongActivity를 아래와 같이 수정한다.

class SongActivity : AppCompatActivity() {

    lateinit var binding : ActivitySongBinding

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivitySongBinding.inflate(layoutInflater)
        setContentView(binding.root)

        if(intent.hasExtra("title") && intent.hasExtra("singer")){
            binding.songMusicTitleTv.text = intent.getStringExtra("title")
            binding.songSingerNameTv.text = intent.getStringExtra("singer")
        }

        binding.songDownIb.setOnClickListener {
            finish()
        }

        binding.songMiniplayerIv.setOnClickListener {
            setPlayerStatus(true)
        }

        binding.songPauseIv.setOnClickListener {
            setPlayerStatus(false)
        }


    }

    fun setPlayerStatus (isPlaying : Boolean){
        if(isPlaying){ // 재생중
            binding.songMiniplayerIv.visibility = View.GONE
            binding.songPauseIv.visibility = View.VISIBLE
        } else { // 일시정지
            binding.songMiniplayerIv.visibility = View.VISIBLE
            binding.songPauseIv.visibility = View.GONE
        }
    }
}
  • hasExtra: intent에 title 또는 singer라는 이름의 데이터가 있는지 확인하여 true/false를 반환한다.
  • getStringExtra: MainActivity의 재생 바를 클릭했을 때 title과 singer라는 이름으로 전달 받은 값을 반환한다.
  • finish(): 액티비티를 종료한다.
  • setPlayerStatus()
    • 일시정지 아이콘을 클릭하면, 플레이어 상태를 false로 설정하며, 재생 아이콘이 나타나게 한다.
    • 반대로, 재생 아이콘을 클릭하면, 플레이어 상태를 true로 설정하고, 일시정지 아이콘이 나타나게 한다.

코드를 실행시켜보자. 재생바를 눌렀을 때, 노래의 제목과 가수가 SongActivity에 나타나야 한다.

2. Fragment 전환 및 데이터 전달

fragment_home.xml 파일의 home_album_img_iv1 이미지 뷰의 src 속성을 아래와 같이 변경한다.

android:src="@drawable/img_album_exp2"

HomeFragment의 라일락 이미지를 클릭했을 때 AlbumFragment로 이동해야 하며, 이 때 가수와 노래 제목에 대한 데이터가 전달되어야 한다. Fragment를 데이터 전달과 함께 전환하는 방법 중 몇가지만 소개해보도록 하겠다. (여기서, HomeFragment는 데이터를 전달하는 Fragment, AlbumFragment는 데이터를 전달받는 Fragment가 된다.)

1) Bundle을 이용하여 데이터 전달하기

별도의 의존성 없이도 사용할 수 있는 방법으로, 다소 오래된 방식임에도 불구하고 자주 사용된다.

① fragment_home.xml 파일에 "LILAC" 부분과 "아이유 (IU)" 부분의 TextView에 id를 매핑한다.

<TextView
	android:id="@+id/title_lilac"
    ... />

<TextView
	android:id="@+id/singer_iu"
    ... />

② HomeFragment의 homeAlbumImgIv1에 대한 클릭 이벤트 리스너를 아래와 같이 수정한다.

binding.homeAlbumImgIv1.setOnClickListener {
    val bundle = Bundle()
    bundle.putString("title", binding.titleLilac.text.toString())
    bundle.putString("singer", binding.singerIu.text.toString())
    
    val albumFragment = AlbumFragment()
    albumFragment.arguments = bundle
    
    (context as MainActivity)
        .supportFragmentManager.beginTransaction()
        .replace(R.id.main_frm, albumFragment).commitAllowingStateLoss()
}
  • Bundle 객체를 생성한 후, Bundle에 key-value 쌍의 데이터를 넣는다. 여기서는 가수의 이름과 노래 제목을 넣고 있다.
  • AlbumFragment의 인스턴스인 albumFragment를 생성하고, arguments 속성을 방금 만든 bundle로 set한다.
  • replace 메서드를 사용하여 albumFragment로 전환한다. (albumFragment를 AlbumFragment()로 쓰지 않도록 주의한다.)

③ AlbumFragment의 onCreateView 메서드에 아래의 내용을 추가한다.

override fun onCreateView(
        inflater: LayoutInflater, 
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        binding = FragmentAlbumBinding.inflate(inflater,container,false)

        binding.albumMusicTitleTv.text = arguments?.getString("title")
        binding.albumSingerNameTv.text = arguments?.getString("singer")
        
        binding.albumBackIv.setOnClickListener {
        	...

이제 코드를 실행시켜보자. AlbumFragment의 노래 제목과 가수명이 전달 받은 값으로 설정된 것을 확인할 수 있을 것이다.

2) Fragment Result API를 이용하여 데이터 전달하기

① Moudule 수준의 build.gradle 파일에 아래의 의존성을 추가한다.

implementation("androidx.fragment:fragment-ktx:1.3.0")

② HomeFragment의 homeAlbumImgIv1에 대한 클릭 이벤트 리스너를 아래와 같이 수정한다.

binding.homeAlbumImgIv1.setOnClickListener {
    setFragmentResult("TitleInfo", bundleOf("title" to binding.titleLilac.text.toString()))
    setFragmentResult("SingerInfo", bundleOf("singer" to binding.singerIu.text.toString()))
    
    (context as MainActivity)
        .supportFragmentManager.beginTransaction()
        .replace(R.id.main_frm, AlbumFragment()).commitAllowingStateLoss()
}
  • setFragmentResult의 첫번째 파라미터는 전달받을 Fragment(여기서는 AlbumFragment)의 어떤 listener에게 데이터를 전달할 지를 의미하고, 두번째 파라미터는 전달한 Bundle 객체를 의미한다.
  • bundleOf는 키-값 쌍을 사용하여 Bundle 객체를 간단하게 생성하는 메서드이다. "key to value" 형식으로 사용한다.

③ AlbumFragment의 onCreateView 메서드를 아래와 같이 수정한다.

override fun onCreateView(
    inflater: LayoutInflater, 
    container: ViewGroup?,
    savedInstanceState: Bundle?
): View? {
    binding = FragmentAlbumBinding.inflate(inflater,container,false)
    setFragmentResultListener("TitleInfo") { requestKey, bundle ->
        binding.albumMusicTitleTv.text = bundle.getString("title")
    }
    setFragmentResultListener("SingerInfo") { requestKey, bundle ->
        binding.albumSingerNameTv.text = bundle.getString("singer")
    }
    
    binding.albumBackIv.setOnClickListener {
    	...

이외에도 다양한 방법이 있지만, 이번 포스팅에서는 위 두가지 방법에 대해서만 다루도록 하겠다.

3. 이전 Activity로 다시 돌아올 때 데이터 전달받기

이전 포스팅에서 MainActivity의 재생 바를 클릭해 SongActivity로 전환하는 방법을 알아보았다. 이번 포스팅에서는 SongActivity에서 다시 MainActivity로 돌아올 때, 데이터를 전달받는 방법을 알아보자.

① SongActivity의 onCreate 메서드를 아래와 같이 수정한다.

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    binding = ActivitySongBinding.inflate(layoutInflater)
    setContentView(binding.root)
    
    var title : String? = null
    var singer : String? = null
    
    if(intent.hasExtra("title") && intent.hasExtra("singer")){
        title = intent.getStringExtra("title")
        singer = intent.getStringExtra("singer")
        binding.songMusicTitleTv.text = title
        binding.songSingerNameTv.text = singer
    }
    
    binding.songDownIb.setOnClickListener {
        val intent = Intent(this, MainActivity::class.java)
        intent.putExtra("message", title + " _ " + singer)
        setResult(RESULT_OK, intent)
        finish()
    }
    
    binding.songMiniplayerIv.setOnClickListener {
    	...

② MainActivity에 아래의 내용을 추가한다.

class MainActivity : AppCompatActivity() {

    lateinit var binding : ActivityMainBinding
    lateinit var activityResultLauncher: ActivityResultLauncher<Intent>

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)
        
		initBottomNavigation()

        val song = Song(binding.mainMiniplayerTitleTv.text.toString(), binding.mainMiniplayerSingerTv.text.toString())

        activityResultLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
            if (result.resultCode == RESULT_OK) {
                val data = result.data
                if (data != null) {
                    val message = data.getStringExtra("message")
                    Log.d("message", message!!)
                    Toast.makeText(this, message, Toast.LENGTH_SHORT).show()
                }
            }
        }
        
        binding.mainPlayerCl.setOnClickListener {
            val intent = Intent(this, SongActivity::class.java)
            intent.putExtra("title", song.title)
            intent.putExtra("singer",song.singer)
            activityResultLauncher.launch(intent)
        }

    }
  • ActivityResultLauncher<Intent> 타입 변수를 lateinit으로 선언한다.
  • 여기서 result는 SongActivity에 있는 setResult의 결과를 의미한다.
  • setResult의 첫번째 파라미터가 resultCode이고, 두번째 파라미터가 data(intent 객체)이다.
  • SongActivity에서 message라는 이름으로 putExtra한 값을 받아 토스트 메시지로 출력한다.

이제 코드를 실행시켜보자. SongActivity의 songDownIb를 클릭했을 때 HomeFragment로 전환되면서 노래 제목과 가수 이름이 토스트 메시지로 출력될 것이다.

이와 동일한 방법을 사용하여, Back 버튼을 클릭했을 때 토스트 메시지를 띄울 수도 있다. SongActivity에 아래의 메서드를 추가한다.

override fun onBackPressed() {
    val intent = Intent(this, MainActivity::class.java)
    intent.putExtra("message", "뒤로가기 버튼 클릭")
    setResult(RESULT_OK, intent)
    finish()
}

이제 뒤로가기 버튼을 클릭해도 토스트 메시지가 출력될 것이다.

profile
LG전자 Connected Service 1 Unit 연구원 변현섭입니다.

0개의 댓글