Fragments - Do you have to use an Activity Wrapper around a fragment which comprises the whole Activity?
Asked Answered
R

3

21

Consider the sample app from developers.android.com

This describes using Fragments like so:

  • On a Phone you can use Fragment 1 on Activity A and fragment 2 on Activity B.
  • On a tablet you have more real estate so you use Fragment 1 and Fragment 2 on Activity A.

Great! ... But... On the first example (the one with a phone) you create an Activity with an xml file containing a single <fragment> and that's all, in the activity you only call setContentView() on that xml? That seems like a lot of redundant code (Activity, XML & Fragment to display a Fragment): Can you set a Fragment as an Activity or is a Wrapper with XML always required?

Resee answered 13/7, 2011 at 9:38 Comment(0)
R
37

Ah, found it here

public class MainMenuHolder extends FragmentActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) 
    {
        super.onCreate(savedInstanceState);
        // If not already added to the Fragment manager add it. If you don't do this a new Fragment will be added every time this method is called (Such as on orientation change)
        if(savedInstanceState == null)
            getSupportFragmentManager().beginTransaction().add(android.R.id.content, new MainMenuFragment()).commit();
    }
}

FragmentActivity allow's you to set the Fragment as the content of android.R.id.content which I assume is the android internal ID of the trunk view.

With this method you still end up with an mostly redundant activity (If all you want is the Fragment acting as the Activity). But still, half as much fluff as having an activity and an XML file acting as a container.

Any other answers would be appreciated!

Resee answered 13/7, 2011 at 11:20 Comment(4)
taking your solution one step forward- create generic SingleFragmentActivitythat get a fragment as constructor param, and add it onCreate. then use this Activity every time you need some single fragment activity.Gamber
@Gamber - I do exactly the same thing - I pass the Fragment canonical name as an Action so it can be instantiated from the String.Resee
Well, You can also stop using Fragments unless you actually need one. In most cases using a simple Activity would do the job just as wellAllysonalma
I created a generic SimpleFragmentActivity that does this (simply embeds a fragment) - it also has a builder for instantiation so that you can set a title, theme, etc. github.com/jt-gilkeson/fragment-utilsLeclair
C
2

The online example doesn't fill in all the blanks. I'll try to answer your questions directly:

"On the first example (the one with a phone) should you create an Activity with an xml file containing a single and an activity which only calls setContentView() on that xml and that's all?"

You've started in the right place. But there's more to it than that. There's always more than one way to solve a problem in Android but a recommended way of generating the effect of having a dynamic number of fragments based on avail. real-estate is:

  1. Create layout XML files in /layout for the primary (default) targeted orientation/device/form-factor/SDK
  2. Create layout XML files for the smallest-width baseline for other targeted devices. You may also want to target other orientations, SDKs, etc.
  3. Each layout XML file will have it's own set of defined fragments
  4. In the Activity, check to see which fragments are present.

Clearly an analogous strategy can be adopted for programmatic layouts.

In your example in the original question (from Google's docs) you could have:

  • layout/main.xml :: this layout would only have Fragment 1
  • layout-sw600dp/main.xml :: this layout would have Fragments 1, 2

Then in MainActivity.java you would check for the existence of each fragment. To do that you could use FragmentManager#findFragmentById() to have a check like: if findFragmentById() returns null for Fragment-2 then MainActivity knows the device has loaded layout/main.xml and only supports one fragment.

Stepping 'back' from the example somewhat reveals that: prior to using Fragments you might have called Activity B from Activity A with startAcitityForResult(int). In the Fragment paradigm you probably only need to have a result from Fragment 2 cause something to happen in Fragment 1, so it's reasonable to have MainActivity be the gatekeeper for that. As you expand on the example you may see that in other apps, MainActivity may need to call other activities - for whatever reason. Perhaps you're targeting a large tablet with enough real estate for 3 fragments but on a handset that needs to be 3 activites. Things can get interesting but the Fragment API is fairly powerful.

"Can you set a Fragment as an Activity or is a Wrapper always required when using fragments?"

A Fragment is not an Activity. Indeed Fragments are loaded by Activities, so yes one might say a wrapper is always required. You're touching on aother subtle aspect of Fragments. Whereas Activities behave like MVC Controllers, Fragments could be called "mini-controllers" due to their lifecycle which both resembles and executes alongside an Activity. Again, the Fragment's lifecycle is contained inside ("wrapped by") the lifecycle of the Activity managing the Fragment. I recommend becoming familiar with the Fragment lifecycle documented at http://developer.android.com/guide/topics/fundamentals/fragments.html#Lifecycle.

Clear answered 16/3, 2012 at 18:47 Comment(1)
I have no idea what you're answering here...?Resee
M
1

More generically you could create a fragment container class:

public class SingleFragmentActivity extends Activity {

    public static final String FRAGMENT_NAME = "fragmentName";
    public static final String FRAGMENT_ARGUMENTS = "fragmentArguments";

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        String fragmentName = getIntent().getStringExtra(FRAGMENT_NAME);
        Fragment fragment = Fragment.instantiate(this, fragmentName);
        Bundle fragmentArguments = getIntent().getBundleExtra(FRAGMENT_ARGUMENTS);
        fragment.setArguments(fragmentArguments);
        getSupportFragmentManager().beginTransaction().replace(android.R.id.content,fragment, "tag").commit();
    }
}

now you use this class to instantiate any fragment as a standalone activity:

public void showFragmentAsActivity() {
    Intent intent = new Intent(this, SingleFragmentActivity.class);
    intent.putExtra(SingleFragmentActivity.FRAGMENT_NAME, MyFragment.class.getName());
    intent.putExtra(SingleFragmentActivity.FRAGMENT_ARGUMENTS,MyFragment.getArgumentsBundle("a string argument"));
    startActivity(intent);
}
Mckelvey answered 25/8, 2017 at 16:9 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.