android - फ्रैगमेंट माईफ्रेगमेंट गतिविधि से जुड़ा नहीं है




android-fragments actionbarsherlock (8)

आपके कोड के साथ समस्या यह है कि आप AsyncTask का उपयोग कर रहे हैं, क्योंकि जब आप अपनी नींद धागे के दौरान स्क्रीन घुमाते हैं:

Thread.sleep(2000) 

AsyncTask अभी भी काम कर रहा है, ऐसा इसलिए है क्योंकि आपने टुकड़े पुनर्निर्माण (जब आप घूमते हैं) से पहले AsstcTask उदाहरण को ठीक से Destroy () में रद्द नहीं किया था और जब यह वही AsyncTask उदाहरण (घुमाने के बाद) पर चलता है PostExecute (), यह खोजने की कोशिश करता है पुराने खंड उदाहरण (एक अमान्य उदाहरण) के साथ getResources () के साथ संसाधन:

getResources().getString(R.string.app_name)

जो बराबर है:

MyFragment.this.getResources().getString(R.string.app_name)

तो जब आप स्क्रीन को घुमाते हैं तो टुकड़ा पुनर्निर्माण से पहले अंतिम समाधान AsyncTask इंस्टेंस (अगर यह अभी भी काम कर रहा है) को प्रबंधित करने के लिए है, और यदि संक्रमण के दौरान रद्द किया गया है, तो बूलियन ध्वज की सहायता से पुनर्निर्माण के बाद AsyncTask को पुनरारंभ करें:

public class MyFragment extends SherlockFragment {

    private MyAsyncTask myAsyncTask = null;
    private boolean myAsyncTaskIsRunning = true;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if(savedInstanceState!=null) {
            myAsyncTaskIsRunning = savedInstanceState.getBoolean("myAsyncTaskIsRunning");
        }
        if(myAsyncTaskIsRunning) {
            myAsyncTask = new MyAsyncTask();
            myAsyncTask.execute();
        }
    }

    @Override
    public void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        outState.putBoolean("myAsyncTaskIsRunning",myAsyncTaskIsRunning);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        if(myAsyncTask!=null) myAsyncTask.cancel(true);
        myAsyncTask = null;

    }

    public class MyAsyncTask extends AsyncTask<Void, Void, Void>() {

        public MyAsyncTask(){}

        @Override
        protected void onPreExecute() {
            super.onPreExecute();
            myAsyncTaskIsRunning = true;
        }
        @Override
        protected Void doInBackground(Void... params) {
            try {
                Thread.sleep(2000);
            } catch (InterruptedException ex) {}
            return null;
        }

        @Override
        protected void onPostExecute(Void result){
            getResources().getString(R.string.app_name);
            myAsyncTaskIsRunning = false;
            myAsyncTask = null;
        }

    }
}

मैंने एक छोटा परीक्षण ऐप बनाया है जो मेरी समस्या का प्रतिनिधित्व करता है। मैं (शेरलॉक) टुकड़ों के साथ टैब को लागू करने के लिए ActionBarSherlock का उपयोग कर रहा हूं।

मेरा कोड: TestActivity.java

public class TestActivity extends SherlockFragmentActivity {
    private ActionBar actionBar;

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

    private void setupTabs(Bundle savedInstanceState) {
        actionBar = getSupportActionBar();
        actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);

        addTab1();
        addTab2();
    }

    private void addTab1() {
        Tab tab1 = actionBar.newTab();
        tab1.setTag("1");
        String tabText = "1";
        tab1.setText(tabText);
        tab1.setTabListener(new TabListener<MyFragment>(TestActivity.this, "1", MyFragment.class));

        actionBar.addTab(tab1);
    }

    private void addTab2() {
        Tab tab1 = actionBar.newTab();
        tab1.setTag("2");
        String tabText = "2";
        tab1.setText(tabText);
        tab1.setTabListener(new TabListener<MyFragment>(TestActivity.this, "2", MyFragment.class));

        actionBar.addTab(tab1);
    }
}

TabListener.java

public class TabListener<T extends SherlockFragment> implements com.actionbarsherlock.app.ActionBar.TabListener {
    private final SherlockFragmentActivity mActivity;
    private final String mTag;
    private final Class<T> mClass;

    public TabListener(SherlockFragmentActivity activity, String tag, Class<T> clz) {
        mActivity = activity;
        mTag = tag;
        mClass = clz;
    }

    /* The following are each of the ActionBar.TabListener callbacks */

