अभिविन्यास परिवर्तनों पर Android Fragment जीवनचक्र


120

फ्रेगमेंट का उपयोग करके 2.2 को लक्षित करने के लिए संगतता पैकेज का उपयोग करना।

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

अभिविन्यास परिवर्तन से लॉग अजीब हैं, ऑनक्रीट व्यू में कई कॉल के साथ।

मैं स्पष्ट रूप से कुछ याद कर रहा हूं - जैसे कि टुकड़ा को अलग करना और एक नया उदाहरण बनाने के बजाय इसे फिर से जोड़ना, लेकिन मैं किसी भी दस्तावेज को नहीं देख सकता हूं जो इंगित करेगा कि मैं गलत कहां जा रहा हूं।

किसी को भी क्या मैं यहाँ गलत कर रहा हूँ पर कुछ प्रकाश डाला कर सकते हैं धन्यवाद

अभिविन्यास परिवर्तन के बाद लॉग निम्नानुसार है।

Initial creation
12-04 11:57:15.808: D/FragmentTest.FragmentTestActivity(3143): onCreate
12-04 11:57:15.945: D/FragmentTest.FragmentOne(3143): OnCreateView
12-04 11:57:16.081: D/FragmentTest.FragmentOne(3143): OnCreateView->SavedInstanceState null


Orientation Change 1
12-04 11:57:39.031: D/FragmentTest.FragmentOne(3143): onSaveInstanceState
12-04 11:57:39.031: D/FragmentTest.FragmentTestActivity(3143): onCreate
12-04 11:57:39.031: D/FragmentTest.FragmentOne(3143): OnCreateView
12-04 11:57:39.031: D/FragmentTest.FragmentOne(3143): OnCreateView->SavedInstanceState not null
12-04 11:57:39.031: D/FragmentTest.FragmentOne(3143): OnCreateView
12-04 11:57:39.167: D/FragmentTest.FragmentOne(3143): OnCreateView->SavedInstanceState null


Orientation Change 2
12-04 11:58:32.162: D/FragmentTest.FragmentOne(3143): onSaveInstanceState
12-04 11:58:32.162: D/FragmentTest.FragmentOne(3143): onSaveInstanceState
12-04 11:58:32.361: D/FragmentTest.FragmentTestActivity(3143): onCreate
12-04 11:58:32.361: D/FragmentTest.FragmentOne(3143): OnCreateView
12-04 11:58:32.361: D/FragmentTest.FragmentOne(3143): OnCreateView->SavedInstanceState not null
12-04 11:58:32.361: D/FragmentTest.FragmentOne(3143): OnCreateView
12-04 11:58:32.361: D/FragmentTest.FragmentOne(3143): OnCreateView->SavedInstanceState not null
12-04 11:58:32.498: D/FragmentTest.FragmentOne(3143): OnCreateView
12-04 11:58:32.498: D/FragmentTest.FragmentOne(3143): OnCreateView->SavedInstanceState null

मुख्य गतिविधि (FragmentActivity)

public class FragmentTestActivity extends FragmentActivity {
/** Called when the activity is first created. */

private static final String TAG = "FragmentTest.FragmentTestActivity";


FragmentManager mFragmentManager;

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    Log.d(TAG, "onCreate");

    mFragmentManager = getSupportFragmentManager();
    FragmentTransaction fragmentTransaction = mFragmentManager.beginTransaction();

    FragmentOne fragment = new FragmentOne();

    fragmentTransaction.add(R.id.fragment_container, fragment);
    fragmentTransaction.commit();
}

और टुकड़ा

public class FragmentOne extends Fragment {

private static final String TAG = "FragmentTest.FragmentOne";

EditText mEditText;

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
        Bundle savedInstanceState) {

    Log.d(TAG, "OnCreateView");

    View v = inflater.inflate(R.layout.fragmentonelayout, container, false);

    // Retrieve the text editor, and restore the last saved state if needed.
    mEditText = (EditText)v.findViewById(R.id.editText1);

    if (savedInstanceState != null) {

        Log.d(TAG, "OnCreateView->SavedInstanceState not null");

        mEditText.setText(savedInstanceState.getCharSequence("text"));
    }
    else {
        Log.d(TAG,"OnCreateView->SavedInstanceState null");
    }
    return v;
}

@Override
public void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);

    Log.d(TAG, "FragmentOne.onSaveInstanceState");

    // Remember the current text, to restore if we later restart.
    outState.putCharSequence("text", mEditText.getText());
}

प्रकट

