development

DialogFragment에서 조각으로 콜백

big-blog 2020. 6. 9. 07:45
반응형

DialogFragment에서 조각으로 콜백


질문 : DialogFragment에서 다른 Fragment로 콜백을 만드는 방법은 무엇입니까? 필자의 경우 관련된 Activity는 DialogFragment를 완전히 인식하지 않아야합니다.

내가 가진 것을 고려

public class MyFragment extends Fragment implements OnClickListener

그리고 어떤 시점에서 내가 할 수

DialogFragment dialogFrag = MyDialogFragment.newInstance(this);
dialogFrag.show(getFragmentManager, null);

MyDialogFragment의 모양

protected OnClickListener listener;
public static DialogFragment newInstance(OnClickListener listener) {
    DialogFragment fragment = new DialogFragment();
    fragment.listener = listener;
    return fragment;
}

그러나 DialogFragment가 일시 중지되고 수명주기 동안 다시 시작되면 리스너가 주변에있을 것이라는 보장은 없습니다. Fragment의 유일한 보증은 setArguments 및 getArguments를 통해 번들을 통과 한 것입니다.

리스너 여야하는 경우 활동을 참조하는 방법이 있습니다.

public Dialog onCreateDialog(Bundle bundle) {
    OnClickListener listener = (OnClickListener) getActivity();
    ....
    return new AlertDialog.Builder(getActivity())
        ........
        .setAdapter(adapter, listener)
        .create();
}

그러나 Activity가 이벤트를 수신하기를 원하지 않습니다. Fragment가 필요합니다. 실제로 OnClickListener를 구현하는 모든 Java 객체 일 수 있습니다.

DialogFragment를 통해 AlertDialog를 표시하는 Fragment의 구체적인 예를 고려하십시오. 예 / 아니요 버튼이 있습니다. 이 버튼 누름을 생성 한 조각으로 다시 보내려면 어떻게해야합니까?


관련된 활동은 DialogFragment를 완전히 인식하지 못합니다.

조각 클래스 :

public class MyFragment extends Fragment {
int mStackLevel = 0;
public static final int DIALOG_FRAGMENT = 1;

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    if (savedInstanceState != null) {
        mStackLevel = savedInstanceState.getInt("level");
    }
}

@Override
public void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);
    outState.putInt("level", mStackLevel);
}

void showDialog(int type) {

    mStackLevel++;

    FragmentTransaction ft = getActivity().getFragmentManager().beginTransaction();
    Fragment prev = getActivity().getFragmentManager().findFragmentByTag("dialog");
    if (prev != null) {
        ft.remove(prev);
    }
    ft.addToBackStack(null);

    switch (type) {

        case DIALOG_FRAGMENT:

            DialogFragment dialogFrag = MyDialogFragment.newInstance(123);
            dialogFrag.setTargetFragment(this, DIALOG_FRAGMENT);
            dialogFrag.show(getFragmentManager().beginTransaction(), "dialog");

            break;
    }
}

@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
        switch(requestCode) {
            case DIALOG_FRAGMENT:

                if (resultCode == Activity.RESULT_OK) {
                    // After Ok code.
                } else if (resultCode == Activity.RESULT_CANCELED){
                    // After Cancel code.
                }

                break;
        }
    }
}

}

DialogFragment 클래스 :

public class MyDialogFragment extends DialogFragment {

public static MyDialogFragment newInstance(int num){

    MyDialogFragment dialogFragment = new MyDialogFragment();
    Bundle bundle = new Bundle();
    bundle.putInt("num", num);
    dialogFragment.setArguments(bundle);

    return dialogFragment;

}

@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {

    return new AlertDialog.Builder(getActivity())
            .setTitle(R.string.ERROR)
            .setIcon(android.R.drawable.ic_dialog_alert)
            .setPositiveButton(R.string.ok_button,
                    new DialogInterface.OnClickListener() {
                        public void onClick(DialogInterface dialog, int whichButton) {
                            getTargetFragment().onActivityResult(getTargetRequestCode(), Activity.RESULT_OK, getActivity().getIntent());
                        }
                    }
            )
            .setNegativeButton(R.string.cancel_button, new DialogInterface.OnClickListener() {
                public void onClick(DialogInterface dialog, int whichButton) {
                    getTargetFragment().onActivityResult(getTargetRequestCode(), Activity.RESULT_CANCELED, getActivity().getIntent());
                }
            })
            .create();
}
}

