OnFragmentInteractionListener को कैसे लागू करें


151

मेरे पास एंड्रॉइड स्टूडियो 0.8.2 में नेविगेशन दराज के साथ एक विज़ार्ड जनरेट किया गया ऐप है

मैंने एक खंड बनाया है और इसे newInstance () के साथ जोड़ा है और मुझे यह त्रुटि मिली है:

com.domain.myapp E / AndroidRuntime EX FATAL EXCEPTION: मुख्य java.lang.ClassCastException: com.domain.myapp.MainActivity@422fb8ff OnFragmentInteractionListener को लागू करना चाहिए

मैं कहीं भी नहीं मिल सकता है कि इस OnFragmentInteractionListener को कैसे लागू किया जाए ?? यह android sdk प्रलेखन में भी नहीं पाया जा सकता है!

MainActivity.java

import android.app.Activity;

import android.app.ActionBar;
import android.app.Fragment;
import android.app.FragmentManager;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.support.v4.widget.DrawerLayout;


public class MainActivity extends Activity
    implements NavigationDrawerFragment.NavigationDrawerCallbacks {

/**
 * Fragment managing the behaviors, interactions and presentation of the navigation drawer.
 */
private NavigationDrawerFragment mNavigationDrawerFragment;

/**
 * Used to store the last screen title. For use in {@link #restoreActionBar()}.
 */
private CharSequence mTitle;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    mNavigationDrawerFragment = (NavigationDrawerFragment)
            getFragmentManager().findFragmentById(R.id.navigation_drawer);
    mTitle = getTitle();

    // Set up the drawer.
    mNavigationDrawerFragment.setUp(
            R.id.navigation_drawer,
            (DrawerLayout) findViewById(R.id.drawer_layout));
}

@Override
public void onNavigationDrawerItemSelected(int position) {
    // update the main content by replacing fragments
    FragmentManager fragmentManager = getFragmentManager();

    switch (position) {
        case 0: fragmentManager.beginTransaction()
                .replace(R.id.container, PlaceholderFragment.newInstance(position + 1))
                .commit(); break; 
        case 1: fragmentManager.beginTransaction() 
                .replace(R.id.container, AboutFragment.newInstance("test1", "test2"))
                .commit(); break; // this crashes the app
        case 2: fragmentManager.beginTransaction()
                .replace(R.id.container, BrowseQuotesFragment.newInstance("test1", "test2"))
                .commit(); break; // this crashes the app
    }
}


public void onSectionAttached(int number) {
    switch (number) {
        case 1:
            mTitle = getString(R.string.title_section1);
            break;
        case 2:
            mTitle = getString(R.string.title_section2);
            break;
        case 3:
            mTitle = getString(R.string.title_section3);
            break;
    }
}

public void restoreActionBar() {
    ActionBar actionBar = getActionBar();
    actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD);
    actionBar.setDisplayShowTitleEnabled(true);
    actionBar.setTitle(mTitle);
}


@Override
public boolean onCreateOptionsMenu(Menu menu) {
    if (!mNavigationDrawerFragment.isDrawerOpen()) {
        // Only show items in the action bar relevant to this screen
        // if the drawer is not showing. Otherwise, let the drawer
        // decide what to show in the action bar.
        getMenuInflater().inflate(R.menu.main, menu);
        restoreActionBar();
        return true;
    }
    return super.onCreateOptionsMenu(menu);
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    // Handle action bar item clicks here. The action bar will
    // automatically handle clicks on the Home/Up button, so long
    // as you specify a parent activity in AndroidManifest.xml.
    int id = item.getItemId();
    if (id == R.id.action_settings) {
        return true;
    }
    return super.onOptionsItemSelected(item);
}

/**
 * A placeholder fragment containing a simple view.
 */
public static class PlaceholderFragment extends Fragment {
    /**
     * The fragment argument representing the section number for this
     * fragment.
     */
    private static final String ARG_SECTION_NUMBER = "section_number";

