ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Deprecated] StartActivityForResult
    Android/Deprecated 2021. 8. 2. 17:19

    빠른 개인 참고용 (kotlin)

     mActivityResultLauncher =
                registerForActivityResult(StartActivityForResult())
                {   activityResult->
                    if(activityResult.resultCode== Activity.RESULT_OK){
                        
                        val intent:Intent?=activityResult.data
                        if(intent!=null){
                            //처리
                        }
                        
                    }else{
                        
                    }
                }

     

    정리 

     

    ComponentActivity의 registerForActivityResult메서드를 사용해야 한다. 

    registerForActivitiyResult메서드를 사용하기 위해서 return되는 것, 인자로 들어가는 것에 대해 알아보자.


    java.lang.Object
       ↳	android.content.Context
     	   ↳	android.content.ContextWrapper
     	 	   ↳	android.view.ContextThemeWrapper
     	 	 	   ↳	android.app.Activity
     	 	 	 	   ↳	androidx.activity.ComponentActivity
     	 	 	 	 	   ↳	androidx.fragment.app.FragmentActivity
     	 	 	 	 	 	   ↳	androidx.appcompat.app.AppCompatActivity

    Activity -> ComponentActivity ->FragmentActivity -> AppCompatActivity

    • ComponentActivity implements ActivityResultCaller (액티비티 리저트 콜러)

     

    ActivityResultCaller 인터페이스

    that can call Activity.startActivityForResult(Intent, int) style APIs without having to manage request codes, and converting request/response to an Intent

    리퀘스트 코드 없이 액티비티를 start시작시킬 수 있다.

     

    ActivityResultCaller인터페이스를 구현한 ComponentActivity의 registerForActivityResult 메서드를 사용

     @NonNull
        @Override
        public final <I, O> ActivityResultLauncher<I> registerForActivityResult(
                @NonNull ActivityResultContract<I, O> contract,
                @NonNull ActivityResultCallback<O> callback) {
            return registerForActivityResult(contract, mActivityResultRegistry, callback);
        }

    메서드는 return <I, O>ActivityResultLauncher<I>

     

    abstract class ActivityResultContract

    어떠한 유형의 인텐트를 날릴 것인가

    이 클래스를 구현해서 제공해주는 클래스가 있다. 밑에서 보자.

     

    interface ActivityResultCallback

    onActivityResult 하나의 메서드가 있고, 결과를 받을 때 호출될 콜백 메서드이다.

    이 메서드에 우리가 결과를 받고 진행할 코드를 넣는다.

    (기존 액티비티 내부의 onActivityResult로 보면된다.)

     

    abstract class ActivityResultLauncher<I>

    componentActivity의 registerForActivitiyResult로 리턴되는 인스턴스이다.

    이 런쳐를 참조변수에 담아두어 launch메서드를 통해 액티비티를 시작한다. 

     

    ActivityResultContract: the contract, specifying conversions to/from Intents (Intent, Output)

    ActivityResultCallback: the callback to be called on the main thread when activity result is available


    • abstract ActivityResultContract<I, O>

    액티비티간에 어떤 계약을 할 것인지( 다른 액티비티를 띄운다는지, 카메라를 실행한다든지)

    public abstract class ActivityResultContract<I, O> {
    
        /** Create an intent that can be used for {@link Activity#startActivityForResult} */
        public abstract @NonNull Intent createIntent(@NonNull Context context,
                @SuppressLint("UnknownNullness") I input);
    
        /** Convert result obtained from {@link Activity#onActivityResult} to O */
        @SuppressLint("UnknownNullness")
        public abstract O parseResult(int resultCode, @Nullable Intent intent);

    인텐트 생성, result파싱에 대한 추상 메서드가 정의되어 있다. 

    이 메서드는 직접사용하지 않고 이렇게 구성되어있다라는 것을 보여주기 위해 그냥 옮겨봤다.

     

    구현된 클래스(프레임워크에서 제공해주는)는 ActivityResultContracts로 s가 붙어있다. 

    사용할 인텐트 유형 따라 이미 구현되어 있는 static nested 클래스를 사용하면 된다.

     

    ActivitiyResultContracts의  static inner클래스들로  각 인텐트 유형 클래스가 정의되어있다.

    다른 액티비티 호출하기 위해서 static inner 클래스 StartActivityForResult 사용

    registerActivityForResult의 첫 인자에 new ActivityResultContracts.StartActivityForResult()


    • interface ActivityResultCallback<O> (액티비티 리저트 콜백)

    A type-safe callback to be called when an activity result is available.

    activity result가 이용가능할 때 호출되는 callback메서드


    • ActivityResultLauncher<I>

    A launcher for a previously-prepared call to start the process of executing an ActivityResultContract

    미리 준비된 call을 실행할 놈이다. 이놈의 launch메서드 호출로 액티비티를 띄우기 시작한다.

    public abstract class ActivityResultLauncher<I> {
    
        /**
         * Executes an {@link ActivityResultContract}.
         *
         * <p>This method throws {@link android.content.ActivityNotFoundException}
         * if there was no Activity found to run the given Intent.
    
         * @param input the input required to execute an {@link ActivityResultContract}.
         *
         * @throws android.content.ActivityNotFoundException
         */
        public void launch(@SuppressLint("UnknownNullness") I input) {
            launch(input, null);
        }
    
        /**
         * Executes an {@link ActivityResultContract}.
         *
         * <p>This method throws {@link android.content.ActivityNotFoundException}
         * if there was no Activity found to run the given Intent.
         *
         * @param input the input required to execute an {@link ActivityResultContract}.
         * @param options Additional options for how the Activity should be started.
         *
         * @throws android.content.ActivityNotFoundException
         */
        public abstract void launch(@SuppressLint("UnknownNullness") I input,
                @Nullable ActivityOptionsCompat options);
    
        /**
         * Unregisters this launcher, releasing the underlying result callback, and any references
         * captured within it.
         *
         * You should call this if the registry may live longer than the callback registered for this
         * launcher.
         */
        @MainThread
        public abstract void unregister();
    
        /**
         * Get the {@link ActivityResultContract} that was used to create this launcher.
         *
         * @return the contract that was used to create this launcher
         */
        @NonNull
        public abstract ActivityResultContract<I, ?> getContract();
    }

     

    Note : 프레그먼트 또는 액티비티가 생성되기 전에 registerForActivityResult()를 호출해도 안전하지만, 프래그먼트 또는 액티비티의 Lifecycle 상태가 CREATED가 되기 전까지는 ActivityResultLauncher를 시작할 수 없다.

     

    (수정) ActivityResultLauncher의 초기화 , launch메서드를 적절한 위치에서 호출하지 않으면 에러가 날수있다.

    나와 같은 경우는 버튼 리스너와 얽혀서 문제가 났던것 같은데 현재 수정 시점에는 기억이 나지 않는다.


    총 코드

     

    MainActivitiy (Intent 보내는)

    public class MainActivity extends AppCompatActivity {
        Button button;
    
        //start시킬 런쳐를 담아둘 변수
        ActivityResultLauncher<Intent> activityResultLauncher;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            button = findViewById(R.id.btn_send_to_2);
    
            //Intent생성
            Intent intent = new Intent(getApplicationContext(), MainActivity2.class);
            intent.putExtra("activity1 key", "홍길동의 아이디 패스워드 요청");
    
            //registerForActivityResult를 통해 런처 초기화
            activityResultLauncher = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), //다른 액티비티 호출에 해당하는 계약
                    new ActivityResultCallback<ActivityResult>() { //액티비티 리저트 콜백을 구현한 익명 객체
                        @Override
                        public void onActivityResult(ActivityResult result) { //구현 메서드에 처리과정 구현
                            if (result.getResultCode() == Activity.RESULT_OK) { //result ok
                                // 액티비티 리저트 콜러 인터페이스의 registerForActivityResult메서드는
                                // request code 없이 진행 -> request code 필요 x
                                Intent data = result.getData();
                                String recString = data.getStringExtra("activity2 key");
                                Toast.makeText(getApplicationContext(), recString, Toast.LENGTH_SHORT).show();
                            } else { //result canceled
                                Toast.makeText(getApplicationContext(), "상대 쪽으로부터 result canceled 응답", Toast.LENGTH_SHORT).show();
                            }
                        }
                    });
    
            button.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
    
                    activityResultLauncher.launch(intent);
                }
            });
        }
    }

     

    MainActivity2( Intent 받는쪽)

     

    public class MainActivity2 extends AppCompatActivity {
        Button button2;
        String receivedValue;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main2);
    
            button2 = findViewById(R.id.btn_send_to_1);
    
            Intent receievedIntent = getIntent(); //받은 인텐트
            Intent resultIntent = new Intent(getApplicationContext(), MainActivity.class); //결과를 보낼 인텐트
    
            if (receievedIntent != null) { //잘 받았으면
                Bundle bundle = receievedIntent.getExtras();
                receivedValue = bundle.getString("activity1 key", "key에 해당하는 값이없다"); 
                //키에 해당하는 값이 없을 때 사용할 default value
                Toast.makeText(this, receivedValue, Toast.LENGTH_SHORT).show(); //요청한 내용 확인
    
                button2.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        if (receivedValue.equals("key에 해당하는 값이없다")) {
                            resultIntent.putExtra("activity2 key", "누구의 정보를 넘겨줘?"); 
                            //key에 해당하는 value 없어서 처리 불가
                        } else {
                            resultIntent.putExtra("activity2 key", "아이디 패스워드는....이야"); //처리 완료
                        }
                        setResult(Activity.RESULT_OK, resultIntent);
                        finish();
                    }
                });
            } else { //인텐트를 못 받았을 경우
                setResult(Activity.RESULT_CANCELED, resultIntent); //canceled를 넘겨주고 종료
                finish();
            }
            
        }
    
    }

     


    https://developer.android.com/training/basics/intents/result

     

    활동에서 결과 가져오기  |  Android 개발자  |  Android Developers

    개발자 앱 내의 활동이든 다른 앱의 활동이든 다른 활동을 시작하는 것이 단방향 작업일 필요는 없습니다. 다른 활동을 시작하고 다시 결과를 받을 수도 있습니다. 예를 들어, 앱에서 카메라 앱

    developer.android.com

     

    https://stackoverflow.com/questions/62671106/onactivityresult-method-is-deprecated-what-is-the-alternative

     

    OnActivityResult method is deprecated, what is the alternative?

    I recently discovered that onActivityResult is deprecated. What should we do to handle it? Any alternative introduced for that?

    stackoverflow.com

    https://charlezz.medium.com/%EC%95%A1%ED%8B%B0%EB%B9%84%ED%8B%B0-%EA%B2%B0%EA%B3%BC-%EC%B2%98%EB%A6%AC%ED%95%98%EA%B8%B0-good-bye-startactivityforresult-onactivityresult-82bafc50edac

     

    액티비티 결과 처리하기 (Good bye… startActivityForResult, onActivityResult)

    액티비티(Activity)는 안드로이드의 주요 컴포넌트 중 하나로 애플리케이션에서 필수적으로 사용된다. 2007년, 안드로이드가 등장한 뒤로 액티비티간에 데이터(인텐트)를 전달하고, 결과를 처리할

    charlezz.medium.com

     

    댓글

Designed by Tistory.