<uses-sdk android:minSdkVersion="8" />

<application
    android:icon="@drawable/ic_launcher"
    android:label="@string/app_name" >
    <activity
        android:label="@string/app_name"
        android:name=".activities.FragmentTestActivity" 
        android:configChanges="orientation">
        <intent-filter >
            <action android:name="android.intent.action.MAIN" />

            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>
</application>

मुझे नहीं पता कि यह एक उचित उत्तर है, लेकिन टुकड़े को जोड़ने पर एक टैग का उपयोग करने का प्रयास करें, जोड़ें (R.id.fragment_container, टुकड़ा, "MYTAG"), या असफल होने पर, बदलें (R.id.fragment_container, टुकड़ा, "MYTAG" ")
जेसन

2
कुछ जांच कर रहे हैं। जब मुख्य गतिविधि (FragmentTestActivity) अभिविन्यास परिवर्तन पर फिर से शुरू होती है और मैं तब FragmentManager का एक नया उदाहरण प्राप्त करता हूं, तब अभी भी मौजूद टुकड़े का पता लगाने के लिए FindFragmentByTag का प्रदर्शन करता हूं, इसलिए यह टुकड़ा मुख्य गतिविधि के मनोरंजन पर बनाए रखा जाता है। अगर मुझे टुकड़ा मिलता है और कुछ भी नहीं करता है तो इसे वैसे भी MainActivity के साथ फिर से परिभाषित किया जाता है।
मार्टिन डेस

जवाबों:


189

आप एक के ऊपर एक अपने फ्रेगरेंस बिछा रहे हैं।

जब एक कॉन्फ़िगरेशन परिवर्तन होता है तो पुराना फ़्रैगमेंट स्वयं को नई गतिविधि में जोड़ता है जब इसे पुनः बनाया जाता है। यह ज्यादातर समय पीछे के हिस्से में भारी दर्द होता है।

आप एक नए को पुनः बनाने के बजाय उसी फ़्रैगमेंट का उपयोग करके होने वाली त्रुटियों को रोक सकते हैं। बस इस कोड को जोड़ें:

if (savedInstanceState == null) {
    // only create fragment if activity is started for the first time
    mFragmentManager = getSupportFragmentManager();
    FragmentTransaction fragmentTransaction = mFragmentManager.beginTransaction();

    FragmentOne fragment = new FragmentOne();

    fragmentTransaction.add(R.id.fragment_container, fragment);
    fragmentTransaction.commit();
} else {        
    // do nothing - fragment is recreated automatically
}

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


54
"यह पिछले समय में सबसे बड़ा दर्द है" (अंगूठे ऊपर)
भीड़

1
FragmentStatePagerAdapter ... किसी भी सुझाव के साथ ViewPage उपयोग के मामले में एक ही परिदृश्य को कैसे संभाला जा सकता है?
CoDe

5
क्या आधिकारिक दस्तावेज में समान दावा है? क्या यह एक विरोधाभासी नहीं है कि गाइड में क्या कहा गया है "when the activity is destroyed, so are all fragments":? के बाद से "When the screen orientation changes, the system destroys and recreates the activity [...]"
शुक्र

4
साइरस - नहींं, गतिविधि वास्तव में नष्ट हो गई है, इसमें जो फ्रेगमेंट शामिल हैं, वह फ्रैगमेंट मैनजर में संदर्भित है, केवल गतिविधि से नहीं, इसलिए यह बना रहता है और इसे पढ़ा जाता है।
ग्रीम

4
FragmentManager में ढूंढने के बाद अंशों को onCreate और onDestroy विधियों के साथ-साथ इसके हैशकोड पर लॉग करना स्पष्ट रूप से दिखाता है कि टुकड़ा IS नष्ट हो गया है। यह बस फिर से बनाया और स्वचालित रूप से reattached है। केवल तभी जब आप सेटटैनइन्स्टैन्स (सत्य) को टुकड़ों में डालते हैं, तो इसे सही तरीके से नष्ट न करें
Lemao1981

87

इस पुस्तक का हवाला देते हुए , "एक सुसंगत उपयोगकर्ता अनुभव सुनिश्चित करने के लिए, एंड्रॉइड फ्रैगमेंट लेआउट और संबंधित बैक स्टैक को बनाए रखता है जब किसी कॉन्फ़िगरेशन परिवर्तन के कारण गतिविधि फिर से शुरू होती है।" (पृष्ठ १२४)

और उस तरीके से संपर्क करने का तरीका जो पहले जांचना है कि क्या फ्रैगमेंट बैक स्टैक पहले से ही आबाद हो गया है, और नया टुकड़ा उदाहरण केवल तभी बनाएं जब यह नहीं हो:

@Override
public void onCreate(Bundle savedInstanceState) {

        ...    

    FragmentOne fragment = (FragmentOne) mFragmentManager.findFragmentById(R.id.fragment_container); 

    if (fragment == null) {
        FragmentTransaction fragmentTransaction = mFragmentManager.beginTransaction();
        fragmentTransaction.add(R.id.fragment_container, new FragmentOne());
        fragmentTransaction.commit();
    }
}

2
आपने शायद इस एक के साथ मुझे बहुत समय दिया ... बहुत बहुत धन्यवाद। आप इस परिवर्तन को ग्रीम से एक के साथ जोड़ सकते हैं ताकि विन्यास परिवर्तन और टुकड़े को संभालने के लिए एक सही समाधान मिल सके।
azpublic

10
यह वास्तव में सही उत्तर है, चिह्नित नहीं है। आपका बहुत बहुत धन्यवाद!
उरियल फ्रैंकेल

ViewPager Fragment के कार्यान्वयन के मामले में एक ही स्थान को कैसे संभाला जा सकता है।
कोडे डे

यह छोटा रत्न एक समस्या पर मदद करता है जिसे मैं कई दिनों से देख रहा था। धन्यवाद! यह निश्चित रूप से समाधान है।
जिसका समय

1
@SharpEdge यदि आपके पास कई टुकड़े हैं, तो आपको कंटेनर में जोड़ते समय उन्हें टैग देना चाहिए, और उसके बाद संदर्भ प्राप्त करने के लिए mFragmentManager.findFragmentByTag (findFragmentById के बजाय) का उपयोग करें - इस तरह आप प्रत्येक टुकड़े के वर्ग को जान पाएंगे और सक्षम हो सकेंगे सही ढंग से
k29

10

आपकी गतिविधि की ऑनक्रिएट () विधि को उन्मुखीकरण परिवर्तन के बाद कहा जाता है जैसा आपने देखा है। इसलिए, अपनी गतिविधि में अभिविन्यास परिवर्तन के बाद Fragment को जोड़ने वाले FragmentTransaction को निष्पादित न करें।

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    if (savedInstanceState==null) {
        //do your stuff
    }
}