    /**
     * Returns a new instance of this fragment for the given section
     * number.
     */
    public static PlaceholderFragment newInstance(int sectionNumber) {
        PlaceholderFragment fragment = new PlaceholderFragment();
        Bundle args = new Bundle();
        args.putInt(ARG_SECTION_NUMBER, sectionNumber);
        fragment.setArguments(args);
        return fragment;
    }

    public PlaceholderFragment() {
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        View rootView = inflater.inflate(R.layout.fragment_main, container, false);
        return rootView;
    }

    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);
        ((MainActivity) activity).onSectionAttached(
                getArguments().getInt(ARG_SECTION_NUMBER));
    }
}

}

जवाबों:


120

यहां पोस्ट किए गए उत्तरों से मदद नहीं मिली, लेकिन निम्नलिखित लिंक ने किया:

http://developer.android.com/training/basics/fragments/communicating.html

एक इंटरफ़ेस परिभाषित करें

public class HeadlinesFragment extends ListFragment {
    OnHeadlineSelectedListener mCallback;

    // Container Activity must implement this interface
    public interface OnHeadlineSelectedListener {
        public void onArticleSelected(int position);
    }

    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);

        // This makes sure that the container activity has implemented
        // the callback interface. If not, it throws an exception
        try {
            mCallback = (OnHeadlineSelectedListener) activity;
        } catch (ClassCastException e) {
            throw new ClassCastException(activity.toString()
                    + " must implement OnHeadlineSelectedListener");
        }
    }

    ...
}

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

@Override
public void onListItemClick(ListView l, View v, int position, long id) {
    // Send the event to the host activity
    mCallback.onArticleSelected(position);
}

इंटरफ़ेस लागू करें

उदाहरण के लिए, निम्नलिखित गतिविधि उपरोक्त उदाहरण से इंटरफ़ेस को लागू करती है।

public static class MainActivity extends Activity
        implements HeadlinesFragment.OnHeadlineSelectedListener{
    ...

    public void onArticleSelected(int position) {
        // The user selected the headline of an article from the HeadlinesFragment
        // Do something here to display that article
    }
}

एपीआई 23: 8/31/2015 के लिए अपडेट

ओवररेटेड विधि onAttach(Activity activity)अब पदावनत हो गई है android.app.Fragment, कोड को अपग्रेड किया जाना चाहिएonAttach(Context context)

@Override
public void onAttach(Context context) {
    super.onAttach(context);
}


@Override
public void onStart() {
    super.onStart();
    try {
        mListener = (OnFragmentInteractionListener) getActivity();
    } catch (ClassCastException e) {
        throw new ClassCastException(getActivity().toString()
                + " must implement OnFragmentInteractionListener");
    }
}

7
कृपया ध्यान दें कि onAttach(Activity activity);पदावनत किया गया है, और उसके साथ बदल दिया गया हैonAttach(Context context)
EpicPandaForce

1
@EpicPandaForce वास्तव में आप सही हैं, मैंने प्रतिबिंबित करने के लिए अपनी पोस्ट अपडेट की है कि
meda

1
क्या कोई कारण है कि यह onAttach से onStart तक चलता है? क्या मैं अभी भी इसे केवल गतिविधि के बजाय संदर्भ का उपयोग करके ऑनऑट में डाल सकता हूं?
लुई त्सई

मुझे लगता है कि बस का उपयोग onAttach(context)करना ठीक काम करेगा
EpicPandaForce

212

आप में से जो लोग अभी भी @meda उत्तर को पढ़ने के बाद नहीं समझ पाते हैं, उनके लिए इस मुद्दे के लिए मेरा संक्षिप्त और पूर्ण विवरण है:

मान लें कि आपके पास 2 फ़्रैगमेंट हैं, Fragment_Aऔर Fragment_Bजो ऐप से ऑटो-जेनरेट होते हैं। आपके द्वारा उत्पन्न अंशों के निचले भाग पर, आप यह कोड खोजने जा रहे हैं:

public class Fragment_A extends Fragment {

    //rest of the code is omitted

    public interface OnFragmentInteractionListener {
        // TODO: Update argument type and name
        public void onFragmentInteraction(Uri uri);
    }
}

public class Fragment_B extends Fragment {

    //rest of the code is omitted

