javaandroidandroid-fragmentsandroid-include

What is the difference between fragment, extending a base class, and includes?


I am new to android and I am trying to understand how to make re-usable UI pieces that I can interact with. I know there are a few techniques out there but I don't understand when one would be better than the other or if they can all be used interchangeably. If someone could point out the differences (or if I've misunderstood), that would be appreciated.

  1. Creating a fragment or fragmentActivity that takes care of the new page. This fragment can then be used whenever applicable but special care must be taken to take care of fragment life cycles.
  2. Extending a base class that has the layout and whatever else is necessary. Any other class can then extend this base and have the base UI also appear and work.
  3. Using <include layout=... lets you re-use only pieces of the UI. For this one, I am not sure where the logic for that layout is supposed to go.

I guess what I'm asking for is a run down of each of these and if I can use whichever one I am more comfortable with without having any negative impacts.

Ps: I'd be using these for things like creating a reusable navigation bar I can put on every page or if different pages all have a help button.


Solution

  • Each of the methods you suggest are indispensable for creating reusable user interfaces, and each have different uses.

    Firstly, layouts just define the visual structure of a user interface, while activities and fragments are the components that define how that visual structure acts. This creates a clear separation between the visual structure and the behavior of a user interface.

    Therefore, the <include/> tag is used to reuse a defined visual structure. This visual structure can be included in any layout, but each activity or fragment can define how that visual structure behaves separately.

    In order to create a reusable behavior, you can subclass an Activity. For example; a FragmentActivity retains the behaviors defined in the Activity class, but adds the ability to house one or more fragments. Any class that subclasses FragmentActivity will keep each of these behaviors as well.

    Fragments were developed to be reusable segments of an Activity, and can define their own visual structure and behavior. Therefore, if you want to be able to reuse both the visual structure and behavior of a section of an Activity, you can create a Fragment in order to do so. Fragments can be subclassed as well, this can be used to modify the visual structure, behavior or both of the extended class.

    And these are not the only ways to create a reusable interface. You can define reusable resources, views, styles or animations to create a modular user interface. Learning how to leverage these various components to suit your needs is a big part of Android development (and development in general).


    Lastly, I will address your post script; how to create a reusable navigation bar for each page, which includes a help button. Hopefully this will show a simple way to create a reusable interface, and that it is not such a daunting task.

    One way of implementing a reusable help button for each Activity is to create a menu resource that can be used as an options menu in a base class:

    <menu xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto">
    
        <item android:id="@+id/action_help" android:title="@string/action_help"
            android:icon="@drawable/ic_help_white_24dp" android:orderInCategory="100"
            app:showAsAction="ifRoom"/>
    
    </menu>
    

    Then this menu resource is inflated within the base class. The base class extends AppCompatActivity (which extends FragmentActivity) in order to make use of the Support Library:

    public abstract class BaseActivity extends AppCompatActivity {
    
        @Override
        public boolean onCreateOptionsMenu(Menu menu) {
            getMenuInflater().inflate(R.menu.base, menu);
            return super.onCreateOptionsMenu(menu);
        }
    
        @Override
        public boolean onOptionsItemSelected(MenuItem item) {
            switch(item.getItemId()) {
                case R.id.action_help:
                    dispatchHelpIntent();
                    return true;
                default:
                    return super.onOptionsItemSelected(item);
            }
        }
    
        protected void dispatchHelpIntent() {
            // Handle help options button
        }
    
    }
    

    With this you can either handle the help button click in the base class, or have a child class override dispatchHelpIntent() to handle it separately. You can also override onCreateOptionsMenu() and onOptionsItemSelected() in a child class to add more items to the menu. Just make sure you call super in both methods, as I do here, in order to retain the help button.

    Next, to create a reusable navigation bar (usually called an App Bar in Android), all you have to do is create a layout file that will be included in the layout file for each Activity:

    <android.support.design.widget.AppBarLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto" android:id="@+id/app_bar"
        android:layout_width="match_parent" android:layout_height="wrap_content"
        android:theme="@style/AppTheme.AppBarOverlay">
    
        <android.support.v7.widget.Toolbar android:id="@+id/toolbar"
            android:layout_width="match_parent" android:layout_height="?attr/actionBarSize"
            android:background="?attr/colorPrimary" app:popupTheme="@style/AppTheme.PopupOverlay"/>
    
    </android.support.design.widget.AppBarLayout>
    

    Then you can include this layout in any other Activity by using the <include/> tag:

    <android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:layout_width="match_parent" android:layout_height="match_parent"/>
    
        <include layout="@layout/app_bar_base"/>
    
        <!-- Activity content goes here -->
    
    </android.support.design.widget.CoordinatorLayout>
    

    And finally add this as the ActionBar ("Action Bar" is the old term for App Bar) in any Activity that extends the BaseActivity:

    public class MainActivity extends BaseActivity {
    
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
            setSupportActionBar(toolbar);
            setupActionBar();
        }
    
        private void setupActionBar() {
            ActionBar actionBar = getSupportActionBar();
            if(actionBar != null) {
                actionBar.setDisplayShowTitleEnabled(true);
            }
        }
    
    }
    

    The reason this cannot be done in the BaseActivity is because, unless every Activity uses the same layout, each Activity must define its own layout with setContentView(). The Toolbar will not be available until the content view is set, so you must set up the Action Bar (App Bar) in each activity separately with this method.