본문 바로가기
안드로이드 코틀린

[Kotlin][Android] Fragment에서 registerForActivityResult() 사용해 액티비티 결과 받기

by teamnova 2022. 2. 24.

Java 버전은 https://stickode.tistory.com/340 에서 확인해주세요.

 

 

오늘은 Fragment 에서 Activity 를 실행시키고 결과를 받아보도록 하겠습니다.

 

결과는 registerForActivityResult() 메소드를 사용해 등록한 ActivityResultCallback 에서 받도록 하겠습니다.

 

registerForActivityResult() 에 대한 정보는 아래 링크의 게시글을 확인해주세요.

https://stickode.tistory.com/187

 

[JAVA][Android] registerForActivityResult() 사용하기

기존에 안드로이드에서 사용하던 startActivityForResult() onActivityResult() 기억 나시나요? 근데 지금 그 메소드가 Deprecated가 되었습니다. 그러면 어떤 방법을 이용해야 할까요? http:// developer.android..

stickode.tistory.com

 

계획은 메인 액티비티에서 프래그먼트를 2개 만들고 하단에 있는 버튼으로 그 프래그먼트들을 교체할 수 있게 만들겠습니다.

 

그리고 현재 켜져있는 프레그먼트에서 사용자 입력을 받기 위한 액티비티를 켜고 registerForActivityResult() 를 통해 프레그먼트에서 데이터를 받도록 구현해보겠습니다.

 

먼저 메인 레이아웃 파일입니다.

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".MainActivity">

    <FrameLayout
        android:id="@+id/mainFragmentContainer"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1" />

    <Button
        android:id="@+id/mainFragmentChangeButton"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="프래그먼트 교체 버튼"
        app:layout_constraintTop_toTopOf="parent" />
</LinearLayout>

프레그먼트가 들어갈 mainFragmentContainer 와 교체를 위한 버튼인 mainFragmentChangeButton 를 두었습니다.

 

다음으로 교체 될 프래그먼트의 레이아웃입니다.

fragment_replace.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center">

    <Button
        android:id="@+id/replaceTitleButton"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="제목"
        android:textSize="30sp" />

</LinearLayout>

액티비티를 실행하고 받은 결과를 표시할 replaceTitleButton 하나만 두도록 하겠습니다.

 

 

마지막으로 사용자 입력을 받기 위한 액티비티의 레이아웃 입니다.

activity_sub.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <EditText
        android:id="@+id/subEditText"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

    <Button
        android:id="@+id/subSummitButton"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="프래그먼트로 보내기" />

</LinearLayout>

값을 입력받는 에딧텍스트와 결과를 전송할 버튼으로 이루어져있습니다.

 

먼저 SubActivity 클래스를 만들고 manifests 에 등록해주세요.

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.tstory1">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.Tstory1">
        <activity
            android:name=".MainActivity"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

        <!--  여기에 SubActivity 를 추가 -->
        <activity android:name=".SubActivity" />
    </application>

</manifest>

 

다음으로 서브 클래스 java 코드입니다.

SubActivity.java

import android.content.Intent
import android.os.Bundle
import android.widget.Button
import android.widget.EditText
import androidx.appcompat.app.AppCompatActivity


class SubActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_sub)

        val editText : EditText = findViewById(R.id.subEditText)
        val summitButton : Button = findViewById(R.id.subSummitButton)

        summitButton.setOnClickListener {
            val intent = Intent()
            intent.putExtra("key", editText.text)
            setResult(RESULT_OK, intent)
            finish()
        }
    }
}

제출 버튼이랑 에딧텍스트를 findViewById 를 통해 찾습니다.

 

그리고 제출 버튼이 눌리면 인텐트에 에딧텍스트에 들어있는 값을 인텐트에 넣고, setResult() 로 결과를 설정하고, 액티비티를 종료합니다.

 

다음으로 교체 프래그먼트입니다.

ReplaceFragment.java

