programing

DialogFragment에서 결과 수신

megabox 2023. 10. 31. 20:41
반응형

DialogFragment에서 결과 수신

목록에서 항목 선택, 텍스트 입력 등 여러 가지 작업에 Dialog Fragments를 사용하고 있습니다.

값(예: 문자열 또는 목록의 항목)을 호출 활동/프래그먼트로 되돌리는 가장 좋은 방법은 무엇입니까?

현재 통화 활동을 구현하고 있습니다.DismissListenerDialogFragment에 활동에 대한 참조를 제공합니다.그런 다음 Dialog(대화 상자)가 호출됩니다.OnDimissmethod in activity and activity는 DialogFragment 객체에서 결과를 가져옵니다.매우 지저분하고 DialogFragment(대화 상자)에서 활동에 대한 참조가 손실되므로 구성 변경(방향 변경)에서는 작동하지 않습니다.

도와주셔서 감사합니다.

사용하다myDialogFragment.setTargetFragment(this, MY_REQUEST_CODE)대화상자를 보여주는 곳에서, 대화상자가 끝나면, 대화상자에서 전화를 걸 수 있습니다.getTargetFragment().onActivityResult(getTargetRequestCode(), ...), 실행합니다.onActivityResult()그 안에 있는 조각에

를 하는 것 onActivityResult(), 특히 활동을 전혀 수반하지 않기 때문입니다.하지만 공식적인 구글 사람들이 추천하는 것을 봤고, 아마도 API 데모에서도 볼 수 있을 것입니다.제 생각엔 그게g/setTargetFragment()가 추가되었습니다.

여기 보시는 것처럼 아주 간단한 방법이 있습니다.

당신의DialogFragment다음과 같은 인터페이스 수신기를 추가합니다.

public interface EditNameDialogListener {
    void onFinishEditDialog(String inputText);
}

그런 다음 해당 수신기에 참조를 추가합니다.

private EditNameDialogListener listener;

수신기 메서드를 "활성화"하고 부모 Activity/Fragment가 이 인터페이스를 구현하는지 확인하는 데 사용됩니다(아래 참조).

Activity/FragmentActivity/Fragment른"이라고DialogFragment이 인터페이스를 구현하기만 하면 됩니다.

당신의DialogFragment당신이 추가해야 할 모든 것은 당신이 그것을 기각하고 싶은 시점에서.DialogFragment결과는 다음과 같습니다.

listener.onFinishEditDialog(mEditText.getText().toString());
this.dismiss();

어디에mEditText.getText().toString()전화를 건 사람들에게 다시 전달될 것입니다.Activity.

다른 내용을 반환하려면 청취자가 취하는 주장을 변경하기만 하면 됩니다.

마지막으로 인터페이스가 실제로 상위 활동/파편에 의해 구현되었는지 확인해야 합니다.

@Override
public void onAttach(Context context) {
    super.onAttach(context);
    // Verify that the host activity implements the callback interface
    try {
        // Instantiate the EditNameDialogListener so we can send events to the host
        listener = (EditNameDialogListener) context;
    } catch (ClassCastException e) {
        // The activity doesn't implement the interface, throw exception
        throw new ClassCastException(context.toString()
                + " must implement EditNameDialogListener");
    }
}

이 방법은 매우 유연하며 대화 상자를 아직 종료하고 싶지 않더라도 결과와 함께 다시 호출할 수 있습니다.

Dialog Fragment에서 결과를 받는 훨씬 더 간단한 방법이 있습니다.

먼저 Activity, Fragment 또는 FragmentActivity에서 다음 정보를 추가해야 합니다.

@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
    // Stuff to do, dependent on requestCode and resultCode
    if(requestCode == 1) { // 1 is an arbitrary number, can be any int
         // This is the return result of your DialogFragment
         if(resultCode == 1) { // 1 is an arbitrary number, can be any int
              // Now do what you need to do after the dialog dismisses.
         }
     }
}

