[android] DialogFragment에서 단편 콜백



4 Answers

TargetFragment 솔루션은 응용 프로그램을 파괴하고 다시 만든 후 IllegalStateException 을 만들 수 있으므로 대화 상자 조각에 가장 적합한 옵션으로 보이지 않습니다. 이 경우 FragmentManager 가 대상 조각을 찾을 수 없으며 다음과 같은 메시지가있는 IllegalStateException 이 발생합니다.

"핵심 안드로이드에 대한 단편이 더 이상 존재하지 않습니다 : target_state : index 1"

Fragment#setTargetFragment() 는 하위 단편과 상위 단편 사이의 통신이 아니라 형제 단편 간의 통신용으로 사용됩니다.

그래서 다른 방법은 FragmentManager 액티비티를 사용하는 대신 부모 조각의 ChildFragmentManager 를 사용하여 이와 같은 대화 상자 조각을 만드는 것입니다.

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

Interface를 사용하여 DialogFragmentonCreate 메소드에서 부모 조각을 얻을 수 있습니다.

@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 하십시오. https://code.google.com/p/android/issues/detail?id=54520

Question

질문 : 어떻게 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를 통해 Bundle을 통해 전달되는 것입니다.

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

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

그러나 나는 활동이 사건을 경청하는 것을 원하지 않는다. 나는 단편이 필요하다. 실제로 그것은 OnClickListener를 구현하는 모든 Java 객체 일 수 있습니다.

DialogFragment를 통해 AlertDialog를 제공하는 Fragment의 구체적인 예를 고려해보십시오. Yes / No 버튼이 있습니다. 어떻게 이러한 버튼 누름을 생성 한 프래그먼트로 다시 보낼 수 있습니까?




프래그먼트 클래스에 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. callBackMethod(Object data) 와 같은 메소드를 사용하여 DialogFragmentCallbackInterface 와 같은 인터페이스를 생성하십시오. 데이터를 전달하기 위해 호출 할 대상
  2. 이제 DialogFragmentCallbackInterface 를 구현하는 DialogFragmentCallbackInterface 인터페이스를 구현할 수 있습니다.
  3. DialogFragment 만들 때 DialogFragment 를 만든 대상 조각으로 호출 조각 인 MyFragment 를 설정합니다. myDialogFragment.setTargetFragment(this, 0) check setTargetFragment (Fragment fragment, int requestCode)

    MyDialogFragment dialogFrag = new MyDialogFragment();
    dialogFrag.setTargetFragment(this, 1); 
    
  4. getTargetFragment() 를 호출하여 대상 조각 객체를 DialogFragmentDialogFragment 에 캐스트합니다. DialogFragmentCallbackInterface 인터페이스를 사용하여 조각에 데이터를 보낼 수 있습니다.

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

    그게 다 끝났어! 단편에서이 인터페이스를 구현했는지 확인하십시오.




조각 LiveWallFilterFragment (조각 수신)에서 조각 DashboardLiveWall (조각 호출) 결과가 나타납니다.

 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 {
                    }
                }
            }
        }
    }



RxAndroid를 사용하여 우아한 방식으로이 문제를 해결했습니다. DialogFragment의 생성자에서 관찰자를 수신하고 관찰 가능하도록 선언하고 콜백이 호출 될 때 값을 푸시합니다. 그런 다음 여러분의 Fragment에서 Observer의 내부 클래스를 생성하고, 인스턴스를 생성하여 DialogFragment의 생성자에 전달합니다. 나는 메모리 누수를 피하기 위해 관찰자에서 WeakReference를 사용했다. 다음은 코드입니다.

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() {

    }
}

https://github.com/andresuarezz26/carpoolingapp 에서 소스 코드를 볼 수 있습니다.




Related