डायलॉगफ्रैगमेंट से फ्रैगमेंट को कॉलबैक


159

प्रश्न: डायलॉगफ्रैगमेंट से दूसरे फ्रैगमेंट में कॉलबैक कैसे बनता है। मेरे मामले में, शामिल गतिविधि डायलॉगफ्रेगमेंट से पूरी तरह से अनजान होनी चाहिए।

मेरे पास विचार करें

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

लेकिन इस बात की कोई गारंटी नहीं है कि डायलॉगफ्रेगमेंट रुकने और अपने जीवनचक्र के माध्यम से फिर से शुरू होने पर श्रोता आसपास होंगे। Fragment में एकमात्र गारंटी वे हैं जो एक बंडल में setArguments और getArguments के माध्यम से पास की जाती हैं।

यदि श्रोता होना चाहिए तो गतिविधि को संदर्भित करने का एक तरीका है:

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

लेकिन मैं नहीं चाहता कि गतिविधि घटनाओं के लिए सुने, मुझे एक परिमार्जन की आवश्यकता है। वास्तव में, यह कोई भी जावा ऑब्जेक्ट हो सकता है जो OnClickListener को लागू करता है।

एक Fragment के ठोस उदाहरण पर विचार करें जो DialogFragment के माध्यम से एक AlertDialog प्रस्तुत करता है। इसमें Yes / No बटन है। मैं उस बटन को वापस कैसे भेज सकता हूं जो इसे बनाए गए फ्रेग्मेंट में है?


आपने उल्लेख किया "लेकिन इस बात की कोई गारंटी नहीं है कि श्रोता चारों ओर होंगे यदि डायलॉगफ्रेग्मेंट अपने जीवनचक्र के माध्यम से रुकता और फिर से शुरू होता है।" मैंने सोचा कि फ्रैडमेंट राज्य ऑनडेस्ट्रॉय () के दौरान नष्ट हो जाते हैं? आपको सही होना चाहिए, लेकिन मैं अभी थोड़ा भ्रमित हूं कि अब फ्रैगमेंट राज्य का उपयोग कैसे करें। मैंने आपके द्वारा बताई गई समस्या को कैसे पुन: पेश किया, श्रोता आसपास नहीं है?
सीन

मैं यह नहीं देखता कि आप OnClickListener listener = (OnClickListener) getParentFragment();इसके बजाय डायलॉगफ्रैगमेंट में बस का उपयोग क्यों नहीं कर सकते हैं , और आपका मुख्य टुकड़ा इंटरफ़ेस को लागू करता है जैसा कि आपने मूल रूप से किया था।
kiruwka

यहाँ एक असंबंधित प्रश्न का उत्तर है, लेकिन यह आपको दिखाता है कि यह कैसे साफ तरीके से किया जाता है stackoverflow.com/questions/28620026/…
user2288580

जवाबों:


190

इसमें शामिल गतिविधि डायलॉगफ्रेगमेंट से पूरी तरह से अनजान है।

फ्रैगमेंट क्लास:

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();
}
}

100
मुझे लगता है कि यहाँ कुंजी है setTargetFragmentऔर getTargetFragment। का उपयोग onActivityResultथोड़ा अस्पष्ट है। यह शायद बेहतर होगा कि आप फ्रैगमेंट कॉलर में अपनी खुद की विशिष्ट विधि की घोषणा करें, और इसका उपयोग करें, इसके बजाय onActivityResult का पुन: उपयोग कर सकते हैं। लेकिन उस बिंदु पर इसके सभी शब्दार्थ।
अनन्तमत्त e

2
स्टैक स्तर चर का उपयोग नहीं किया जाता है?
डिस्प्ले का नाम

6
क्या यह परिवर्तन-रोटेशन से बचेगा?
मैक्सरनर