TargetFragment 솔루션은 IllegalStateException응용 프로그램이 파괴되고 재생성 된 후 생성 될 수 있기 때문에 대화 상자 조각에 가장 적합한 옵션으로 보이지 않습니다 . 이 경우 FragmentManager대상 조각을 찾을 수 없으며 다음 IllegalStateException과 같은 메시지가 표시됩니다.

"키 android : target_state : 인덱스 1에 대한 단편이 더 이상 존재하지 않습니다."

Fragment#setTargetFragment()자식 조각과 부모 조각 사이의 통신이 아니라 형제-조각 사이의 통신을위한 것 같습니다 .

따라서 다른 방법은 ChildFragmentManager활동을 사용하는 대신 부모 조각 을 사용하여 이와 같은 대화 조각을 만드는 것입니다 FragmentManager.

dialogFragment.show(ParentFragment.this.getChildFragmentManager(), "dialog_fragment");

그리고에, 인터페이스를 사용하여 onCreate의 방법 DialogFragment당신은 부모 조각을 얻을 수 있습니다 :

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    try {
        callback = (Callback) getParentFragment();
    } catch (ClassCastException e) {
        throw new ClassCastException("Calling fragment must implement Callback interface");
    }
}

남은 것은이 단계 후에 콜백 메소드를 호출하는 것입니다.

문제에 대한 자세한 내용은 다음 링크를 참조 하십시오. https://code.google.com/p/android/issues/detail?id=54520


어쩌면 조금 늦었지만 같은 질문을 가진 다른 사람들을 도울 수 있습니다.

표시하기 전에 setTargetFragmenton 을 사용할 수 있으며 Dialog대화 상자 getTargetFragment에서 참조를 얻기 위해 호출 할 수 있습니다 .


나는이 간단한 단계를 수행 하여이 일을했습니다.

  1. DialogFragmentCallbackInterface와 같은 방법으로 인터페이스를 만드십시오 callBackMethod(Object data). 데이터를 전달하기 위해 호출합니다.
  2. 이제 DialogFragmentCallbackInterface조각에서 인터페이스를 구현할 수 있습니다MyFragment implements DialogFragmentCallbackInterface
  3. DialogFragment생성하여 호출 조각 세트 MyFragment생성 대상 조각 등의 DialogFragment사용 myDialogFragment.setTargetFragment(this, 0)검사 setTargetFragment을 (조각 조각, INT requestCode가)

    MyDialogFragment dialogFrag = new MyDialogFragment();
    dialogFrag.setTargetFragment(this, 1); 
    
  4. DialogFragment호출 하여 대상 조각 객체를 가져 와서 getTargetFragment()캐스트하십시오 DialogFragmentCallbackInterface.이 인터페이스를 사용하여 조각으로 데이터를 보낼 수 있습니다.

    DialogFragmentCallbackInterface callback = 
               (DialogFragmentCallbackInterface) getTargetFragment();
    callback.callBackMethod(Object data);
    

    그게 다야! 이 인터페이스를 프래그먼트에 구현했는지 확인하십시오.


다른 조각과통신 안내서에 따르면 조각은 관련 활동을 통해 통신 해야합니다 .

예를 들어 한 조각이 다른 조각과 통신하기를 원할 수 있습니다 (예 : 사용자 이벤트를 기반으로 내용 변경). 모든 Fragment-to-Fragment 통신은 연관된 활동을 통해 수행됩니다. 두 개의 조각은 직접 통신해서는 안됩니다.


interface프래그먼트 클래스에서를 정의하고 해당 부모 인터페이스에서 해당 인터페이스를 구현해야합니다. 자세한 내용은 http://developer.android.com/guide/components/fragments.html#EventCallbacks 에 나와 있습니다 . 코드는 다음과 유사합니다.

파편:

public static class FragmentA extends DialogFragment {

    OnArticleSelectedListener mListener;

    // Container Activity must implement this interface
    public interface OnArticleSelectedListener {
        public void onArticleSelected(Uri articleUri);
    }

    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);
        try {
            mListener = (OnArticleSelectedListener) activity;
        } catch (ClassCastException e) {
            throw new ClassCastException(activity.toString() + " must implement OnArticleSelectedListener");
        }
    }
}

