मैं प्रोग्रामेटिक रूप से निर्मित सामग्री दृश्य के साथ किसी गतिविधि में एक फ़्रैगमेंट कैसे जोड़ सकता हूं


240

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

public class DebugExampleTwo extends Activity {

    private ExampleTwoFragment mFragment;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        FrameLayout frame = new FrameLayout(this);
        if (savedInstanceState == null) {
            mFragment = new ExampleTwoFragment();
            FragmentTransaction ft = getFragmentManager().beginTransaction();
            ft.add(frame.getId(), mFragment).commit();
        }

        setContentView(frame);
    }
}

...

public class ExampleTwoFragment extends Fragment {

    @Override
    public View onCreateView(LayoutInflater inflater, 
                             ViewGroup container, 
                             Bundle savedInstanceState) {
        Button button = new Button(getActivity());
        button.setText("Hello There");
        return button;
    }
}

यह कोड संकलित करता है, लेकिन शुरू में क्रैश हो जाता है, शायद इसलिए कि मेरा FragmentTransaction.add()गलत है। ऐसा करने का सही तरीका क्या है?

जवाबों:


198

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

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

public class DebugExampleTwo extends Activity {

    private static final int CONTENT_VIEW_ID = 10101010;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        FrameLayout frame = new FrameLayout(this);
        frame.setId(CONTENT_VIEW_ID);
        setContentView(frame, new LayoutParams(
            LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));

        if (savedInstanceState == null) {
            Fragment newFragment = new DebugExampleTwoFragment();
            FragmentTransaction ft = getFragmentManager().beginTransaction();
            ft.add(CONTENT_VIEW_ID, newFragment).commit();
        }
    }

    public static class DebugExampleTwoFragment extends Fragment {
        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container,
                Bundle savedInstanceState) {
            EditText v = new EditText(getActivity());
            v.setText("Hello Fragment!");
            return v;
        }
    }
}

115
यदि आप केवल गतिविधि के शीर्ष स्तरीय सामग्री दृश्य के रूप में टुकड़े का उपयोग करना चाहते हैं, तो आप उपयोग कर सकते हैं ft.add(android.R.id.content, newFragment)। केवल एक कस्टम लेआउट बनाना और उसकी आईडी सेट करना आवश्यक है यदि टुकड़ा का कंटेनर गतिविधि की सामग्री दृश्य नहीं है।
टोनी वोंग

25
आईडी को हार्ड कोड करने के बजाय, आप इसे XML में परिभाषित कर सकते हैं और इसे सामान्य (R.id.myid) के रूप में संदर्भित कर सकते हैं
जेसन हैनली

1
मुझे नहीं पता कि ऐसा कैसे करना है, लेकिन याद रखें कि एक आईडी को केवल उस दायरे में अद्वितीय होना चाहिए जो आपको इसका उपयोग करने की आवश्यकता है।
जेसन हैनले

2
आईडी में केवल लेआउट के वर्तमान उत्तराधिकार के भीतर अपने स्तर पर अद्वितीय होना चाहिए। तो यह कहो कि एक रैखिक लेआउट में लिपटे, यह केवल उस रैखिक लेआउट के भीतर अन्य विचारों के बीच unqiue होने की जरूरत है।
शॉन

1
आप गतिशील रूप से setId (View.NO_ID) और उसके बाद getId () का उपयोग करके एक आईडी बना सकते हैं।
enl8enmentnow

71

टोनी वोंग की टिप्पणी को पढ़ने के बाद मैं यहां आया हूं :

public class DebugExampleTwo extends BaseActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        addFragment(android.R.id.content,
                    new DebugExampleTwoFragment(),
                    DebugExampleTwoFragment.FRAGMENT_TAG);
    }

}

...

public abstract class BaseActivity extends Activity {

    protected void addFragment(@IdRes int containerViewId,
                               @NonNull Fragment fragment,
                               @NonNull String fragmentTag) {
        getSupportFragmentManager()
                .beginTransaction()
                .add(containerViewId, fragment, fragmentTag)
                .disallowAddToBackStack()
                .commit();
    }

    protected void replaceFragment(@IdRes int containerViewId,
                                   @NonNull Fragment fragment,
                                   @NonNull String fragmentTag,
                                   @Nullable String backStackStateName) {
        getSupportFragmentManager()
                .beginTransaction()
                .replace(containerViewId, fragment, fragmentTag)
                .addToBackStack(backStackStateName)
                .commit();
    }

}

...

public class DebugExampleTwoFragment extends Fragment {

    public static final String FRAGMENT_TAG = 
        BuildConfig.APPLICATION_ID + ".DEBUG_EXAMPLE_TWO_FRAGMENT_TAG";

    // ...

}

Kotlin

यदि आप कोटलिन का उपयोग कर रहे हैं, तो सुनिश्चित करें कि Google द्वारा कोटलिन एक्सटेंशन क्या है या बस अपना स्वयं का विवरण दें।


ऐसा मत करो! if (savedInstanceState == null)टुकड़ा बनाने से पहले जांच लें, या स्क्रीन को घुमाने के बाद आपके पास दो टुकड़े या टुकड़े फिर से होने लगेंगे। addविधि का प्रयोग बिलकुल न करें ! केवल replace। या आपके साथ अजीब व्यवहार होगा।
कूलमाइंड

आपको "backStackStateName" का मान कहाँ मिलता है? (जब प्रतिस्थापित फ़ंक्शन का उपयोग कर रहे हैं)
vikzilla