    public interface OnFragmentInteractionListener {
        // TODO: Update argument type and name
        public void onFragmentInteraction(Uri uri);
    }
}

समस्या को दूर करने के लिए, आपको onFragmentInteractionअपनी गतिविधि में विधि जोड़ना होगा , जिसे मेरे मामले में नाम दिया गया है MainActivity2। उसके बाद, आपको इस तरह से implementsसभी टुकड़ों की आवश्यकता है MainActivity:

public class MainActivity2 extends ActionBarActivity
        implements Fragment_A.OnFragmentInteractionListener, 
                   Fragment_B.OnFragmentInteractionListener, 
                   NavigationDrawerFragment.NavigationDrawerCallbacks {
    //rest code is omitted

    @Override
    public void onFragmentInteraction(Uri uri){
        //you can leave it empty
    }
}

पुनश्च: संक्षेप में, इस पद्धति का उपयोग टुकड़ों के बीच संचार के लिए किया जा सकता है। आप में से जो इस विधि के बारे में अधिक जानना चाहते हैं, कृपया इस लिंक को देखें ।


10
एंड्रॉइड स्टूडियो में एसडीके के वर्तमान संस्करण के साथ, आपको उस पद्धति को लागू करने की आवश्यकता हैonFragmentIntereactior(Uri) , जिसका किसी अन्य उत्तर में उल्लेख नहीं किया गया है। +1

2
आपका बहुत बहुत धन्यवाद!
46िर_घई १३'१५ को ir:

इस उल्लेख के लिए धन्यवाद। मेरी बहुत मदद की।
हबलमा

2
आवश्यक है? आप श्रोताओं से संबंधित कोड को मिटा सकते हैं ... यदि आपके पास ऐसे टुकड़े हैं जो अन्य टुकड़ों के साथ बातचीत करने की आवश्यकता नहीं है, तो वे श्रोता बेकार हैं।
ट्रेस

4
स्वीकृत उत्तर की तुलना में अनुसरण करना और समझना बहुत आसान है।
जेरेथेबम

44

Fragmentएंड्रॉइड स्टूडियो द्वारा बनाए गए अपने ऑटो-जेनरेट देखें । जब आपने नया बनाया था Fragment, तो स्टूडियो ने आपके लिए कोड का एक गुच्छा जमा किया था। ऑटो-जेनरेट किए गए टेम्प्लेट के निचले भाग में एक आंतरिक इंटरफ़ेस परिभाषा है OnFragmentInteractionListener। आपका Activityइस इंटरफ़ेस को लागू करने की जरूरत है। यह आपके Fragmentलिए सूचित करने के लिए अनुशंसित पैटर्न हैActivity ईवेंट इसलिए यह उचित कार्रवाई कर सकता है, जैसे कि दूसरे को लोड करना Fragment। विवरण के लिए यह पृष्ठ देखें, "गतिविधि के लिए ईवेंट कॉलबैक बनाना" अनुभाग देखें: http://developer.android.com/guide/compenders/fragments.html


प्रलेखन में दिखाया गया है कि श्रोता को टुकड़े में कैसे लागू किया जाए (जो पहले से ही विज़ार्ड द्वारा उत्पन्न होता है), लेकिन मुख्यता में नहीं जो ऐप को क्रैश करने का कारण बनता है।
मारियो एम

3
बिल्कुल नहीं। डॉक्टर (और उत्पन्न कोड) इंटरफ़ेस को परिभाषित करता है और जब इसके Activityसाथ जुड़ा होता है तो इसके खिलाफ जांच करता है Fragment। क्रैश जो आप देख रहे हैं, क्योंकि आपके Activityइंटरफ़ेस को लागू नहीं किया गया है। आपको अपने में जाने Activityऔर implements YourFragment.OnFragmentInteractionListenerफिर इंटरफ़ेस में परिभाषित विधि के कार्यान्वयन को जोड़ने की आवश्यकता है।
लैरी शिएफ़र

ठीक है, लेकिन मुझे नहीं पता कि उस कार्यान्वयन को कैसे जोड़ा जाए क्योंकि यह एंड्रॉइड sdk प्रलेखन में कहीं नहीं है
मारियो एम