활동:

public class MyActivity extends Activity implements OnArticleSelectedListener{

    ...
    @Override
    public void onArticleSelected(Uri articleUri){

    }
    ...
}

나는 비슷한 문제에 직면했다. 내가 찾은 해결책은 다음과 같습니다.

  1. James McCracken이 위에서 설명한 것처럼 DialogFragment에서 인터페이스를 선언하십시오.

  2. 활동에서 인터페이스를 구현하십시오 (조각화가 아닙니다! 좋은 습관은 아닙니다).

  3. 활동의 콜백 메소드에서 수행하려는 작업을 수행하는 프래그먼트에서 필수 공용 함수를 호출하십시오.

따라서 DialogFragment-> Activity 및 Activity-> Fragment의 두 단계 프로세스가됩니다.


Fragment LiveWallFilterFragment (fragment 수신)에서 Fragment DashboardLiveWall (call fragment) 결과가 표시됩니다.

 LiveWallFilterFragment filterFragment = LiveWallFilterFragment.newInstance(DashboardLiveWall.this ,"");

 getActivity().getSupportFragmentManager().beginTransaction(). 
 add(R.id.frame_container, filterFragment).addToBackStack("").commit();

어디

public static LiveWallFilterFragment newInstance(Fragment targetFragment,String anyDummyData) {
        LiveWallFilterFragment fragment = new LiveWallFilterFragment();
        Bundle args = new Bundle();
        args.putString("dummyKey",anyDummyData);
        fragment.setArguments(args);

        if(targetFragment != null)
            fragment.setTargetFragment(targetFragment, KeyConst.LIVE_WALL_FILTER_RESULT);
        return fragment;
    }

다음과 같이 호출 결과로 다시 setResult

private void setResult(boolean flag) {
        if (getTargetFragment() != null) {
            Bundle bundle = new Bundle();
            bundle.putBoolean("isWorkDone", flag);
            Intent mIntent = new Intent();
            mIntent.putExtras(bundle);
            getTargetFragment().onActivityResult(getTargetRequestCode(),
                    Activity.RESULT_OK, mIntent);
        }
    }

onActivityResult

@Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);

        if (resultCode == Activity.RESULT_OK) {
            if (requestCode == KeyConst.LIVE_WALL_FILTER_RESULT) {

                Bundle bundle = data.getExtras();
                if (bundle != null) {

                    boolean isReset = bundle.getBoolean("isWorkDone");
                    if (isReset) {

                    } else {
                    }
                }
            }
        }
    }

업데이트 :

@CallbackFragmentand 를 사용하여 캐스팅을 생성하는 내 요지 코드를 기반으로 라이브러리를 만들었습니다 @Callback.

https://github.com/zeroarst/callbackfragment .

이 예제는 프래그먼트에서 다른 프래그먼트로 콜백을 보내는 예제를 제공합니다.

이전 답변 :

나는 BaseCallbackFragment주석을 만들었다 @FragmentCallback. 현재 확장 Fragment되어 있으며로 변경할 수 DialogFragment있으며 작동합니다. getTargetFragment ()> getParentFragment ()> 컨텍스트 (활동) 순서로 구현을 확인합니다.

그런 다음 확장하고 확장하여 인터페이스를 선언하고 주석을 지정하면 기본 조각이 나머지를 수행합니다. 주석 mandatory에는 프래그먼트가 콜백을 구현하도록 강제할지 여부를 결정 하는 매개 변수도 있습니다 .

public class EchoFragment extends BaseCallbackFragment {

    private FragmentInteractionListener mListener;

    @FragmentCallback
    public interface FragmentInteractionListener {
        void onEcho(EchoFragment fragment, String echo);
    }
}

https://gist.github.com/zeroarst/3b3f32092d58698a4568cdb0919c9a93


리스너를 프래그먼트로 설정하는 올바른 방법은 리스너를 첨부 할 때 설정하는 것입니다 . 내가 가진 문제는 onAttachFragment ()가 호출되지 않았다는 것입니다. 조사 후 getChildFragmentManager 대신 getFragmentManager사용하고 있음을 깨달았습니다.

내가하는 방법은 다음과 같습니다.