3
इसका इस्तेमाल किया। नोट्स: रोटेशन या नींद से बचने के लिए स्टैक स्तर आवश्यक नहीं था। OnActivityResult के बजाय, मेरे टुकड़े का कार्यान्वयन DialogResultHandler # हैंडलDialogResult (एक इंटरफ़ेस जो मैंने बनाया है)। @myCode, एक ऐसे डायलॉग को दिखाने के लिए सुपर मददगार होगा, जिसे इंटेंट में जोड़ा जा रहा है, और फिर अपने onActiveResult के अंदर पढ़ें। शुरुआती लोगों के लिए इरादे स्पष्ट नहीं हैं।
क्रिस बेटी

7
@eternalmatt, आपकी आपत्ति पूरी तरह से उचित है, लेकिन मुझे लगता है कि onActivityResult () का मूल्य यह है कि किसी भी Fragment पर मौजूद होने की गारंटी है, इसलिए किसी भी Fragment का उपयोग माता-पिता के रूप में किया जा सकता है। यदि आप अपना स्वयं का इंटरफ़ेस बनाते हैं और माता-पिता के टुकड़े को लागू करते हैं, तो बच्चे का उपयोग केवल उस इंटरफ़ेस को लागू करने वाले माता-पिता के साथ किया जा सकता है। यदि आप बच्चे को अधिक व्यापक रूप से बाद में उपयोग करना शुरू करते हैं तो बच्चे को उस इंटरफ़ेस पर युग्मित करना आपको परेशान करने के लिए वापस आ सकता है। "बिल्ट-इन" onActivityResult () इंटरफ़ेस का उपयोग करने के लिए अतिरिक्त युग्मन की आवश्यकता नहीं होती है, इसलिए यह आपको थोड़ा अधिक लचीलापन देता है।
Dalbergia

78

TargetFragment समाधान संवाद टुकड़ों के लिए सबसे अच्छा विकल्प नहीं लगता क्योंकि यह IllegalStateExceptionएप्लिकेशन के नष्ट होने और फिर से बनाए जाने के बाद बना सकता है । इस मामले FragmentManagerमें लक्ष्य टुकड़ा नहीं मिल सका और आपको IllegalStateExceptionइस तरह एक संदेश मिलेगा :

"कुंजी अब Android के लिए मौजूद नहीं है: target_state: index 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


2
यह एपी 23 में शुरू किए गए onAttach (संदर्भ संदर्भ) के साथ भी काम करता है।
सांता टेकलाडो

1
यह स्वीकृत उत्तर होना चाहिए। वर्तमान स्वीकृत उत्तर छोटी गाड़ी है और टुकड़ों का इस तरह उपयोग करने के लिए नहीं है।
NecipAllef

3
@ अहमदाबादमाडली समस्या यहाँ टुकड़ों के बीच संचार के लिए सही संदर्भ (माता-पिता) प्राप्त करना है। यदि आप गतिविधि के एक बच्चे के रूप में संवाद टुकड़े का उपयोग करने वाले हैं, तो कोई भ्रम नहीं होना चाहिए। फ्रैगमेंट मैनजर ऑफ़ एक्टिविटी और गेटअक्टिविटी () कॉलबैक प्राप्त करने के लिए पर्याप्त है।
ओगुज़ ओज़कान

1
यह स्वीकृत उत्तर होना चाहिए। यह स्पष्ट रूप से समझाया गया है और विस्तृत है, यह सिर्फ लोगों पर फेंका गया कोड नहीं है।
विंस

1
@lukecross ParentFragment वह टुकड़ा है जो DialogFragment बनाता है (एक जो शो बुलाता है ()) लेकिन ऐसा लगता है कि childFragmentManager पुन: संयोजन / स्क्रीन रोटेशन से बचे नहीं है ...
iwat05s

34