requestCode기본적으로 전화하신 DialogFragment의 int 레이블입니다. 잠시 후에 이것이 어떻게 작동하는지 보여드리겠습니다.ResultCode는 DialogFragment에서 현재 대기 중인 Activity, Fragment 또는 FragmentActivity에서 발생한 작업을 알려주는 코드입니다.

다음으로 입력할 코드는 Dialog Fragment에 대한 호출입니다.예를 들어 다음과 같습니다.

DialogFragment dialogFrag = new MyDialogFragment();
// This is the requestCode that you are sending.
dialogFrag.setTargetFragment(this, 1);     
// This is the tag, "dialog" being sent.
dialogFrag.show(getFragmentManager(), "dialog");

이 세 줄로 DialogFragment(DialogFragment)를 선언하고 requestCode(요청 코드)를 설정합니다(Dialog(대화)가 해제되면 onActivityResult(...)). 그런 다음 대화 상자를 표시합니다.그렇게 간단하다.

이제 DialogFragment(대화 상자)에서 한 줄을 바로 앞에 추가하면 됩니다.dismiss()결과 코드를 onActivityResult()로 다시 보내도록 합니다.

getTargetFragment().onActivityResult(getTargetRequestCode(), resultCode, getActivity().getIntent());
dismiss();

바로 그겁니다.참고로 결과Code는 다음과 같이 정의됩니다.int resultCode내가 하기로 한 것은resultCode = 1;이 경우에는

이제 Dialog Fragment의 결과를 호출 작업, Fragment 또는 Fragment Activity로 다시 보낼 수 있습니다.

또한 이 내용은 이전에 게시된 것으로 보이는데, 충분한 예시가 없어서 좀 더 자세히 설명해 드리려고 했습니다.

EDIT 2016.06.24. 위와 같은 잘못된 코드에 대해 사과드립니다.그러나 결과를 작업으로 다시 돌려받을 수는 없습니다.

dialogFrag.setTargetFragment(this, 1);

목표를 정합니다Fragment 안 돼요.Activity. 따라서 이를 수행하기 위해서는 구현을 사용해야 합니다.InterfaceCommunicator.

당신의DialogFragment글로벌 변수를 설정하다

public InterfaceCommunicator interfaceCommunicator;

이를 처리할 공용 기능을 만듭니다.

public interface InterfaceCommunicator {
    void sendRequestCode(int code);
}

그러면 코드를 다시 보낼 준비가 되면Activity그 때에DialogFragment실행이 완료되었습니다. 먼저 줄을 추가하면 됩니다.dismiss();당신의.DialogFragment:

interfaceCommunicator.sendRequestCode(1); // the parameter is any int code you choose.

이제 두 가지 작업을 수행해야 합니다. 첫 번째 작업은 더 이상 적용할 수 없는 코드 한 줄을 제거하는 것입니다.

dialogFrag.setTargetFragment(this, 1);  

그러면 인터페이스를 구현하면 모두 끝입니다.다음 행을 추가하면 가능합니다.implements수업의 맨 위에 있는 절:

public class MyClass Activity implements MyDialogFragment.InterfaceCommunicator

그리고 나서.@Override활동에 있어서의 기능,

@Override
public void sendRequestCode(int code) {
    // your code here
}

당신은 당신이 사용하는 것과 마찬가지로 이 인터페이스 방법을 사용합니다.onActivityResult()방법.인터페이스 방법이 다음을 위한 것인 경우를 제외하고는DialogFragments그리고 다른 하나는Fragments.

아직도 이 글을 읽고 있는 모든 사람들:setTargetFragment()감가 상각되었습니다.이제 를 사용하는 것이 좋습니다.FragmentResultListenerAPI는 다음과 같습니다.

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setFragmentResultListener("requestKey") { key, bundle ->
        val result = bundle.getString("resultKey")
        // Do something with the result...
    }

    ...

    // Somewhere show your dialog
    MyDialogFragment.newInstance().show(parentFragmentManager, "tag")
}