MyDialogFragment dialogFragment = MyDialogFragment.newInstance("title", "body");
dialogFragment.show(getChildFragmentManager(), "SOME_DIALOG");

onAttachFragment에 첨부하십시오.

@Override
public void onAttachFragment(Fragment childFragment) {
    super.onAttachFragment(childFragment);

    if (childFragment instanceof MyDialogFragment) {
        MyDialogFragment dialog = (MyDialogFragment) childFragment;
        dialog.setListener(new MyDialogFragment.Listener() {
            @Override
            public void buttonClicked() {

            }
        });
    }
}

공식 문서에 따르면 :

조각 #setTargetFragment

이 프래그먼트의 선택적 대상입니다. 예를 들어,이 프래그먼트가 다른 프래그먼트에 의해 시작되고 완료되면 결과를 처음으로 되돌리려 고 할 때 사용될 수 있습니다. 여기에 설정된 대상은 FragmentManager # putFragment를 통해 인스턴스 전체에 유지됩니다.

프래그먼트 #getTargetFragment

setTargetFragment (Fragment, int)로 설정된 대상 조각을 반환합니다.

그래서 당신은 이것을 할 수 있습니다 :

// In your fragment

public class MyFragment extends Fragment implements OnClickListener {
    private void showDialog() {
        DialogFragment dialogFrag = MyDialogFragment.newInstance(this);
        // Add this
        dialogFrag.setTargetFragment(this, 0);
        dialogFrag.show(getFragmentManager, null);
    }
    ...
}

// then

public class MyialogFragment extends DialogFragment {
    @Override
    public void onAttach(Context context) {
        super.onAttach(context);
        // Then get it
        Fragment fragment = getTargetFragment();
        if (fragment instanceof OnClickListener) {
            listener = (OnClickListener) fragment;
        } else {
            throw new RuntimeException("you must implement OnClickListener");
        }
    }
    ...
}

I solved this in an elegant way with RxAndroid. Receive an observer in the constructor of the DialogFragment and suscribe to observable and push the value when the callback being called. Then, in your Fragment create an inner class of the Observer, create an instance and pass it in the constructor of the DialogFragment. I used WeakReference in the observer to avoid memory leaks. Here is the code:

BaseDialogFragment.java

import java.lang.ref.WeakReference;

import io.reactivex.Observer;

public class BaseDialogFragment<O> extends DialogFragment {

    protected WeakReference<Observer<O>> observerRef;

    protected BaseDialogFragment(Observer<O> observer) {
        this.observerRef = new WeakReference<>(observer);
   }

    protected Observer<O> getObserver() {
    return observerRef.get();
    }
}

DatePickerFragment.java

public class DatePickerFragment extends BaseDialogFragment<Integer>
    implements DatePickerDialog.OnDateSetListener {


public DatePickerFragment(Observer<Integer> observer) {
    super(observer);
}

@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
    // Use the current date as the default date in the picker
    final Calendar c = Calendar.getInstance();
    int year = c.get(Calendar.YEAR);
    int month = c.get(Calendar.MONTH);
    int day = c.get(Calendar.DAY_OF_MONTH);

    // Create a new instance of DatePickerDialog and return it
    return new DatePickerDialog(getActivity(), this, year, month, day);
}

@Override
public void onDateSet(DatePicker view, int year, int month, int dayOfMonth) {
        if (getObserver() != null) {
            Observable.just(month).subscribe(getObserver());
        }
    }
}

MyFragment.java

//Show the dialog fragment when the button is clicked
@OnClick(R.id.btn_date)
void onDateClick() {
    DialogFragment newFragment = new DatePickerFragment(new OnDateSelectedObserver());
    newFragment.show(getFragmentManager(), "datePicker");
}
 //Observer inner class
 private class OnDateSelectedObserver implements Observer<Integer> {

    @Override
    public void onSubscribe(Disposable d) {

    }

    @Override
    public void onNext(Integer integer) {
       //Here you invoke the logic

    }

    @Override
    public void onError(Throwable e) {

    }

    @Override
    public void onComplete() {

    }
}

You can see the source code here: https://github.com/andresuarezz26/carpoolingapp

참고URL : https://stackoverflow.com/questions/13733304/callback-to-a-fragment-from-a-dialogfragment

반응형