मैंने इस सामान को करने के लिए सरल चरणों का पालन किया।

  1. जैसे DialogFragmentCallbackInterfaceकुछ विधि के साथ इंटरफ़ेस बनाएँ callBackMethod(Object data)। जिसे आप डेटा पास करने के लिए कहेंगे।
  2. अब आप DialogFragmentCallbackInterfaceअपने टुकड़े में इंटरफ़ेस को लागू कर सकते हैं जैसेMyFragment implements DialogFragmentCallbackInterface
  3. के समय DialogFragmentनिर्माण अपने प्रेरक टुकड़ा सेट MyFragmentलक्ष्य टुकड़ा जो बनाया के रूप में DialogFragmentउपयोग myDialogFragment.setTargetFragment(this, 0)की जांच setTargetFragment (टुकड़ा टुकड़ा, पूर्णांक requestCode)

    MyDialogFragment dialogFrag = new MyDialogFragment();
    dialogFrag.setTargetFragment(this, 1); 
  4. DialogFragmentकॉल करके अपने टारगेट टुकड़ा ऑब्जेक्ट को प्राप्त करें getTargetFragment()और इसे कास्ट करें। DialogFragmentCallbackInterfaceअब आप इस इंटरफेस का उपयोग अपने टुकड़े को डेटा भेजने के लिए कर सकते हैं।

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

    यह सब किया है! बस सुनिश्चित करें कि आपने इस इंटरफ़ेस को अपने टुकड़े में लागू किया है।


4
यह सबसे अच्छा जवाब होना चाहिए। बहुत बढ़िया जवाब।
मो। सजदुल करीम

स्रोत और गंतव्य खंड दोनों के लिए समान फ़्रैगमेंट प्रबंधक का उपयोग करना सुनिश्चित करें, अन्यथा getTargetFragment काम नहीं करेगा। इसलिए यदि आप चाइल्डफ्रैगमेंट मैनजर का उपयोग कर रहे हैं, तो यह काम नहीं करेगा क्योंकि स्रोत टुकड़ा चाइल्ड फ्रैगमेंट मैनेजर द्वारा प्रतिबद्ध नहीं है। माता-पिता / बच्चे के टुकड़े के बजाय इन 2 टुकड़ों को भाई-बहन के टुकड़े के रूप में सोचना सबसे अच्छा है।
Thupten

स्पष्ट रूप से, 2 सिबल टुकड़े के बीच संचार करते समय केवल लक्ष्य खंड पैटर्न का उपयोग करना बेहतर होता है। श्रोता नहीं होने से, आप गलती से खंड 2 में खंड 1 को लीक करने से बचते हैं। लक्ष्य खंड का उपयोग करते समय, श्रोता / कॉलबैक का उपयोग न करें। केवल onActivityResult(request code, resultcode, intent)परिणाम के लिए वापस लौटने के लिए उपयोग करें १। खंड 1 से, setTargetFragment()और खंड 2 से, उपयोग करें getTargetFragment()। जब माता-पिता / बच्चे के टुकड़े को टुकड़े या गतिविधि से टुकड़े करने के लिए उपयोग करते हैं, तो आप श्रोता या कॉलबैक का उपयोग कर सकते हैं क्योंकि बच्चे के टुकड़े में माता-पिता को लीक करने का कोई खतरा नहीं है।
थुपटेन

@ जब आप "लीक" कहते हैं तो क्या आपका मतलब मेमोरी लीक या "लीक कार्यान्वयन विवरण" से है? मुझे नहीं लगता कि विजय का जवाब रिटर्न वैल्यू के लिए onActivityResulty का उपयोग करने की तुलना में मेमोरी को लीक करेगा। दोनों पैटर्न लक्ष्यीकरण के संदर्भ को बनाए रखेंगे। यदि आपका मतलब कार्यान्वयन विवरण लीक करना है, तो मुझे लगता है कि उसका पैटर्न onActivityResult से भी बेहतर है। कॉलबैक विधि स्पष्ट है (यदि सही नाम दिया गया है)। यदि आप सभी वापस प्राप्त करते हैं तो ठीक है और रद्द कर दिया गया है, पहले टुकड़े की व्याख्या करना है कि उन लोगों का क्या मतलब है।
tir38

34

शायद थोड़ा देर से, लेकिन अन्य लोगों की मदद कर सकते हैं जैसे मैंने किया था।