그럼 당신의MyDialogFragment결과를 설정합니다.

button.setOnClickListener{
    val result = "some string"
    setFragmentResult("requestKey", bundleOf("resultKey" to result))
    dismiss()
}

대답하기에는 너무 늦었을 수도 있지만 여기에 제가 결과를 얻기 위해 한 일이 있습니다.DialogFragment대답과 . @brandon의 대답과 매우 비슷합니다.전화 드립니다.DialogFragment단편에서 이 코드를 대화상자를 호출하는 위치에 배치합니다.

FragmentManager fragmentManager = getFragmentManager();
            categoryDialog.setTargetFragment(this,1);
            categoryDialog.show(fragmentManager, "dialog");

어디에categoryDialogs입니다DialogFragment당신의 실행에 있어서 이 후에 전화하고 싶습니다.dialogfragment데이터를 설정할 위치에 이 코드를 배치합니다.치의 입니다.resultCode1을 설정하거나 시스템 정의를 사용할 수 있습니다.

            Intent intent = new Intent();
            intent.putExtra("listdata", stringData);
            getTargetFragment().onActivityResult(getTargetRequestCode(), resultCode, intent);
            getDialog().dismiss();

이제 호출 프래그먼트로 돌아가서 이 메소드를 구현해야 할 때입니다.원하는 경우 데이터 유효성 또는 결과 성공 여부를 검사합니다.resultCode그리고.requestCode만일의 경우에는

 @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);        
        //do what ever you want here, and get the result from intent like below
        String myData = data.getStringExtra("listdata");
Toast.makeText(getActivity(),data.getStringExtra("listdata"),Toast.LENGTH_SHORT).show();
    }

다른 접근 방식으로 프래그먼트가 활동까지 통신할 수 있도록 합니다.

1)조각에 공용 인터페이스를 정의하고 이에 대한 변수를 만듭니다.

public OnFragmentInteractionListener mCallback;

public interface OnFragmentInteractionListener {
    void onFragmentInteraction(int id);
}

2)프래그먼트의 mCallback 변수에 활동 캐스트

try {
    mCallback = (OnFragmentInteractionListener) getActivity();
} catch (Exception e) {
    Log.d(TAG, e.getMessage());
}

3)활동에 청취자 구현

public class MainActivity extends AppCompatActivity implements DFragment.OnFragmentInteractionListener  {
     //your code here
}

4)OnFragment 재정의활동에서의 상호작용

@Override
public void onFragmentInteraction(int id) {
    Log.d(TAG, "received from fragment: " + id);
}

더 자세한 정보: https://developer.android.com/training/basics/fragments/communicating.html

한 가지 쉬운 방법은 다음과 같습니다.이 대화상자를 실행합니다.

  CallingActivity callingActivity = (CallingActivity) getActivity();
  callingActivity.onUserSelectValue("insert selected value here");
  dismiss();

그런 다음 Dialog Fragment라는 활동에서 다음과 같은 적절한 기능을 만듭니다.

 public void onUserSelectValue(String selectedValue) {

        // TODO add your implementation.
      Toast.makeText(getBaseContext(), ""+ selectedValue, Toast.LENGTH_LONG).show();
    }

토스트는 그것이 효과가 있다는 것을 보여주기 위한 것입니다.나를 위해 일했습니다.

아무도 지역 방송을 이용하자고 제안하지 않은 것을 보고 매우 놀랐습니다.DialogFragment.Activity소통! 보다 훨씬 합니다.저는 그것이 다른 제안들보다 훨씬 더 간단하고 깨끗하다고 생각합니다.기본적으로, 당신은 당신의 인터넷 주소를 등록합니다.Activity방송을 듣고 당신은 당신의 지역 방송을 보냅니다.DialogFragment예를 들면간단하죠.모든 설정 방법에 대한 단계별 가이드는 여기를 참조하십시오.