    public void onTabSelected(Tab tab, FragmentTransaction ft) {
        SherlockFragment preInitializedFragment = (SherlockFragment) mActivity.getSupportFragmentManager().findFragmentByTag(mTag);

        // Check if the fragment is already initialized
        if (preInitializedFragment == null) {
            // If not, instantiate and add it to the activity
            SherlockFragment mFragment = (SherlockFragment) SherlockFragment.instantiate(mActivity, mClass.getName());
            ft.add(android.R.id.content, mFragment, mTag);
        } else {
            ft.attach(preInitializedFragment);
        }
    }

    public void onTabUnselected(Tab tab, FragmentTransaction ft) {
        SherlockFragment preInitializedFragment = (SherlockFragment) mActivity.getSupportFragmentManager().findFragmentByTag(mTag);

        if (preInitializedFragment != null) {
            // Detach the fragment, because another one is being attached
            ft.detach(preInitializedFragment);
        }
    }

    public void onTabReselected(Tab tab, FragmentTransaction ft) {
        // User selected the already selected tab. Usually do nothing.
    }
}

MyFragment.java

public class MyFragment extends SherlockFragment {

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

        new AsyncTask<Void, Void, Void>() {

            @Override
            protected Void doInBackground(Void... params) {
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException ex) {
                }
                return null;
            }

            @Override
            protected void onPostExecute(Void result){
                getResources().getString(R.string.app_name);
            }

        }.execute();
    }
}

मैंने डाउनलोड डेटा अनुकरण करने के लिए Thread.sleep भाग जोड़ा है। onPostExecute में कोड Fragment उपयोग को अनुकरण करना है।

जब मैं लैंडस्केप और पोर्ट्रेट के बीच स्क्रीन को बहुत तेज़ onPostExecute हूं, तो मुझे onPostExecute कोड पर अपवाद मिलता है:

java.lang.IleglegalStateException: फ्रैगमेंट माईफ्रेगमेंट {410f6060} गतिविधि से जुड़ा नहीं है

मुझे लगता है कि ऐसा इसलिए है क्योंकि इस दौरान एक नया MyFragment बनाया गया था, और AsyncTask समाप्त होने से पहले गतिविधि से जुड़ा हुआ था। onPostExecute पर कोड एक unattached MyFragment पर कॉल करता है।

लेकिन मैं इसे कैसे ठीक कर सकता हूं?


एक पुरानी पोस्ट, लेकिन मैं सबसे ज्यादा वोट देने वाले उत्तर के बारे में हैरान था।

इसके लिए उचित समाधान ontop (या जहां भी आपके टुकड़े में उपयुक्त हो) में asynctask को रद्द करना चाहिए। इस तरह आप एक मेमोरी रिसाव (एक एसिंक्टास्क को अपने नष्ट टुकड़े के संदर्भ में रखते हुए) पेश नहीं करते हैं और आपके पास अपने टुकड़े में क्या हो रहा है इसका बेहतर नियंत्रण है।

@Override
public void onStop() {
    super.onStop();
    mYourAsyncTask.cancel(true);
}

मुझे बहुत सरल जवाब मिला है: isAdded() :

अगर खंड वर्तमान में अपनी गतिविधि में जोड़ा गया है तो true लौटें।

@Override
protected void onPostExecute(Void result){
    if(isAdded()){
        getResources().getString(R.string.app_name);
    }
}

जब Fragment Activity से जुड़ा हुआ नहीं है, तो onPostExecute से बचने के लिए Fragment को रोक या रोकते समय AsyncTask को रद्द करना है। फिर isAdded() अब और आवश्यक नहीं होगा। हालांकि, इस चेक को जगह में रखने की सलाह दी जाती है।


मुझे यहां दो अलग-अलग परिदृश्यों का सामना करना पड़ा है:

1) जब मैं एसिंक्रोनस कार्य को वैसे भी खत्म करना चाहता हूं: कल्पना करें कि मेरा onPostExecute डेटा संग्रहीत करता है और उसके बाद दृश्यों को अपडेट करने के लिए श्रोता को कॉल करता है, इसलिए अधिक कुशल होने के लिए, मैं कार्य को वैसे भी खत्म करना चाहता हूं, इसलिए उपयोगकर्ता के नाम के दौरान डेटा तैयार हो वापस। इस मामले में मैं आमतौर पर ऐसा करता हूं:

@Override
protected void onPostExecute(void result) {
    // do whatever you do to save data
    if (this.getView() != null) {
        // update views
    }
}