import android.content.Intent
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Button
import androidx.activity.result.contract.ActivityResultContracts.StartActivityForResult
import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.Fragment



class ReplaceFragment : Fragment() {

    companion object{
        fun newInstance(name: String): ReplaceFragment {
            val args = Bundle()
            args.putString("key", name)
            val fragment = ReplaceFragment()
            fragment.arguments = args
            return fragment
        }
    }

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?,
    ): View? {
        return inflater.inflate(R.layout.fragment_replace, container, false)
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        val bundle = arguments ?: return

        val title = bundle.getString("key")
        val button : Button = view.findViewById(R.id.replaceTitleButton)
        button.text = title

        val activityResultLauncher = registerForActivityResult(StartActivityForResult()) { result ->
            if (result.resultCode == AppCompatActivity.RESULT_OK) {
                val data = result.data
                val text = data!!.getCharSequenceExtra("key")
                button.text = text
            }
        }

        button.setOnClickListener {
            activityResultLauncher.launch(Intent(requireActivity(), SubActivity::class.java))
        }
    }
}

newInstance() 메소드를 통해 ReplaceFragment 를 생성을 합니다.

 

생성할때 이름을 담은 Bundle 도 같이 넣어주도록 만들었습니다.

 

onCreateView 에서 레이아웃을 부풀(?)립니다.

 

그 후 onViewCreated 에서 MainActivity 에서 전달받은(아래 MainActivity 에서 설명할 예정) 프래그먼트의 제목을 버튼에 셋팅하도록 합니다.

 

그리고 오늘의 주인공인 registerForActivityResult() 를 사용해서 콜백을 등록합니다.

 

콜백이 RESULT_OK 면 SubActivity 에서 넣은 에딧텍스트 값을 가져와서 Button 에 넣습니다.

 

마지막으로 button 을 누르면 사용자 입력을 받을 SubActivity 를 실행시킵니다.

 

 

마지막으로 메인 액티비티입니다.

MainActivity.java

import android.os.Bundle
import android.widget.Button
import androidx.appcompat.app.AppCompatActivity

class MainActivity : AppCompatActivity() {
    private val trueFragment: ReplaceFragment by lazy { ReplaceFragment.newInstance("true") }
    private val falseFragment: ReplaceFragment by lazy { ReplaceFragment.newInstance("false") }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        val button : Button = findViewById(R.id.mainFragmentChangeButton)
        button.setOnClickListener {
            replaceFragment()
        }
        button.performClick()
    }

    private fun replaceFragment() {
        val beforeFragment = supportFragmentManager.primaryNavigationFragment
        val fragment = if(beforeFragment == trueFragment){
            falseFragment
        }else{
            trueFragment
        }

        with(supportFragmentManager.beginTransaction()){
            if (beforeFragment != null) {
                hide(beforeFragment)
            }

            if (!supportFragmentManager.fragments.contains(fragment)) {
                add(R.id.mainFragmentContainer, fragment)
            }

            setPrimaryNavigationFragment(fragment)
                .show(fragment)
                .commit()
        }
    }
}

 

 

교체하기 위한 두개의 프래그먼트를 멤버 변수에 선언합니다.

 

onCreate 에서 프래그먼트 교체 버튼을 찾아서 버튼 클릭 로직을 작성합니다.

 

클릭하면 replaceFragment() 를 실행시킵니다.

 

replaceFragement() 는 프래그먼트를 교체해주는 메소드입니다.

 

교체하기전에 띄워져있던 프레그먼트(beforeFragment)가 있으면 getPrimaryNavigationFragment() 로 가져와 숨깁니다.

 

beforeFragment 가 trueFragment falseFragment 를 반대면 trueFragment 를 보여주도록 만듭니다.

 

새로 전달받은 프래그먼트가 FragmentManager 에 추가가 안되어 있으면 FragmentManager 에 추가해줍니다.

 

마지막으로 보여줄 프래그먼트를 setPrimaryNavigationFragment 에 넣고 액티비티에 띄웁니다.

 

실행 영상입니다.