material-components/material-components-android · error · IllegalStateException

Demo must implement createFragment or createActivityIntent

Error message

Demo must implement createFragment or createActivityIntent

What it means

DemoLandingFragment.startDemo(Demo, View, String) launches a demo by first calling demo.createFragment() and then demo.createActivityIntent(). If both return null the demo cannot be started and an IllegalStateException is thrown — the same contract as Demo.getDemoClassName(): every Demo must implement at least one factory method.

Source

Thrown at catalog/java/io/material/catalog/feature/DemoLandingFragment.java:225

  }

  private void startDemo(@NonNull Demo demo) {
    startDemo(demo, null, null);
  }

  private void startDemo(
      @NonNull Demo demo, @Nullable View sharedElement, @Nullable String transitionName) {
    Fragment fragment = demo.createFragment();
    if (fragment != null) {
      startDemoFragment(fragment, sharedElement, transitionName);
      return;
    }
    Intent activityIntent = demo.createActivityIntent();
    if (activityIntent != null) {
      startDemoActivity(activityIntent, sharedElement, transitionName);
      return;
    }
    throw new IllegalStateException("Demo must implement createFragment or createActivityIntent");
  }

  private void startDemoFragment(
      Fragment fragment, @Nullable View sharedElement, @Nullable String transitionName) {
    Bundle args = new Bundle();
    args.putString(DemoFragment.ARG_DEMO_TITLE, getString(getTitleResId()));
    args.putString(FeatureDemoUtils.ARG_TRANSITION_NAME, transitionName);
    fragment.setArguments(args);
    FeatureDemoUtils.startFragment(
        getActivity(), fragment, FRAGMENT_DEMO_CONTENT, sharedElement, transitionName);
  }

  private void startDemoActivity(
      Intent intent, @Nullable View sharedElement, @Nullable String transitionName) {
    intent.putExtra(DemoActivity.EXTRA_DEMO_TITLE, getString(getTitleResId()));

    if (sharedElement != null && transitionName != null) {
      intent.putExtra(DemoActivity.EXTRA_TRANSITION_NAME, transitionName);

View on GitHub (pinned to ac7e18efee)

Solutions

  1. Implement createFragment() in the Demo being launched, returning its Fragment.
  2. Or implement createActivityIntent() returning an Intent to the demo Activity.
  3. Verify the demo entry wired into the landing fragment's list is the Demo class you actually implemented.

Example fix

// before
new Demo(R.string.my_demo_title, R.drawable.my_demo_icon) {} // no factory

// after
new Demo(R.string.my_demo_title, R.drawable.my_demo_icon) {
  @Override
  public Fragment createFragment() {
    return new MyDemoFragment();
  }
}
Defensive patterns

Strategy: validation

Validate before calling

Fragment f = demo.createFragment();
Intent i = (f == null) ? demo.createActivityIntent() : null;
if (f != null || i != null) {
  // safe to start
}

Prevention

When it happens

Trigger: Registering a Demo subclass that implements neither createFragment() nor createActivityIntent(), then tapping its entry in the demo landing list so startDemo is invoked.

Common situations: Adding a new demo to a landing screen but leaving the Demo object empty; returning null from createFragment() conditionally; merging demos and dropping an override during the merge.

Related errors


AI-assisted analysis of material-components/material-components-android@ac7e18efee (2026-08-14). Data as JSON: /api/errors/d308099ba42ef82c. Report an issue: GitHub.