अंशों को अपरिवर्तित होना चाहिए।


क्या हमें पता है कि टुकड़ा बनने और जुड़ने के बाद उदाहरण सहेजा जाएगा? मेरा मतलब है कि अगर फ्रैगमेंट जोड़े जाने से ठीक पहले कोई यूजर घूमता है तो? हम अभी भी गैर-शून्य सहेजे हुए हैं। InstanceState जिसमें टुकड़ा अवस्था नहीं है
फ़रीद

4

आप @OverrideFragmentActivity का उपयोग कर सकते हैं onSaveInstanceState()। कृपया super.onSaveInstanceState()विधि में कॉल नहीं करने के लिए सुनिश्चित करें ।


2
यह पहले से ही काफी गड़बड़ प्रक्रिया में अधिक संभावित समस्याओं को प्रस्तुत करने वाली जीवनचक्र गतिविधियों को तोड़ देगा। FragmentActivity के स्रोत कोड को देखें: यह वहां के सभी टुकड़ों की स्थिति को बचा रहा है।
ब्रायन

मेरे पास समस्या थी कि मेरे पास अलग-अलग अभिविन्यास के लिए अलग-अलग एडेप्टर गिनती है। इसलिए मेरे पास डिवाइस को चालू करने और कुछ पृष्ठों को स्वाइप करने के बाद हमेशा एक अजीब स्थिति थी, मुझे पुरानी और गलत एक मिल गई। SaveInstance की ओर मुड़ने के साथ यह मेमोरी लीक्स के बिना सबसे अच्छा काम करता है (मैंने setSavedEnabled (गलत) का उपयोग किया है और हर ओरिएंटेशन चेंज पर बड़ी मेमोरी लीक के साथ समाप्त हो गया है)
Informatic0re

0

हमें हमेशा nullpointer अपवाद को रोकने का प्रयास करना चाहिए, इसलिए हमें बंडल जानकारी के लिए सबसे पहले saveinstance विधि में जांच करनी होगी। संक्षिप्त विवरण के लिए इस ब्लॉग लिंक की जाँच करें

public static class DetailsActivity extends Activity {

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