또는 다음과 같은 ViewModel 공유:

public class SharedViewModel extends ViewModel {
    private final MutableLiveData<Item> selected = new MutableLiveData<Item>();

    public void select(Item item) {
        selected.setValue(item);
    }

    public LiveData<Item> getSelected() {
        return selected;
    }
}


public class MasterFragment extends Fragment {
    private SharedViewModel model;
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        model = ViewModelProviders.of(getActivity()).get(SharedViewModel.class);
        itemSelector.setOnClickListener(item -> {
            model.select(item);
        });
    }
}

public class DetailFragment extends Fragment {
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        SharedViewModel model = ViewModelProviders.of(getActivity()).get(SharedViewModel.class);
        model.getSelected().observe(this, { item ->
           // Update the UI.
        });
    }
}

https://developer.android.com/topic/libraries/architecture/viewmodel#sharing_data_between_fragments

제 경우에는 대상 프래그먼트에 인수를 전달해야 했습니다.하지만 "프래그먼트는 이미 활성화되어 있습니다"라는 예외가 생겼습니다.그래서 나는 내 DialogFragment에 인터페이스를 선언했고, 이 인터페이스는 parentFragment가 구현했습니다.상위 조각이 DialogFragment를 시작할 때 자체를 TargetFragment로 설정했습니다.그 다음 Dialog Fragment에서 전화를 걸었습니다.

 ((Interface)getTargetFragment()).onSomething(selectedListPosition);

인코틀린

    // My DialogFragment
class FiltroDialogFragment : DialogFragment(), View.OnClickListener {
    
    var listener: InterfaceCommunicator? = null

    override fun onAttach(context: Context?) {
        super.onAttach(context)
        listener = context as InterfaceCommunicator
    }

    interface InterfaceCommunicator {
        fun sendRequest(value: String)
    }   

    override fun onClick(v: View) {
        when (v.id) {
            R.id.buttonOk -> {    
        //You can change value             
                listener?.sendRequest('send data')
                dismiss()
            }
            
        }
    }
}

// 마이 액티비티

class MyActivity: AppCompatActivity(),FiltroDialogFragment.InterfaceCommunicator {

    override fun sendRequest(value: String) {
    // :)
    Toast.makeText(this, value, Toast.LENGTH_LONG).show()
    }
}
 

도움이 되었으면 좋겠군요, 개선이 된다면 수정 부탁드립니다.나의 영어실력은 매우 좋지 않습니다.

인수를 보내고 두 번째 fragment에서 결과를 수신하려면 fragment를 사용할 수 있습니다.이 작업을 수행하기 위한 인수 설정

static class FirstFragment extends Fragment {
    final Handler mUIHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
            case 101: // receive the result from SecondFragment
                Object result = msg.obj;
                // do something according to the result
                break;
            }
        };
    };

    void onStartSecondFragments() {
        Message msg = Message.obtain(mUIHandler, 101, 102, 103, new Object()); // replace Object with a Parcelable if you want to across Save/Restore
                                                                               // instance
        putParcelable(new SecondFragment(), msg).show(getFragmentManager().beginTransaction(), null);
    }
}

static class SecondFragment extends DialogFragment {
    Message mMsg; // arguments from the caller/FirstFragment

    @Override
    public void onViewCreated(View view, Bundle savedInstanceState) {
        // TODO Auto-generated method stub
        super.onViewCreated(view, savedInstanceState);
        mMsg = getParcelable(this);
    }

    void onClickOK() {
        mMsg.obj = new Object(); // send the result to the caller/FirstFragment
        mMsg.sendToTarget();
    }
}

static <T extends Fragment> T putParcelable(T f, Parcelable arg) {
    if (f.getArguments() == null) {
        f.setArguments(new Bundle());
    }
    f.getArguments().putParcelable("extra_args", arg);
    return f;
}
static <T extends Parcelable> T getParcelable(Fragment f) {
    return f.getArguments().getParcelable("extra_args");
}