2) जब मैं अतुल्यकालिक कार्य को केवल तभी समाप्त करना चाहता हूं जब विचार अपडेट किए जा सकें: यदि आप यहां प्रस्तावित कर रहे हैं, तो कार्य केवल दृश्यों को अपडेट करता है, कोई डेटा संग्रहण आवश्यक नहीं है, इसलिए यदि विचार हैं तो कार्य समाप्त होने के लिए इसका कोई संकेत नहीं है अब दिखाया नहीं जा रहा है। मैं यह करता हूँ:

@Override
protected void onStop() {
    // notice here that I keep a reference to the task being executed as a class member:
    if (this.myTask != null && this.myTask.getStatus() == Status.RUNNING) this.myTask.cancel(true);
    super.onStop();
}

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

इच्छा है कि यह किसी की मदद करता है! :)


यदि आप Application वर्ग का विस्तार करते हैं और एक स्थिर 'वैश्विक' संदर्भ वस्तु को निम्नानुसार बनाए रखते हैं, तो आप स्ट्रिंग संसाधन को लोड करने के लिए गतिविधि के बजाय इसका उपयोग कर सकते हैं।

public class MyApplication extends Application {
    public static Context GLOBAL_APP_CONTEXT;

    @Override
    public void onCreate() {
        super.onCreate();
        GLOBAL_APP_CONTEXT = this;
    }
}

यदि आप इसका उपयोग करते हैं, तो आप जीवन के बारे में चिंता किए बिना Toast और संसाधन लोडिंग से दूर हो सकते हैं।


लोड किए गए वरीयताओं के साथ एप्लिकेशन सेटिंग्स गतिविधि दिखाई देने पर मुझे इसी तरह के मुद्दों का सामना करना पड़ा। अगर मैं वरीयताओं में से एक को बदल दूंगा और फिर डिस्प्ले सामग्री को घुमाने और वरीयता को फिर से बदल दूंगा, तो यह एक संदेश से दुर्घटनाग्रस्त हो जाएगा कि खंड (मेरी प्राथमिकता वर्ग) किसी गतिविधि से जुड़ा नहीं था।

जब इसे डिबगिंग किया जाता है तो ऑनरेट () प्राथमिकता के तरीके की तरह दिखता था, प्रदर्शन सामग्री घुमाए जाने पर दो बार बुलाया जा रहा था। वह पहले से ही अजीब था। फिर मैंने ब्लॉक के बाहर जोड़ा गया () चेक जोड़ा जहां यह दुर्घटना का संकेत देगा और इसने हल को हल किया।

यहां श्रोता का कोड दिया गया है जो नई प्रविष्टि दिखाने के लिए प्राथमिकता सारांश अपडेट करता है। यह मेरी प्राथमिकता वर्ग की ऑनक्रेट () विधि में स्थित है जो वरीयता फ्रेगमेंट क्लास को बढ़ाता है:

public static class Preferences extends PreferenceFragment {
    SharedPreferences.OnSharedPreferenceChangeListener listener;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        // ...
        listener = new SharedPreferences.OnSharedPreferenceChangeListener() {
            @Override
            public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
                // check if the fragment has been added to the activity yet (necessary to avoid crashes)
                if (isAdded()) {
                    // for the preferences of type "list" set the summary to be the entry of the selected item
                    if (key.equals(getString(R.string.pref_fileviewer_textsize))) {
                        ListPreference listPref = (ListPreference) findPreference(key);
                        listPref.setSummary("Display file content with a text size of " + listPref.getEntry());
                    } else if (key.equals(getString(R.string.pref_fileviewer_segmentsize))) {
                        ListPreference listPref = (ListPreference) findPreference(key);
                        listPref.setSummary("Show " + listPref.getEntry() + " bytes of a file at once");
                    }
                }
            }
        };
        // ...
    }

मुझे उम्मीद है कि यह दूसरों की मदद करेगा!


उनके लिए यह काफी चाल समाधान है और गतिविधि से टुकड़े की रिसाव है।

तो GetResource या किसी भी चीज के मामले में जो फ्रेगमेंट से प्राप्त गतिविधि संदर्भ के आधार पर है, यह हमेशा गतिविधि की स्थिति और टुकड़े की स्थिति की जांच करता है

 Activity activity = getActivity(); 
    if(activity != null && isAdded())

         getResources().getString(R.string.no_internet_error_msg);
//Or any other depends on activity context to be live like dailog


        }
    }

if (getActivity() == null) return;

कुछ मामलों में भी काम करता है। बस कोड निष्पादन को तोड़ देता है और सुनिश्चित करता है कि ऐप क्रैश न हो





actionbarsherlock