@vikzilla आप यहाँ और डॉक्स में बहुत अच्छे उत्तर पा सकते हैं । संक्षेप में: backStackStateNameस्ट्रिंग कुछ ऐसा है जो आपके द्वारा परिभाषित किया गया है।
JJD

34
    public class Example1 extends FragmentActivity {

        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
          DemoFragment fragmentDemo = (DemoFragment) 
          getSupportFragmentManager().findFragmentById(R.id.frame_container);
          //above part is to determine which fragment is in your frame_container
          setFragment(fragmentDemo);
                       (OR)
          setFragment(new TestFragment1());
        }

        // This could be moved into an abstract BaseActivity 
        // class for being re-used by several instances
        protected void setFragment(Fragment fragment) {
            FragmentManager fragmentManager = getSupportFragmentManager();
            FragmentTransaction fragmentTransaction = 
                fragmentManager.beginTransaction();
            fragmentTransaction.replace(android.R.id.content, fragment);
            fragmentTransaction.commit();
        }
    }

एक गतिविधि या FramentActivity में एक टुकड़ा जोड़ने के लिए यह एक कंटेनर की आवश्यकता है। उस कंटेनर में एक " Framelayout" होना चाहिए , जिसे xml में शामिल किया जा सकता है या फिर आप android.R.id.contentगतिविधि में एक टुकड़े को हटाने या बदलने के लिए " जैसे" के लिए डिफ़ॉल्ट कंटेनर का उपयोग कर सकते हैं ।

main.xml

<RelativeLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent" >
 <!-- Framelayout to display Fragments -->
   <FrameLayout
        android:id="@+id/frame_container"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

    <ImageView
        android:id="@+id/imagenext"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_alignParentRight="true"
        android:layout_margin="16dp"
        android:src="@drawable/next" />
</RelativeLayout>

29

सभी उत्तरों को पढ़ने के बाद मैं सुरुचिपूर्ण तरीके से आया:

public class MyActivity extends ActionBarActivity {

 Fragment fragment ;

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

    FragmentManager fm = getSupportFragmentManager();
    fragment = fm.findFragmentByTag("myFragmentTag");
    if (fragment == null) {
        FragmentTransaction ft = fm.beginTransaction();
        fragment =new MyFragment();
        ft.add(android.R.id.content,fragment,"myFragmentTag");
        ft.commit();
    }

}

मूल रूप से आपको अपने टुकड़े के कंटेनर के रूप में एक फ्रेम -आउट जोड़ने की आवश्यकता नहीं है, इसके बजाय आप सीधे एंड्रॉइड रूट व्यू कंटेनर में टुकड़े को जोड़ सकते हैं

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


उत्तर के लिए धन्यवाद, यह पूरे स्क्रीन पर खंड टैब जोड़ता है? लेकिन आप एक फ़्रेम लेआउट में कैसे जोड़ते हैं या पेजर देखते हैं?
फ्लांकेन

6
public abstract class SingleFragmentActivity extends Activity {

    public static final String FRAGMENT_TAG = "single";
    private Fragment fragment;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
        if (savedInstanceState == null) {
            fragment = onCreateFragment();
           getFragmentManager().beginTransaction()
                   .add(android.R.id.content, fragment, FRAGMENT_TAG)
                   .commit();
       } else {
           fragment = getFragmentManager().findFragmentByTag(FRAGMENT_TAG);
       }
   }

   public abstract Fragment onCreateFragment();

   public Fragment getFragment() {
       return fragment;
   }

}

उपयोग

public class ViewCatalogItemActivity extends SingleFragmentActivity {
    @Override
    public Fragment onCreateFragment() {
        return new FragmentWorkShops();
    }

}

6

के लिए एपीआई स्तर 17 या अधिक, View.generateViewId()इस समस्या का समाधान होगा। उपयोगिता विधि एक अद्वितीय आईडी प्रदान करती है जिसका उपयोग बिल्ड समय में नहीं किया जाता है।


3
ढेर अतिप्रवाह में आपका स्वागत है! जब तक यह सैद्धांतिक रूप से प्रश्न का उत्तर दे सकता है, उत्तर के आवश्यक भागों को शामिल करना और संदर्भ के लिए लिंक प्रदान करना बेहतर होगा
SuperBiasedMan 15

3

कोटलिन में प्रोग्राम से संबंधित गतिविधि में अंश संलग्न करने के लिए, आप निम्नलिखित कोड देख सकते हैं:

MainActivity.kt

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

            // create fragment instance
            val fragment : FragmentName = FragmentName.newInstance()

            // for passing data to fragment
            val bundle = Bundle()
            bundle.putString("data_to_be_passed", DATA)
            fragment.arguments = bundle

            // check is important to prevent activity from attaching the fragment if already its attached
            if (savedInstanceState == null) {
                supportFragmentManager
                    .beginTransaction()
                    .add(R.id.fragment_container, fragment, "fragment_name")
                    .commit()
            }
        }

    }
}

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".ui.MainActivity">

    <FrameLayout
        android:id="@+id/fragment_container"
        android:layout_width="0dp"
        android:layout_height="0dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

FragmentName.kt

class FragmentName : Fragment() {

    companion object {
        fun newInstance() = FragmentName()
    }

    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {

        // receiving the data passed from activity here
        val data = arguments!!.getString("data_to_be_passed")
        return view
    }

    override fun onActivityCreated(savedInstanceState: Bundle?) {
        super.onActivityCreated(savedInstanceState)
    }

}

यदि आप कोटलिन में एक्सटेंशन से परिचित हैं तो आप इस लेख का अनुसरण करके इस कोड को बेहतर बना सकते हैं ।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.