TL;DR - 이 AppDialog 클래스를 사용하여 DialogFragment에 데이터를 전달하고 결과를 가져옵니다.

상세설명 :

  • 전제 - 구성 변경 시 프래그먼트가 파괴되고 재생성됩니다.뷰 모델들이 어슬렁거리고 있습니다.Dialog(대화 상자)를 사용할 때 사용자가 장치를 회전하고 방향을 변경할 때 Dialog Fragment(대화 상자)가 예기치 않게 사라지지 않도록 Dialog Fragment(대화 상자)로 래핑하는 것이 좋습니다(Dialog Fragment(대화 상자)가 장치를 다시 만들고 다시 표시합니다).
  • 제한(따라서 이 질문) - DialogFragment의 작동 방식은 구성 변경 시 재인스톨이 필요한 클래스를 사용하는 것입니다. 즉, 하위 클래스에 생성자 매개변수를 지정하여 매개변수를 전달할 수 없으며, 일반적으로 대화 결과를 전달하려면 뷰 모델을 통해 사용자 지정 콜백을 수행해야 합니다.이는 일반적으로 모든 대화상자에 대한 새로운 하위 클래스를 의미합니다.
  • 해결책 - 이 모든 것을 돕기 위해 이 사용자 지정 AppDialog fragment가 복구됩니다. 매개 변수는 메모리에 저장됩니다(보기 모델과 유사하게 T를 메모리에 저장하고 이를 사용하여 구성 변경에 대한 대화 상자를 다시 생성하는 작은 사용자 지정 뷰 모델이라고 생각할 수 있습니다).다시 전화를 거는 적절한 방법은 뷰 모델을 통해서일 것입니다.AppDialog(앱 대화 상자)를 표시하는 조각의 경우, 이미 뷰 모델이 있고 대화 상자를 만드는 데 사용된 람다에서 참조할 수 있습니다. 즉, 대화 상자 조각이 제거될 때까지 뷰 모델에 대한 추가적인 강력한 참조를 의미합니다.
  • 예제 - 이 AppDialog 유틸리티 클래스를 사용하여 매개 변수를 수신하고 모델을 보기 위해 콜백하여 결과를 알리는 간단한 대화 상자 예제를 참조합니다.

도우미 클래스:


class AppDialog<T>: DialogFragment() {
    companion object {

        fun<T> buildDialog(params: T? = null, builder: AppDialogLambda<T>): AppDialog<T> {

            // Setup arguments
            val args = Bundle()
            args.putInt("key", pushDialogArgs(params, builder))

            // Instantiate
            val fragment = AppDialog<T>()
            fragment.arguments = args
            return fragment
        }

        // --------------------
        // Dialog Arguments

        private var lastKey: Int = 0
        private val dialogArgs = mutableMapOf<Int, Pair<Any?, AppDialogLambda<*>>>()

        private fun pushDialogArgs(params: Any?, builder: AppDialogLambda<*>): Int {
            dialogArgs[lastKey] = params to builder
            return lastKey++
        }

        private fun getDialogArgs(key: Int): Pair<Any?, AppDialogLambda<*>> {
            return dialogArgs[key]!!
        }

        private fun deleteDialogArgs(key: Int) {
            dialogArgs.remove(key)
        }
    }

    override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
        // Get arguments
        val argKey = requireArguments().getInt("key")
        val (params, builder) = getDialogArgs(argKey)

        // We are getting back our arguments we passed AppDialog.buildDialog and
        // the type is guaranteed to be the same. Silence this warning
        @Suppress("UNCHECKED_CAST")
        return (builder as AppDialogLambda<T>)(this, params as T?)
    }

    override fun onDismiss(dialog: DialogInterface) {
        super.onDismiss(dialog)
        val argKey = requireArguments().getInt("key")
        deleteDialogArgs(argKey)
    }
}