आप उपयोग कर सकते हैं setTargetFragmentपर Dialogदिखाने से पहले, और संवाद में आप कॉल कर सकते हैं getTargetFragmentसंदर्भ मिलता है।


यहाँ एक अन्य प्रश्न का उत्तर है लेकिन यह आपके प्रश्न पर भी लागू होता है और एक स्वच्छ समाधान है: stackoverflow.com/questions/28620026/…
user2288580

मेरे लिए IllegalStateException
luke cross

19

संचार अन्य टुकड़े के साथ गाइड टुकड़े करना चाहिए कहते हैं संबद्ध गतिविधि के माध्यम से संवाद

अक्सर आप चाहते हैं कि एक फ्रैगमेंट दूसरे के साथ संवाद करने के लिए होगा, उदाहरण के लिए उपयोगकर्ता घटना के आधार पर सामग्री को बदलने के लिए। सभी फ्रैगमेंट-टू-फ्रैगमेंट संचार संबंधित गतिविधि के माध्यम से किया जाता है। दो टुकड़े कभी सीधे संवाद नहीं करना चाहिए।


1
भीतर के टुकड़े के बारे में क्या है कि कैसे एक और टुकड़े के भीतर एक टुकड़ा होना चाहिए टुकड़ा को होस्ट करने के लिए संवाद
रवि

@ रवी: प्रत्येक अंश को उस गतिविधि से संवाद करना चाहिए जो गेटएक्टिविटी () कहकर सभी अंशों के लिए सामान्य है ।
एडवर्ड ब्रे

1
@ क्रिस: यदि टुकड़े को चल रहे संचार की आवश्यकता होती है, तो लागू करने के लिए प्रत्येक उपयुक्त टुकड़े के लिए एक इंटरफ़ेस परिभाषित करें। गतिविधि का काम तब इंटरफ़ेस बिंदुओं के साथ उनके समकक्ष टुकड़ों को टुकड़े प्रदान करने तक सीमित है। उसके बाद, टुकड़े इंटरफेस के माध्यम से "सीधे" सुरक्षित रूप से संवाद कर सकते हैं।
एडवर्ड ब्रे

3
मुझे लगता है कि जैसे ही टुकड़ों के उपयोग को विस्तारित किया गया है, प्रत्यक्ष टुकड़ा संचार का उपयोग नहीं करने के मूल विचार को तोड़ दिया गया है। जैसे कि नेविगेशन ड्रावर में गतिविधि के प्रत्येक तत्काल बच्चे के टुकड़े लगभग एक गतिविधि के रूप में कार्य कर रहे हैं। तो इस तरह के एक संवाद के रूप में एक टुकड़ा होने के रूप में गतिविधि के माध्यम से संवाद संचारनीयता / लचीलापन IMO को हानि पहुँचाता है। वास्तव में यह पुन: प्रयोज्य तरीके से गतिविधियों और टुकड़े दोनों के साथ काम करने की अनुमति देने के लिए डायलफ्रैगमेंट को एनकैप्सुलेट करने का कोई अच्छा तरीका नहीं लगता है।
सैम

16
मुझे पता है कि यह पुराना है, लेकिन किसी और के यहां आने पर मुझे ऐसा लगता है कि इस मामले में बात की गई बात उस दस्तावेज़ में लागू नहीं होती है जब एक टुकड़ा "मालिक" होता है जो कि डायलॉगफ्रैगमेंट के निर्माण और प्रबंधन को निर्धारित करने के लिए उपयोग किया जाता है। अपने विखंडन से कनेक्शन का एक गुच्छा बनाने के लिए अजीब तरह की गतिविधि होती है जब गतिविधि यह भी सुनिश्चित नहीं करती है कि डायलॉग क्यों बनाया जा रहा है या किन शर्तों के तहत इसे खारिज किया जाना चाहिए। इसके अलावा DialogFragment सुपर सरल है, और केवल उपयोगकर्ता को सूचित करने और संभावित रूप से प्रतिक्रिया प्राप्त करने के लिए मौजूद है।
क्रिस