1
यह एसडीके का हिस्सा नहीं है, लेकिन एक सर्वोत्तम अभ्यास है। विज़ार्ड द्वारा निर्मित टेम्प्लेट कोड सिर्फ आपके लिए आधार का काम कर रहा है। इंटरफ़ेस onFragmentInteraction(Uri uri)केवल एक ठूंठ है। आप इस विधि को अपनी इच्छानुसार कुछ भी बना सकते हैं और Activityइसे लागू करने की आवश्यकता है। देखें कि क्या यह मदद करता है।
लैरी शिएफर

3
इस संकेत ने कई घंटे बचाए। टुकड़ा बनाने के दौरान संयुक्त राष्ट्र की जाँच "टुकड़ा कारखाने के तरीकों को शामिल करें" और "इंटरफ़ेस कॉलबैक शामिल करें"। और आपको OnFragmentInteractionListener को लागू करने की आवश्यकता नहीं है। मैं जावा एसडीके 8. एंड्रॉइड 6.0 (एपीआई 23) के साथ एंड्रॉइड स्टूडियो 1.3.2 का उपयोग कर रहा हूं और एसडीके-प्लेटफॉर्म 23 है। धन्यवाद लैरी शिएफर।
शिक्षार्थी

28

आपमें से जो इस त्रुटि पर आगे स्पष्टीकरण के लिए इस पृष्ठ पर जाते हैं, मेरे मामले में इस मामले में इस तरह के 2 कार्यान्वयन करने के लिए आवश्यक टुकड़े को कॉल करने वाली गतिविधि, इस तरह:

public class MyActivity extends Activity implements 
    MyFragment.OnFragmentInteractionListener, 
    NavigationDrawerFragment.NaviationDrawerCallbacks {
    ...// rest of the code
}

9

आपको अपने टुकड़ों से निम्न कोड निकालने का प्रयास करना चाहिए

    try {
        mListener = (OnFragmentInteractionListener) activity;
    } catch (ClassCastException e) {
        throw new ClassCastException(activity.toString()
                + " must implement OnFragmentInteractionListener");
    }

इंटरफ़ेस / श्रोता एक डिफ़ॉल्ट बनाया गया है ताकि आपकी गतिविधि और टुकड़े आसानी से संवाद कर सकें


2
यह एक बहुत अच्छा बिंदु है क्योंकि इस श्रोता को अधिकांश शुरुआती ऐप्स में ज़रूरत नहीं है।
कोड-अपरेंटिस

5

@ User26409021 के उत्तर के अलावा, यदि आपने एक ItemFragment जोड़ा है, तो ItemFragment में संदेश है;

Activities containing this fragment MUST implement the {@link OnListFragmentInteractionListener} interface.

और आपको अपनी गतिविधि में जोड़ना चाहिए;