사용 예시(이후):

        val info = mapOf("message" to "${error.description}\n\nPlease check your Internet connection and try again.")
        AppDialog.buildDialog(info) { fragment, params ->
            fragment.isCancelable = false // since we are in a DialogFragment
            AlertDialog.Builder(fragment.context)
                .setTitle("Terms Of Service Failed To Load")
                .setMessage(params!!["message"])
                .setPositiveButton("Retry") { _, _ ->
                    // Update the view model instead of calling UserTOSFragment directly 
                    // as the fragment may be destroyed and recreated
                    // on configuration changes. The viewModel will stay alive.
                    viewModel.onTermsOfServiceReload()
                }
                .setNegativeButton("Cancel") { _, _ ->
                    viewModel.onTermsOfServiceDeclined()
                    fragment.findNavController().popBackStack()
                }.create()
        }.show(parentFragmentManager, "TOS Failed Dialog")

사용 예시(이전):DialogFragment를 사용하지 않으면(설명을 위해 이 작업을 수행하지 마십시오. 구성 변경 시 대화 상자가 삭제되므로 이는 잘못된 관행입니다.) UserTOSFragment.kt - 다시 시도할 때 UserTOSFragment.loadContent()를 직접 호출하는 데 사용되는 코드입니다.위 예제에서 대신 viewModel.onTermsOfServiceDeclined()를 호출하도록 다시 작성해야 합니다.

        AlertDialog.Builder(context)
            .setTitle("Terms Of Service Failed To Load")
            .setMessage("${error.description}\n\nPlease check your Internet connection and try again.")
            .setPositiveButton("Retry") { _, _ ->
                loadContent()
            }
            .setCancelable(false)
            .setNegativeButton("Cancel") { _, _ ->
                viewModel.onTermsOfServiceDeclined()
                findNavController().popBackStack()
            }
            .show()

다양한 접근법(2023):

  • 탐색 그래프 사용: 반환 방향에 대한 인수(대화 상자 조각에서 부모로)를 설정하고 대상에서 수신하면 됩니다.

대화 상자에서 보내기(자바):NavHostFragment.navigate(this, YourDialogName+Directions .action+---+To---(DefinedArgument)));

부모(자바)로 받기:dialogResult = NameOfFragmentArgs.fromBundle(requireArguments()).get+DefinedArgument;

  • 탐색 그래프 및 ViewModel+LiveData 사용 (권장)

CommonsWare 웹사이트에는 이러한 접근방식에 대한 완전한 예시가 있습니다.

  • 인텐트 및 번들 사용

  • 사용자 지정 UI를 사용하여 대화상자에 직접 액세스할 수 있습니다.setOnClickListener단편 내부의 양 및 음 버튼에 대한 방법.

  • 정의된 인터페이스 구현(예:setOnYes목적지 파편/활동 중인

  • 으로.FragmentManager그리고.setFragmentResult(String, Bundle) 이 게시물 보기

대화 상자에서 조각

class AbcDialogFragment(private val ondata: (data: String) -> Unit) :  DialogFragment() {}

fragment/Activity에서 대화 상자를 표시하는 코드

val abcDialogFragment = AbcDialogFragment(ondata = {data->  })
                
abcDialogFragment.show(requireActivity().supportFragmentManager, "TAG")

대화 조각에서 대화 조각이 닫히거나 클릭 수신기를 클릭하면 onData를 호출할 수 있습니다.

(아직 아무도 언급하지 않았기 때문에) 옵션 중 하나로 사용할 수 있습니다 - 오토와 같은 이벤트 버스를 사용할 수 있습니다.대화 상자에서 수행하는 작업은 다음과 같습니다.

bus.post(new AnswerAvailableEvent(42));

그리고 발신자(Activity 또는 Fragment)에게 가입하게 합니다.

@Subscribe public void answerAvailable(AnswerAvailableEvent event) {
   // TODO: React to the event somehow!
}

언급URL : https://stackoverflow.com/questions/10905312/receive-result-from-dialogfragment

반응형