Android
Fragment
Best Practices
App Development
Mobile Development

Best practice for instantiating a new Android Fragment

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

The safest default for creating a Fragment in Android is still simple: keep a public empty constructor, put startup arguments in a Bundle, and let the FragmentManager recreate the Fragment when needed. This matches how the Android framework restores fragments across configuration changes and process recreation.

The old advice to "always use newInstance" is not wrong, but the real principle is more specific: do not rely on custom constructors for Fragment state. Arguments belong in the fragment arguments bundle, and long-lived dependencies belong in a ViewModel, a FragmentFactory, or a DI container.

Keep Construction Compatible With Recreation

Android may recreate a fragment later without going through your own calling code. That is why custom constructors with required parameters are risky. The framework expects to be able to instantiate the fragment safely.

A common pattern is:

kotlin
1class ExampleFragment : Fragment() {
2
3    companion object {
4        private const val ARG_PARAM1 = "param1"
5        private const val ARG_PARAM2 = "param2"
6
7        fun newInstance(param1: String, param2: String): ExampleFragment {
8            return ExampleFragment().apply {
9                arguments = Bundle().apply {
10                    putString(ARG_PARAM1, param1)
11                    putString(ARG_PARAM2, param2)
12                }
13            }
14        }
15    }
16}

This works well because the arguments are stored in a form the FragmentManager understands and can restore.

Read Arguments in the Fragment, Not in the Constructor

Once the fragment exists, read those values from arguments:

kotlin
1class ExampleFragment : Fragment() {
2    private var param1: String? = null
3    private var param2: String? = null
4
5    override fun onCreate(savedInstanceState: Bundle?) {
6        super.onCreate(savedInstanceState)
7        arguments?.let {
8            param1 = it.getString("param1")
9            param2 = it.getString("param2")
10        }
11    }
12}

This keeps the data lifecycle aligned with the fragment lifecycle instead of the caller's construction path.

Use Fragment Transactions Deliberately

Once instantiated, add or replace the fragment through FragmentManager:

kotlin
1val fragment = ExampleFragment.newInstance("alpha", "beta")
2
3supportFragmentManager.beginTransaction()
4    .replace(R.id.fragment_container, fragment)
5    .addToBackStack(null)
6    .commit()

This is the point where the fragment becomes part of the UI lifecycle. Instantiation and attachment are related but separate concerns.

Know When newInstance Is Not Enough

newInstance is mainly about arguments. It is not a full dependency-injection solution. If the fragment needs repositories, services, or test-controlled collaborators, pushing them through a constructor is still not ideal for normal fragment recreation.

Better options include:

  • storing UI state in a ViewModel
  • using a FragmentFactory for advanced creation control
  • letting your dependency-injection framework integrate with fragment creation

That way the arguments bundle remains for lightweight state, while larger dependencies follow a more appropriate lifecycle.

If your app uses the Navigation component, the same idea still applies. Arguments are defined declaratively and delivered through the navigation system rather than through ad hoc constructor logic.

The best practice does not change: fragment state that must survive recreation belongs in supported Android lifecycle mechanisms, not in a custom constructor contract.

Common Pitfalls

The biggest mistake is putting required fragment state into a non-default constructor. That often works in a happy-path demo and then breaks during configuration change or process recreation.

Another common issue is passing too much through fragment arguments. Bundles are for serializable startup state, not for large service graphs or heavy objects.

People also create a fragment correctly but then bypass the FragmentManager lifecycle with ad hoc handling elsewhere. Instantiation style alone does not save a fragment architecture that ignores lifecycle ownership.

Finally, do not confuse "factory method" with "mandatory magic." The important part is the arguments bundle and framework-compatible recreation, not the exact method name.

Summary

  • Keep fragment creation compatible with framework recreation.
  • Put startup state in arguments, not in custom constructors.
  • A newInstance companion function is a clean way to package those arguments.
  • Use ViewModel, FragmentFactory, or DI for heavier dependencies.
  • Let FragmentManager and the Android lifecycle own fragment recreation.

Course illustration
Course illustration

All Rights Reserved.