8

Honestly, I can't help but feel that this is done merely to confuse newcomers. Most of the errors on Stack Overflow by complete Android newbies mostly stem from that they have a static inner class Fragment that they don't understand how it works, why it's there, and try to use Activities even though they don't fully understand the concept behind what is happening.

I must admit, I had trouble understanding the "PlaceholderFragment" approach too, and using static inner classes isn't really extensible at all. The first thing you'd have to do is create an actual class outside - but why do newbies have to do that?

I think this could be much more efficient if they used a project structure similar to the following simple fragment-based android project structure:

  • src
    • wholepackagename
      • activity
        • MainActivity
      • fragment
        • FirstFragment
        • SecondFragment
  • res
    • layout
    • values
    • ...

With the code of

src/wholepackagename/activity/MainActivity:

public class MainActivity extends FragmentActivity implements FirstFragment.Callback
{
    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        getSupportFragmentManager().addOnBackStackChangedListener(new OnBackStackChangedListener()
        {
            public void onBackStackChanged()
            {
                int backCount = getSupportFragmentManager().getBackStackEntryCount();
                if (backCount == 0)
                {
                    finish();
                }
            }
        });

        if (savedInstanceState == null)
        {
            getSupportFragmentManager().beginTransaction().add(R.id.main_container, new FirstFragment()).addToBackStack(null).commit();
        }
    }

    @Override
    public void firstFragmentCallback()
    {
        getSupportFragmentManager().beginTransaction().replace(R.id.main_container, new SecondFragment()).addToBackStack(null).commit();
    }
} 

src/wholepackagename/fragment/FirstFragment.java:

public class FirstFragment extends Fragment implements View.OnClickListener
{
    private Callback callback;

    private Button firstFragmentButton;

    public static interface Callback
    {
        void firstFragmentCallback();
    }

    public FirstFragment()
    {
        super();
    }

    @Override
    public void onAttach(Activity activity)
    {
        super.onAttach(activity);
        try
        {
            callback = (Callback) activity;
        }
        catch (ClassCastException e)
        {
            Log.e(getClass().getSimpleName(), activity.getClass().getSimpleName() + " must implement Callback interface!", e);
            throw e;
        }
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
    {
        View rootView = inflater.inflate(R.layout.fragment_first, container, false);
        firstFragmentButton = (Button) rootView.findViewById(R.id.fragment_first_button);
        firstFragmentButton.setOnClickListener(this);
        return rootView;
    }

    @Override
    public void onClick(View v)
    {
        if(v == firstFragmentButton)
        {
            callback.firstFragmentCallback();
        }
    };
}

src/wholepackagename/fragment/SecondFragment.java:

public class SecondFragment extends Fragment implements View.OnClickListener
{
    private Button secondFragmentButton;

    public SecondFragment()
    {
        super();
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
    {
        View rootView = inflater.inflate(R.layout.fragment_second, container, false);
        secondFragmentButton = (Button) rootView.findViewById(R.id.fragment_second_button);
        secondFragmentButton.setOnClickListener(this);
        return rootView;
    }

    @Override
    public void onClick(View v)
    {
        if(v == secondFragmentButton)
        {
            Toast.makeText(getActivity(), "This is an example!", Toast.LENGTH_LONG).show();
        }
    };
}

Android-Manifest.xml:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="wholepackagename"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="19" />
    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name="wholepackagename.activity.MainActivity"
            android:label="@string/app_name">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

res/layout/activity_main.xml:

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/main_container"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />

res/layout/fragment_first.xml:

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

    <Button
        android:id="@+id/fragment_first_button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true" 
        android:text="@string/first_button" />

</RelativeLayout>

res/layout/fragment_second.xml:

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

    <Button
        android:id="@+id/fragment_second_button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:text="@string/second_button" />

</RelativeLayout>

res/values/strings.xml:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="app_name">Application name</string>
    <string name="hello_world">Hello world!</string>
    <string name="action_settings">Settings</string>
    <string name="first_button">First Button</string>
    <string name="second_button">Second Button</string>
</resources>



To me, it seems that the static inner class Fragment doesn't really support any kind of maintainability, it's hard to see what is going on, and the overall functionality is not obvious as the Activity and Fragment (display of fragment and logic) are mixed together, which makes it hard to see and oversee for a newbie.

I believe it would provide an easier entry into developing for the Android platform to have an example like above. Are there any benefits to the current approach, providing a static inner class as a Fragment?

  • 2
    Asked this to myself yesterday – Mirco Jul 19 '14 at 16:02
1
+50

I, and others, share your sentiment that Fragments are pretty weird and should not be blindly accepted as Good Things™.

I always thought the intention behind their existence in the bootstrap code was to throw Fragments in front of developers' faces as early as possible. Since Fragments have not been around since version 1, I imagine Google felt they needed to put some weight behind their introduction in order to get more people on board. But, I can only speculate.

|improve this answer|||||

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.