12

आपको interfaceअपने खंड में परिभाषित करना चाहिए और उस इंटरफ़ेस को उसकी मूल गतिविधि में लागू करना चाहिए । विवरण यहाँ उल्लिखित है http://developer.android.com/guide/compenders/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
मुझे लगता है कि आपने डॉक्स को बहुत जल्दी स्किम कर लिया है। ये दोनों कोड खंड हैं FragmentAऔर वह मान रहा है कि गतिविधि एक है OnArticleSelectedListener, न कि उस खंड ने जो उसे शुरू किया था।
शाश्वत

2
मैं इस बात पर विचार करूंगा कि आप क्या बुरा अभ्यास करने की कोशिश कर रहे हैं। Android दिशानिर्देशों का सुझाव है कि सभी टुकड़ा-टू-टुकड़ा संचार गतिविधि (प्रति डेवलपर . android.com/training/basics/fragments/… ) के माध्यम से होता है । यदि आप वास्तव में चाहते हैं कि यह सब MyFragmentआपके भीतर संभाला जाए, तो आप नियमित रूप से उपयोग करने के लिए स्विच कर सकते हैंAlertDialog
जेम्स मैकक्रैकन

1
मुझे लगता है कि टुकड़ों के एक दूसरे से सीधे बात करने के साथ चिंता यह है कि कुछ लेआउट में सभी टुकड़े लोड नहीं हो सकते हैं और जैसा कि वे उदाहरण में दिखाते हैं कि टुकड़े में स्विच करना आवश्यक हो सकता है। मुझे नहीं लगता कि एक खंड से एक संवाद टुकड़ा लॉन्च करने की बात करते समय चिंता वैध है।

मैंने इसे अपनी गतिविधियों के लिए लागू किया है। प्रश्न: क्या इस समाधान को इस तरह बढ़ाया जा सकता है कि एक टुकड़ा इस संवाद को तुरंत लागू कर सके?
बिल मोटे

1
यह एक वास्तुशिल्प दृष्टिकोण से एक अच्छा अभ्यास है, और इस तरह के रूप में स्वीकार किया जाना चाहिए। OnActivityResult का उपयोग करने से स्पेगेटी आर्किटेक्चर होता है
ब्रूनो कैरियर

4

किसी श्रोता को किसी खंड से जोड़ने का सही तरीका यह है कि इसे संलग्न करते समय सेट किया जाए । मेरे पास समस्या यह थी कि 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() {

            }
        });
    }
}

3

आधिकारिक दस्तावेज के अनुसार:

टुकड़ा # 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");
        }
    }
    ...
}

क्या आप अपनी व्याख्या कर सकते हैं?
यिलमाज़

इस मामले में, हमें "MyialogFragment" के लिए "MyFragment" संदर्भ पास करने की आवश्यकता है, और "Fragment" इसे करने की विधि प्रदान करता है। मैंने आधिकारिक दस्तावेज का विवरण जोड़ा, यह मुझे स्पष्ट रूप से कहना चाहिए।
SUPERYAO

2

मैं एक ऐसी ही समस्या का सामना कर रहा था। मुझे जो समाधान मिला वह था:

  1. अपने संवाद में एक अंतरफलक की घोषणा करें जैसे जेम्स मैकक्रैकन ने ऊपर बताया है।

  2. अपनी गतिविधि में इंटरफ़ेस को लागू करें (टुकड़ा नहीं! यह एक अच्छा अभ्यास नहीं है)।

  3. अपनी गतिविधि में कॉलबैक विधि से, अपने टुकड़े में एक आवश्यक सार्वजनिक फ़ंक्शन को कॉल करें जो वह कार्य करता है जो आप करना चाहते हैं।

इस प्रकार, यह एक दो-चरण प्रक्रिया बन जाती है: DialogFragment -> गतिविधि और फिर गतिविधि -> टुकड़ा


1

