본문 바로가기
안드로이드 자바

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

by teamnova 2022. 1. 15.

오늘은 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.view.View;
import android.widget.Button;
import android.widget.EditText;

import androidx.appcompat.app.AppCompatActivity;

public class SubActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_sub);

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


        summitButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent();
                intent.putExtra("key", editText.getText());

                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.ActivityResult;
import androidx.activity.result.ActivityResultCallback;
import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContracts;
import androidx.annotation.Nullable;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.Fragment;

public class ReplaceFragment extends Fragment {

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        return inflater.inflate(R.layout.fragment_replace, container, false);
    }

    @Override
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);

        Bundle bundle = getArguments();
        if (bundle == null) return;

        String title = bundle.getString("key");

        Button button = view.findViewById(R.id.replaceTitleButton);
        button.setText(title);

        ActivityResultLauncher<Intent> activityResultLauncher = registerForActivityResult(
                new ActivityResultContracts.StartActivityForResult(),
                new ActivityResultCallback<ActivityResult>() {
                    @Override
                    public void onActivityResult(ActivityResult result) {
                        if (result.getResultCode() == AppCompatActivity.RESULT_OK) {
                            Intent data = result.getData();
                            CharSequence text = data.getCharSequenceExtra("key");
                            button.setText(text);
                        }
                    }
                }
        );

        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                activityResultLauncher.launch(new Intent(requireActivity(), SubActivity.class));
            }
        });
    }
}

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

 

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

 

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

 

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

 

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

 

 

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

MainActivity.java


import android.os.Bundle;
import android.view.View;
import android.widget.Button;

import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentTransaction;

public class MainActivity extends AppCompatActivity {

    boolean isTrue;
    ReplaceFragment trueFragment, falseFragment;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Button button = findViewById(R.id.mainFragmentChangeButton);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (isTrue) {
                    if (trueFragment == null) {
                        trueFragment = new ReplaceFragment();
                    }
                    replaceFragment(trueFragment, "true");
                } else {
                    if (falseFragment == null) {
                        falseFragment = new ReplaceFragment();
                    }
                    replaceFragment(falseFragment, "false");
                }
            }
        });

        button.performClick();

    }


    void replaceFragment(Fragment fragment, String name) {

        isTrue = !isTrue;

        FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
        Fragment beforeFragment = getSupportFragmentManager().getPrimaryNavigationFragment();

        if (beforeFragment != null) {
            transaction.hide(beforeFragment);
        }

        if (!getSupportFragmentManager().getFragments().contains(fragment)) {
            Bundle bundle = new Bundle();
            bundle.putString("key", name);
            fragment.setArguments(bundle);
            transaction.add(R.id.mainFragmentContainer, fragment);
        }

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

}

프래그먼트 교체용 스위치로 isTrue 라는 멤버 변수를 사용합니다.

 

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

 

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

 

클릭하면 isTrue 에 따라 trueFragment, falseFragment 를 replaceFragement() 의 인자로 넣어줍니다.

 

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

 

교체하기전에 띄워져있던 프레그먼트가 있으면 getPrimaryNavigationFragment() 로 가져와 숨기고, 새로 전달받은 프래그먼트를 보여줍니다.

 

새로 전달받은 프래그먼트가 FragmentManager 에 추가가 안되어 있으면 프래그먼트에 이름을 번들로 넣고(아까 위에서 말한 부분) FragmentManager 에 추가해줍니다.

 

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

 

실행 영상입니다.