public class MainActivity extends AppCompatActivity
    implements NavigationView.OnNavigationItemSelectedListener, ItemFragment.OnListFragmentInteractionListener {

//the code is omitted

 public void onListFragmentInteraction(DummyContent.DummyItem uri){
    //you can leave it empty
}

यहां डमी आइटम वह है जो आपके आइटमफ्रेगमेंट के तल पर है


5

मेरे साथ इसने इस कोड को हटाने का काम किया:

@Override
    public void onAttach(Context context) {
        super.onAttach(context);
        if (context instanceof OnFragmentInteractionListener) {
            mListener = (OnFragmentInteractionListener) context;
        } else {
            throw new RuntimeException(context.toString()
                    + " must implement OnFragmentInteractionListener");
        }
    }

इस तरह समाप्त:

@Override
public void onAttach(Context context) {
    super.onAttach(context);
}

4

OnFragmentInteractionListenerगतिविधि संचार के लिए टुकड़ा से निपटने के लिए डिफ़ॉल्ट कार्यान्वयन है। यह आपकी आवश्यकताओं के आधार पर लागू किया जा सकता है। मान लीजिए कि अगर आपको अपनी गतिविधि के दौरान किसी विशेष कार्रवाई के दौरान आपके टुकड़े करने की क्रिया की आवश्यकता है, तो आप इस कॉलबैक विधि का उपयोग कर सकते हैं। यदि आपको अपनी होस्टिंग के बीच यह इंटरैक्शन करने की आवश्यकता नहीं है activityऔर fragment, आप इस कार्यान्वयन को हटा सकते हैं।

संक्षेप implementमें अगर आप इस तरह के टुकड़ा गतिविधि गतिविधि की जरूरत है, तो आप अपने टुकड़ा होस्टिंग गतिविधि में श्रोता चाहिए

public class MainActivity extends Activity implements 
YourFragment.OnFragmentInteractionListener {..}

और आपके टुकड़े को इसे इस तरह परिभाषित करना चाहिए था

public interface OnFragmentInteractionListener {
    // TODO: Update argument type and name
    void onFragmentInteraction(Uri uri);
}

के लिए परिभाषा भी प्रदान करते हैं void onFragmentInteraction(Uri uri);अपनी गतिविधि के करें

अगर आप किसी भी टुकड़ा-गतिविधि बातचीत नहीं है, तो बस listenerअपने टुकड़े से प्रारंभिकता को हटा देंonAttach


3

गतिविधि उपयोग संदर्भ के बजाय। यह मेरे लिए काम करता है।

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

3

बस एक परिशिष्ट:

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

लक्ष्य यह है कि आप अपने टुकड़े को कई गतिविधियों में संलग्न कर सकते हैं और फिर भी समान संचार दृष्टिकोण का पुन: उपयोग कर सकते हैं (प्रत्येक गतिविधि के पास प्रत्येक टुकड़े के लिए अपनी OnFragmentInteractionListener हो सकती है)।

लेकिन और अगर मुझे यकीन है कि मेरा टुकड़ा केवल एक प्रकार की गतिविधि से जुड़ा होगा और मैं उस गतिविधि के साथ संवाद करना चाहता हूं?

फिर, यदि आप इसकी क्रियाशीलता के कारण OnFragmentInteractionListener का उपयोग नहीं करना चाहते हैं, तो आप अपनी गतिविधि का उपयोग कर सकते हैं:

((MyActivityClass) getActivity()).someMethod()

हालाँकि, यह ज्यादातर मामलों में काम करेगा, कभी-कभी getActivity () अशक्त हो सकती है अगर टुकड़े गतिविधि से अलग हो गए हैं, जबकि यह कहा जा रहा है, उदाहरण के लिए एक asynctask के postExecute विधि में, यदि आप गतिविधि प्राप्त करते हैं, लेकिन पहले से ही टुकड़ा छोड़ दिया है इससे पहले कि asyncTask पूरा हो गया है तो आपको एक शून्य सूचक अपवाद मिलेगा। इस कारण से एंड्रॉइड डॉक्यूमेंट्स विशेष रूप से एक विखंडन इंटरैक्शन श्रोता इंटरफ़ेस का उपयोग करने के लिए कहते हैं
MichaelStoddart

2

बस अपनी विखंडन गतिविधि पर जाएं और सभी विधि को हटा दें ..... इसके बजाय क्रिएटव्यू विधि पर।

आपके टुकड़े में केवल ऑनक्रीट का तरीका है।

// केवल यह विधि अन्य विधि को लागू करने को हटाती है

 @Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
        Bundle savedInstanceState) {
    View rootView = inflater.inflate(R.layout.fragment_main, container, false);
    return rootView;
}

और सुनिश्चित करें कि आपका लेआउट यू के लिए डेमो है।


धन्यवाद ... अगर कुछ चाहिए kalpeshnikam1080@gmail.com ड्रॉप मेल
कल्पेश ए। निकम

1

जब खंड गतिविधि से अलग हो जाता है या नष्ट हो जाता है तो मैं श्रोता के विनाश को जोड़ना चाहता हूं।

@Override
public void onDetach() {
    super.onDetach();
    mListener = null;
}

और जब नया प्रयोग करें () संदर्भ के साथ विधि

@Override
public void onDestroy() {
    super.onDestroy();
    mListener = null;
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.