मैं इस तरह से Fragment LiveWallFilterFragment (टुकड़ा प्राप्त) से Fragment 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 {
                    }
                }
            }
        }
    }

1

अपडेट किया गया:

मैंने अपने जिस्ट कोड के आधार पर एक पुस्तकालय बनाया जो उपयोग करके @CallbackFragmentऔर आपके लिए उन कास्टिंग को उत्पन्न करता है @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


1

कोटलिन दोस्तों यहाँ हम चलते हैं!

तो हमारे पास समस्या यह है कि हमने एक गतिविधि बनाई है MainActivity, उस गतिविधि पर हमने एक खंड बनाया है, FragmentAऔर अब हम FragmentAकॉल के शीर्ष पर एक संवाद टुकड़ा बनाना चाहते हैं FragmentB। बिना FragmentBपीछे FragmentAकिए हम परिणाम कैसे प्राप्त करते हैं MainActivity?

ध्यान दें:

  1. FragmentAका एक बच्चा टुकड़ा है MainActivityFragmentAहम बनाए गए अंशों का प्रबंधन करने के लिए उपयोग करेंगे childFragmentManagerजो ऐसा करता है!
  2. FragmentAएक अभिभावक टुकड़ा है FragmentB, जिसका उपयोग हम FragmentAअंदर से FragmentBकरेंगे parenFragment

कहा कि अंदर FragmentA,

class FragmentA : Fragment(), UpdateNameListener {
    override fun onSave(name: String) {
        toast("Running save with $name")
    }

    // call this function somewhere in a clickListener perhaps
    private fun startUpdateNameDialog() {
        FragmentB().show(childFragmentManager, "started name dialog")
    }
}

यहाँ संवाद टुकड़ा है FragmentB

class FragmentB : DialogFragment() {

    private lateinit var listener: UpdateNameListener

    override fun onAttach(context: Context) {
        super.onAttach(context)
        try {
            listener = parentFragment as UpdateNameListener
        } catch (e: ClassCastException) {
            throw ClassCastException("$context must implement UpdateNameListener")
        }
    }

    override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
        return activity?.let {
            val builder = AlertDialog.Builder(it)
            val binding = UpdateNameDialogFragmentBinding.inflate(LayoutInflater.from(context))
            binding.btnSave.setOnClickListener {
                val name = binding.name.text.toString()
                listener.onSave(name)
                dismiss()
            }
            builder.setView(binding.root)
            return builder.create()
        } ?: throw IllegalStateException("Activity can not be null")
    }
}

यहाँ दो को जोड़ने वाला इंटरफ़ेस है।

interface UpdateNameListener {
    fun onSave(name: String)
}

बस।


1
मैंने इस दस्तावेज़ का अनुसरण किया: developer.android.com/guide/topics/ui/dialogs और यह काम नहीं किया। बहुत बहुत धन्यवाद। मुझे उम्मीद है कि यह पेरेंटफ्रैगमेंट चीज हर बार उम्मीद की तरह काम करती है :)
उमुतटेकिन

1
श्रोता को onDetach के अंदर अशक्त करने के लिए मत भूलना :)
BekaBot

@BekaBot टिप्पणी के लिए धन्यवाद। मैंने कुछ शोध किए हैं और ऐसा प्रतीत होता है कि श्रोताओं को बंद करना आवश्यक नहीं है। stackoverflow.com/a/37031951/10030693
सेन्स्योजो

0

मैंने इसे RxAndroid के साथ सुरुचिपूर्ण तरीके से हल किया। 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


1
एंड्रॉइड के बारे में मजेदार बात यह है कि कुछ को जीवनचक्र कहा जाता है। बेस टुकड़ा या संवाद टुकड़ा जीवन चक्र की घटनाओं पर राज्य (और उनके कनेक्शन) को संरक्षित करने में सक्षम होने की आवश्यकता है। कॉलबैक या पर्यवेक्षकों को क्रमबद्ध नहीं किया जा सकता है और इसलिए यहां एक ही मुद्दा है।
गैंडर
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.