Our first Fragment app

Let's build a Fragment in its simplest possible form so we can understand what is going on, before in later chapters we start producing Fragments all over the place that are of genuine use.

Tip

I urge all readers to go through and build this project. There is a lot of jumping around from file to file, and just reading alone can make it seem more complex than it really is. Certainly, you can copy and paste the code from the download bundle, but please also follow the steps, and create your own projects and classes. Fragments are not too tough, but their implementation, like their name suggests, is a little fragmented.

Create a new project called Simple Fragment using the Basic Activity template and leaving the rest of the settings at their defaults.

Note

Note that there is the option to create a project with a Fragment, but we will learn more doing things ourselves from scratch.

Switch to activity_main.xml and delete the default Hello world! TextView.

Now make sure the root ConstraintLayout is selected by left-clicking it in the Component tree window, and then change its id property to fragmentHolder. We will now be able to get a reference to this layout in our Java code and, as the id property implies, we will be adding a Fragment to it.

Now we will create a layout that will define our fragment's appearance. Right-click the layout folder and choose New | Layout resource file. In the File name field, type fragment_layout, and left-click OK. We have just created a new layout of the LinearLayout type.

Add a single Button widget anywhere on the layout and make its id property button.

Now that we have a simple layout for our fragment to use, let's write some Java code to make the actual fragment.

Tip

Note that you can create a Fragment by simply dragging and dropping one from the palette, but doing things this way is much less flexible and controllable, and flexibility and control are the big benefits to fragments, as we will see throughout the next chapter. By creating a class that extends Fragment, we can make as many fragments from it as we like.

In the project explorer, right-click the folder that contains the MainActivity file. From the context menu, choose New | Java class. In the Name field, type SimpleFragment and left-click OK.

Tip

Note that there are options to create Fragment classes in various pre-coded states to enable you to implement a Fragment more quickly, but these will slightly cloud the learning objectives of this app.

In our new SimpleFragment class, change the code to extend Fragment. As you type the code, you will be asked to choose the specific Fragment class to import, as shown in the following screenshot:

Our first Fragment app

Choose the top option (as shown in the previous screenshot), which is the regular Fragment class.

Tip

We will need all of the following import statements in this class:

import android.app.Fragment;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.Toast;

Now add a single String variable called myString, and a Button variable called myButton, as members.

Now override the onCreate method. Inside the onCreate method, initialize myString to Hello from SimpleFragment. Our code so far (excluding the package declaration and import statements) will look exactly like this next code:

public class SimpleFragment extends Fragment {

   // member variables accessible from anywhere in this fragment
   String myString;
   Button myButton;
    
    @Override
    public void onCreate(Bundle savedInstanceState){
        super.onCreate(savedInstanceState);
        
        myString = "Hello from SimpleFragment";
    }
}

In the previous code, we created a member variable called myString, and then, in the onCreate method, we initialized it. This is very much like we do for our previous apps when only using Activity.

The difference, however, is that we did not set the view or attempt to get a reference to our Button member variable, myButton.

When using Fragment, we need to do this in the onCreateView method. Let's override that now and see how we set the view and get a reference to our Button.

Add this code to the SimpleFragment class after the onCreate method:

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup
container, Bundle savedInstanceState) {

   View view = inflater.inflate(R.layout.fragment_layout,
        container, false);

   myButton = (Button) view.findViewById(R.id.button);
   
   return view;
}

To understand the previous block of code, we must first look at the onCreateView method signature. Observe in the first instance that the start of the method states that it must return an object of the View type:

public View onCreateView...

Next, we have the three arguments. Let's look at the first two:

(LayoutInflater inflater, ViewGroup container,...

We need LayoutInflater as we cannot call setContentView because Fragment provides no such method. In the body of onCreateView, we use the inflate method of inflater to inflate our layout contained in fragment_layout.xml and initialize view (an object of the View type) with the result.

We use container, which was passed in to onCreateView, as an argument in the inflate method as well. The container variable is a reference to the layout in activity_main.xml.

It might seem obvious that activity_main.xml is the containing layout, but, as we will see later in the chapter, the ViewGroup container argument allows any Activity with any layout to be the container for our fragment. This is exceptionally flexible and makes our Fragment code reusable to a significant extent.

The third argument we pass in to inflate is false, which means that we don't want our layout added immediately to the containing layout. We will do this ourselves soon from another part of the code.

The third argument of onCreateView is Bundle savedInstanceState, which is there to help us maintain the data that our fragments hold.

Now that we have an inflated layout contained in view, we can use this to get a reference to our Button as follows:

myButton = (Button) view.findViewById(R.id.button);

And use it as the return value to the calling code, as required:

return view;

Now we can add an anonymous class to listen for clicks on our button in the usual manner. In the onClick method, we display a pop up Toast message to demonstrate that everything is working as expected.

Add this code just before the return statement in onCreateView, as highlighted in the following code:

@Override
public View onCreateView(LayoutInflater inflater, 
      ViewGroup container, 
      Bundle savedInstanceState) {

      View view = inflater.inflate(R.layout.fragment_layout,
      container, false);

      myButton = (Button) view.findViewById(R.id.button);

      myButton.setOnClickListener(
              new View.OnClickListener() {
                        
                            @Override
                             public void onClick(View v) {

                                  Toast.makeText(getActivity(),
                                                     myString , 
                                            Toast.LENGTH_SHORT).
                                            show();
                        }
                  });

      return view;
}

Tip

As a reminder, the getActivity() call used as an argument in makeText gets a reference to the Activity that contains the Fragment. This is required to display a Toast message. We also used getActivity in our FragmentDialog-based classes in the Note to self app.

We can't run our app just yet; it will not work because there is one more step required. We need to create an instance of SimpleFragment and initialize it appropriately. This is where FragmentManager will get introduced.

This next code creates a new FragmentManager by calling getFragmentManager. It creates a new Fragment, based on our SimpleFragment class using the FragmentManager, and passing in the id of the layout (within the Activity) that will hold it.

Add this code to the onCreate method of MainActivity.java just after the call to setContentView:

// Get a fragment manager
FragmentManager fManager = getFragmentManager();

// Create a new fragment using the manager
// Passing in the id of the layout to hold it
Fragment frag = fManager.findFragmentById(R.id.fragmentHolder);

// Check the fragment has not already been initialized
if(frag == null){

   // Initialize the fragment based on our SimpleFragment
   frag  = new SimpleFragment();
   fManager.beginTransaction()
                .add(R.id.fragmentHolder, frag)
                .commit();

}

Tip

You will need to add the following import statements to the MainActivity class:

import android.app.Fragment;
import android.app.FragmentManager;

Now run the app and gaze in wonder at our clickable button that displays a message with the Toast class, and which took two layouts and two whole classes to create:

Our first Fragment app

If you remember doing that way back in Chapter 2, First Contact: Java, XML and the UI Designer, and with far less code, then it is clear that we need a fragment reality check to answer a question; like, WHY!

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.220.1.239