        if (getResources().getConfiguration().orientation
            == Configuration.ORIENTATION_LANDSCAPE) {
            // If the screen is now in landscape mode, we can show the
            // dialog in-line with the list so we don't need this activity.
            finish();
            return;
        }

        if (savedInstanceState == null) {
            // During initial setup, plug in the details fragment.
            DetailsFragment details = new DetailsFragment();
            details.setArguments(getIntent().getExtras());
            getFragmentManager().beginTransaction().add(android.R.id.content, details).commit();
        }
    } 
}

0

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

FragmentOne fragment = new FragmentOne();

fragmentTransaction.add(R.id.fragment_container, fragment);

यह करो:

if (mFragmentManager.findFragmentByTag(FRAG1_TAG) == null) {
    FragmentOne fragment = new FragmentOne();

    fragmentTransaction.add(R.id.fragment_container, fragment, FRAG1_TAG);
}

कृपया ध्यान दें कि जब तक आप setRetainInstance (सही) नहीं कहते हैं, तब तक फ्रेमवर्क अभिविन्यास परिवर्तन पर FragmentOne का एक नया उदाहरण जोड़ता है, इस स्थिति में यह FragmentOne के पुराने उदाहरण को जोड़ देगा।


-1

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

आप स्वचालित रूप से स्क्रीन स्थिति का निर्धारण करेंगे, संबंधित लेआउट को लोड करेंगे), गतिविधि या टुकड़े को फिर से शुरू करने की आवश्यकता के कारण, उपयोगकर्ता का अनुभव अच्छा नहीं है, सीधे स्क्रीन स्विच पर नहीं, मैं संदर्भित करता हूं? यूआरएल = YgNfP-vHy-Nuldi7YHTfNet3AtLdN-w__O3z1wLOnzr3wDjYo7X7PYdNyhw8R24ZE22xiKnydni7R0r35s2fOLcHOiLGYT9Qh_fjqtytJki और wd = & eqid = f258719e0001f24000000004585a1082

आधार यह है कि लेआउट का लेआउट जिस तरह से आपके वजन का उपयोग कर रहा है, वह निम्नानुसार है:

<LinearLayout
Android:id= "@+id/toplayout"
Android:layout_width= "match_parent"
Android:layout_height= "match_parent"
Android:layout_weight= "2"
Android:orientation= "horizontal" >

इसलिए मेरा दृष्टिकोण है, जब स्क्रीन स्विचिंग, व्यू फाइल के एक नए लेआउट को लोड करने की आवश्यकता नहीं है, लेआउट को onConfigurationChanged डायनेमिक वेट्स में संशोधित करें, निम्न चरण: 1 पहला सेट: गतिविधि विशेषता में AndroidManifest.xml: android: configChanges = "कीबोर्डहेड्ड। अभिविन्यास | स्क्रीनसेज़" स्क्रीन स्विचिंग को रोकने के लिए, पुनः लोडिंग से बचें, ताकि ऑनकोनफिगरेशन पर नज़र रखने में सक्षम हो सकें। 2 पुन: लिखने की गतिविधि या ऑनकोनफिगरेशनचैन विधि में टुकड़ा।

@Override
Public void onConfigurationChanged (Configuration newConfig) {
    Super.onConfigurationChanged (newConfig);
    SetContentView (R.layout.activity_main);
    if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
        //On the layout / / weight adjustment
        LinearLayout toplayout = (LinearLayout) findViewById (R.id.toplayout);
        LinearLayout.LayoutParams LP = new LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, 0, 2.0f);
        Toplayout.setLayoutParams (LP);
        LinearLayout tradespace_layout = (LinearLayout) findViewById(R.id.tradespace_layout);
        LinearLayout.LayoutParams LP3 = new LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, 0, 2.8f);
        Tradespace_layout.setLayoutParams (LP3);
    }
    else if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT)
    {
        //On the layout / / weight adjustment
        LinearLayout toplayout = (LinearLayout) findViewById (R.id.toplayout);
        LinearLayout.LayoutParams LP = new LayoutParams (LinearLayout.LayoutParams.MATCH_PARENT, 0, 2.8f);
        Toplayout.setLayoutParams (LP);
        LinearLayout tradespace_layout = (LinearLayout) findViewById (R.id.tradespace_layout);
        LinearLayout.LayoutParams LP3 = new LayoutParams (LinearLayout.LayoutParams.MATCH_PARENT, 0, 2.0f);
        Tradespace_layout.setLayoutParams (LP3);
    }
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.