[android] How do I add a Fragment to an Activity with a programmatically created content view

I want to add a Fragment to an Activity that implements its layout programmatically. I looked over the Fragment documentation but there aren't many examples describing what I need. Here is the type of code I tried to write:

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

This code compiles but crashes at start, probably because my FragmentTransaction.add() is incorrect. What is the correct way to do this?

This question is related to android android-3.0-honeycomb android-fragments

The answer is


This may help you

Defining a Fragment

create xml file for fragment view fragment_abc.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent" android:layout_height="match_parent"
android:orientation="vertical" >

<TextView
    android:id="@+id/textView1"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="TextView" />

<Button
    android:id="@+id/button1"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Button" />

</LinearLayout>

create fragment ABCFragment.java

import androidx.fragment.app.Fragment;

public class FooFragment extends Fragment {
// The onCreateView method is called when Fragment should create its View object hierarchy,
// either dynamically or via XML layout inflation. 

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup parent, Bundle 
savedInstanceState) {
    // Defines the xml file for the fragment
    return inflater.inflate(R.layout.fragment_abc, parent, false);
}

// This event is triggered soon after onCreateView().
// Any view setup should occur here.  E.g., view lookups and attaching view listeners.
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
    // Setup any handles to view objects here
    // EditText etFoo = (EditText) view.findViewById(R.id.etFoo);
}
}

Add frameLayout in your activity

<FrameLayout
   android:id="@+id/your_placeholder"
   android:layout_width="match_parent"
   android:layout_height="match_parent">

now in activity, add following method

protected void setFragment() {
    // Begin the transaction
    FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
    // Replace the contents of the container with the new fragment
    ft.replace(R.id.fragment_container, new ABCFragment());
    // or ft.add(R.id.your_placeholder, new ABCFragment());
    // Complete the changes added above
    ft.commit();
}

reference : https://guides.codepath.com/android/creating-and-using-fragments#defining-a-fragment


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

}

use

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

}

After read all Answers I came up with elegant way:

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

}

basically you don't need to add a frameLayout as container of your fragment instead you can add straight the fragment into the android root View container

IMPORTANT: don't use replace fragment as most of the approach shown here, unless you don't mind to lose fragment variable instance state during onrecreation process.


Here is what I came up with after reading Tony Wong's comment:

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

If you are using Kotlin make sure to take a look at what the Kotlin extensions by Google provide or just write your own.


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

To add a fragment into a Activity or FramentActivity it requires a Container. That container should be a "Framelayout", which can be included in xml or else you can use the default container for that like "android.R.id.content" to remove or replace a fragment in Activity.

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>

For attaching fragment to an activity programmatically in Kotlin, you can look at the following code:

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

}

If you are familiar with Extensions in Kotlin then you can even better this code by following this article.


For API level 17 or higher, View.generateViewId() will solve this problem. The utility method provides a unique id that is not used in build time.


Examples related to android

Under what circumstances can I call findViewById with an Options Menu / Action Bar item? How to implement a simple scenario the OO way My eclipse won't open, i download the bundle pack it keeps saying error log getting " (1) no such column: _id10 " error java doesn't run if structure inside of onclick listener Cannot retrieve string(s) from preferences (settings) strange error in my Animation Drawable how to put image in a bundle and pass it to another activity FragmentActivity to Fragment A failure occurred while executing com.android.build.gradle.internal.tasks

Examples related to android-3.0-honeycomb

Why fragments, and when to use fragments instead of activities? How to implement the Android ActionBar back button? How to hide action bar before activity is created, and then show it again? Android replace the current fragment with another fragment getActionBar() returns null Fragments onResume from back stack How to set a Fragment tag by code? Android: How to change the ActionBar "Home" Icon to be something other than the app icon? ActionBar text color Unable to resolve host "<insert URL here>" No address associated with hostname

Examples related to android-fragments

FragmentActivity to Fragment How to start Fragment from an Activity How to use data-binding with Fragment In android how to set navigation drawer header image and name programmatically in class file? Android Fragment onAttach() deprecated How to convert any Object to String? Activity, AppCompatActivity, FragmentActivity, and ActionBarActivity: When to Use Which? Difference and uses of onCreate(), onCreateView() and onActivityCreated() in fragments java.lang.IllegalStateException: Fragment not attached to Activity java.lang.NullPointerException: Attempt to invoke virtual method 'int android.view.View.getImportantForAccessibility()' on a null object reference