Presentation is loading. Please wait.

Presentation is loading. Please wait.

Chapter 9: Fragments.

Similar presentations


Presentation on theme: "Chapter 9: Fragments."— Presentation transcript:

1 Chapter 9: Fragments

2 Learning Objectives Divide the screen into several parts and use fragments to manage them Explore various ways to manage fragments, using XML and code

3 Fragments A fragment is a portion of an activity and can help manage a portion of the screen (although a fragment can also be invisible). Think of a fragment as a mini-activity. Fragments help support larger screen devices like tablets. Fragments were introduced with API level 11.

4 Activity with Three Fragments

5 Why Use Fragments? Fragments are reusable.
A fragment developed for one activity (or one app) can be reused in another activity (or another app).

6 Fragments We build an app with three fragments (actually four, including an invisible fragment) to simulate the game of hangman. Model = Hangman.java (see Example 9.1)

7 Fragment Topics Create and add a fragment using XML
Create and add a fragment using XML and code Create and add a fragment using code only Communication between an activity and a fragment Create and add an invisible fragment Make a fragment reusable

8 Fragments (1 of 2) In order to define a fragment, we extend the Fragment class or one of its subclasses. A fragment must be embedded inside an activity. A fragment has life cycle methods of its own, but they depend on the life cycle methods of the activity in which the fragment is.

9 Fragments (1 of 2) Selected subclasses of the Fragment class

10 Version 0: XML We use a fragment, created and added using XML, for the red part on the left.

11 Fragment by XML The overall activity layout file (activity_main.xml) specifies a fragment element (and other elements) in its layout. We code a fragment XML layout (fragment_game_control.xml). We code a class extending Fragment that manages the fragment (GameControlFragment).

12 activity_main.xml (1 of 5)
As usual, a layout XML file (activity_main.xml) defines the GUI for the an activity (MainActivity). activity_main.xml includes a fragment element, specifies the name of its class and the name of its associated XML layout file.

13 activity_main.xml (2 of 5)
We use a LinearLayout to organize the GUI. We split the screen horizontally into two even parts: a fragment on the left and a LinearLayout on the right. To divide the screen horizontally, we use the android:layout_weight and android:layout_width attributes.

14 activity_main.xml (3 of 5)
If we have two elements, we can split the screen 25/75 between them by giving android:layout_weight values of 1 and 3 to them (1 / ( )) = 25% and (3 / ( 1 + 3)) = 75% and we specify android:layout_width values of 0 so that the widths are calculated based on the weights.

15 activity_main.xml (4 of 5)
To divide the screen evenly, we use android:layout_weight values of 1 and 1. Thus, each element (a fragment on the left and a LinearLayout on the right) has the same amount of space, half the screen.

16 activity_main.xml (5 of 5)
<LinearLayout … > <fragment … android:layout_weight="1" android:layout_width="0dp" … <LinearLayout … android:layout_weight="1" android:layout_width="0dp" >

17 Fragment Element The fragment element includes attributes to specify its name (GameControlFragment) and its layout file (fragment_game_control.xml). The attributes are android:name and tools:layout.

18 activity_main.xml <LinearLayout … > <fragment android:name="com.jblearning.hangmanv0.GameControlFragment" android:layout_height="match_parent" android:layout_weight="1" android:layout_width="0dp"

19 fragment_game_control.xml (1 of 2)
The fragment_game_control.xml file defines the fragment layout. At this point the fragment is just a red linear layout matching its parent in size.

20 fragment_game_control.xml (2 of 2)
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android=" android:layout_width="match_parent" android:layout_height="match_parent" android:background="#FF00" > </LinearLayout>

21 GameControlFragment Class (1 of 5)
GameControlFragment extends Fragment. It must have a default constructor: when an activity's state is restored, any fragment inside the activity is automatically re-instantiated  we need a default constructor for that.

22 GameControlFragment Class (2 of 5)
public class GameControlFragment extends Fragment { public GameControlFragment( ) { }

23 GameControlFragment Class (3 of 5)
The onCreateView method is automatically called when the fragment is created. Inside it, we inflate the XML for the fragment by calling the inflate method with a LayoutInflater (a parameter of onCreateView).

24 GameControlFragment Class (4 of 5)
The inflate method returns a reference to the View that results from the XML file that is inflated. We return it (since onCreateView returns a View).

25 GameControlFragment Class (5 of 5)
public View onCreateView( LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState ) { return inflater.inflate( R.layout.fragment_game_control, container, false ); }

26 Life Cycle Methods (1 of 3)
We can check which methods of the Activity and Fragment classes are called in what order when an activity goes in the background, comes back to the foreground, is closed ... See Figure 9.6

27 Life Cycle Methods (2 of 3)
The Activity and Fragment classes have similar methods (onStart, onPause, onResume, onStop, onDestroy ...).

28 Life Cycle Methods (3 of 3)
When an Activity shows, Fragment methods are called after the corresponding Activity methods. When an Activity goes off screen, Fragment methods are called before the corresponding Activity methods.

29 Version 1 (1 of 2) In Version 1, we populate the fragment on the left part of the screen with a button (“PLAY”) and a TextView (storing the number of guesses left—retrieved from the Model).

30 Version 1 (2 of 2)

31 activity_main.xml (1 of 2)
We give the two LinearLayouts on the right of the screen ids so that we can access them programmatically later. <LinearLayout … > <LinearLayout … >

32 activity_main.xml (2 of 2)
We also create a colors.xml file and use the defined colors in activity_main.xml See Examples 9.5 and 9.6 We add a string named play in strings.xml. We also add to the styles.xml file and create styles for LinearLayouts, TextViews, EditTexts, and Buttons (see Example 9.9) .

33 fragment_game_control.xml (1 of 3)
We add a Button (PLAY) and a TextView (number of guesses left) in the fragment_game_control.xml layout file. We place them inside LinearLayouts so that the Button is centered within the top half of the screen and the TextView is centered within the bottom half.

34 fragment_game_control.xml (2 of 3)
Clicking on the button triggers a call to the play method <Button android:onClick="play" />

35 fragment_game_control.xml (3 of 3)
We give the TextView an id so we can update it later. <TextView />

36 MainActivity We add a Hangman instance variable Inside onCreate
if ( game == null ) game = new Hangman( Hangman.DEFAULT_GUESSES ); setContentView( R.layout.activity_main ); TextView status = ( TextView ) findViewById( R.id.status ); status.setText( "" + game.getGuessesLeft( ) );

37 MainActivity, Version 1 We implement the play method as a do nothing method (if we do not, the app will crash if the user clicks on the play button). We will enable play in Version 4.

38 Version 2 (1 of 3) In Version 2, we add a fragment to an activity programmatically (in blue in the top right area of the screen). To keep it simple, we set the activity orientation to landscape in the manifest android:screenOrientation="landscape"

39 Version 2 (2 of 3) We define the fragment in an XML file.
We add it to the activity programmatically, inside the MainActivity class. The fragment contains a TextView (showing the state of the game) and an EditText (user input). We both wrap them inside a LinearLayout so they can each take half the space and be centered.

40 Version 2 (3 of 3)

41 fragment_game_state.xml We give an id to the TextView and the EditText so we can access them later (retrieve user input and update the state of the game). See Example 9.11

42 Adding a Fragment (1 of 4) To programmatically add a fragment to an activity: Get the fragment manager for the activity Create a fragment transaction Create a fragment Create a transaction: Add the fragment to a container (a ViewGroup) Commit the fragment transaction

43 Adding a Fragment (2 of 4) Get the fragment manager for the activity
The FragmentManager (abstract) class provides the functionality to interact with fragments within an activity. To obtain a reference to the fragment manager, we use this method (from the Activity class). FragmentManager getFragmentManager( ) FragmentManager manager = getFragmentManager( );

44 Adding a Fragment (3 of 4) Create a fragment transaction
The FragmentTransaction class contains methods to perform fragment operations such as adding a fragment to an activity, hiding it, removing it, replacing it ... (see Table 9.5).

45 Adding a Fragment (4 of 4) To obtain a FragmentTransaction reference, we use the beginTransaction method from the Fragment Manager class. FragmentTransaction beginTransaction( ) FragmentTransaction transaction = manager.beginTransaction( );

46 Managing Fragments The FragmentManager class contains methods to retrieve a fragment, by id or tag. Method Description Fragment findFragmentById( int id ) Returns a Fragment identified by its id Fragment findFragmentByTag( String tag ) Returns a Fragment identified by its tag

47 Adding a Fragment (1 of 3) FragmentManager manager =
getFragmentManager( ); FragmentTransaction transaction = manager.beginTransaction( ); Now we need to create the fragment and add it to the activity.

48 Adding a Fragment (2 of 3) Create a fragment
The GameStateFragment class extends the Fragment class GameStateFragment fragment = new GameStateFragment( );

49 Adding a Fragment (3 of 3) Add the fragment, and give it an id (so we can retrieve it later). Then, commit the transaction transaction.add( R.id.game_state, fragment ); transaction.commit( ); See Example 9.12, MainActivity class

50 GameStateFragment Class (1 of 2)
The GameStateFragment class (Example 9.13) extends Fragment. It includes a default constructor. Inside onCreateView, we inflate the XML layout file for the fragment. Inside onStart, we update the TextView of the fragment with data retrieved from the Model.

51 GameStateFragment Class (2 of 2)
Since we are not inside MainActivity and the Model (Hangman) reference is in MainActivity, we need to get a reference to MainActivity; we use the getActivity method from the Fragment class. Activity getActivity( )  Need to cast the return value to our Activity class (MainActivity)

52 GameStateFragment Class: Inside onStart Method (1 of 2)
Retrieve the View for this fragment Retrieve the TextView inside the fragment’s View so we can update it Get a reference to MainActivity Retrieve the state of the Model and update the TextView

53 GameStateFragment Class: Inside onStart Method (2 of 2)
super.onStart( ); View fragmentView = getView( ); TextView gameStateTV = ( TextView ) fragmentView.findViewById( R.id.state_of_game ); MainActivity fragmentActivity = ( MainActivity ) getActivity( ); gameStateTV.setText( fragmentActivity .getGame( ).currentIncompleteWord( ) );

54 Version 3 (1 of 3) Creating (and adding) a fragment programmatically
We create and place a fragment in the bottom right part of the screen (green background). Inside the fragment, we display a message about the result of the game once the game is over; we display GOOD LUCK when the game starts.

55 Version 3 (2 of 3)

56 Version 3 (3 of 3) The game result fragment contains one GUI component, a TextView. GameResultFragment includes a TextView instance variable. Inside onCreateView, we instantiate it and add it to the ViewGroup parameter of onCreateView. We hard code the text of the TextView to GOOD LUCK (see Example 9.15).

57 GameResultFragment Class (1 of 4)
private TextView gameResultTV; Inside onCreateView, set up the GUI for this fragment. Inside onStart, set the initial text for the TextView inside this fragment.

58 GameResultFragment Class (2 of 4)
public View onCreateView( LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState ) { // Our setUpFragmentGui method creates // the GUI for this fragment setUpFragmentGui( container ); return super.onCreateView( inflater, container, savedInstanceState ) ; }

59 GameResultFragment Class (3 of 4)
public void setUpFragmentGui( ViewGroup container ) { if( gameResultTV == null ) { gameResultTV = new TextView( getActivity( ) ); gameResultTV.setGravity( Gravity.CENTER ); container.addView( gameResultTV ); } }

60 GameResultFragment Class (4 of 4)
public void onStart( ) { super.onStart( ); gameResultTV.setText( "GOOD LUCK" ); }

61 Version 3 Inside MainActivity, the steps and code to add the game result fragment are similar to those adding the game state fragment (Version 2).

62 Version 4 (1 of 3) In Version 4, we enable play.
This happens after the user enters a letter and clicks on the PLAY button. We make the fragments communicate with the activity to which they belong.

63 Version 4 (2 of 3)

64 Version 4 (3 of 3) Capture user input Update the Model Update the View
Clear the EditText (user entry) Check whether the game is over; if it is, update the View

65 Version 4: Play Method We code the play method of MainActivity
We first retrieve user input EditText input = ( EditText ) findViewById( R.id.letter ); Editable userText = input.getText( );

66 Version 4: Play Method, Retrieve User Input
We only care about the first letter of the user input (the user is supposed to enter only one letter) if( userText != null && userText.length( ) > 0 ) { // retrieve first letter char letter = userText.charAt( 0 );

67 Version 4: Update Model Update the Model, and update the number of guesses left inside the View game.guess( letter ); TextView status = ( TextView ) findViewById( R.id.status ); status.setText( "" + game.getGuessesLeft( ) );

68 Version 4: Access TextView (1 of 3)
Now we update the incomplete word, retrieving the updated incomplete word from the Model. We access the TextView inside the game state fragment using the following steps: we get a reference to the fragment manager, then get a reference to the game state fragment, then get a reference to the game state fragment’s view, and then get a reference to the TextView inside it.

69 Version 4: Access TextView (2 of 3)
Get a reference to the fragment manager FragmentManager fragmentManager = getFragmentManager( ); Get a reference to the fragment GameStateFragment gsFragment = ( GameStateFragment ) fragmentManager.findFragmentById( R.id.game_state );

70 Version 4: Access TextView (3 of 3)
Get a reference to the fragment’s view View gsFragmentView = gsFragment.getView( ); Get a reference to the TextView TextView gameStateTV = ( TextView ) gsFragmentView.findViewById( R.id.state_of_game );

71 Version 4: Update View Retrieve the updated incomplete word from the Model and set the text inside the TextView gameStateTV.setText( game.currentIncompleteWord( ) );

72 Version 4: Clear User Input
Clear the EditText input.setText( "" );

73 Version 4: Is Game Over? Check whether the game is over
int result = game.gameOver( ); if( result != 0 ) /* game is over */ { // update the TextView in the result fragment // delete hint in EditText }

74 Version 4: Game Is Over (1 of 3)
Retrieve the game result fragment GameResultFragment grFragment = ( GameResultFragment ) fragmentManager.findFragmentById( R.id.game_result );

75 Version 4: Game Is Over (2 of 3)
Update TextView in game result fragment We need to code the setResult method in the GameResultFragment class if( result == 1 ) grFragment.setResult( "YOU WON" ); else if( result == -1 ) grFragment.setResult( "YOU LOST" );

76 Version 4: Game Is Over (3 of 3)
Delete hint in EditText input.setHint( "" );

77 Version 4 The setResult method of the GameResultFragment class
public void setResult( String result ) { gameResultTV.setText( result ); }

78 Version 5 (1 of 7) A fragment can be invisible, doing some work in the background without any visual representation. We keep the invisible fragment as simple as possible; it includes a method that returns a String, a warning (“ONLY 1 LEFT!”). Whenever there is one guess left, we call that method and update the View with the warning.

79 Version 5 (2 of 7)

80 Version 5 (3 of 7) The new fragment class, BackgroundFragment, extends Fragment and includes this method public String warning( ) { return "ONLY 1 LEFT!"; }

81 Version 5 (4 of 7) Inside the onCreate method of MainActivity, we need to add the fragment. Inside the play method, we need to retrieve it in order to call its warning method and retrieve the message so that we can update the View when there is only one guess left.

82 Version 5 (5 of 7) In order to be able to retrieve the fragment later, we give it a tag when we create it (inside onCreate method of MainActivity) if( fragmentManager.findFragmentByTag( "background" ) == null ) { FragmentTransaction transaction = fragmentManager.beginTransaction( ); BackgroundFragment fragment = new BackgroundFragment( ); transaction.add( fragment, "background" ); // the tag is background transaction.commit( ); }

83 Version 5 (6 of 7) Inside the play method, if there is only one guess left, we want to ask the invisible fragment for the warning String. Check whether there is only one guess left if( game.getGuessesLeft( ) == 1 ) { // Retrieve the background fragment // Retrieve the game result fragment // Retrieve the warning from the background fragment // Display the warning in the game result fragment }

84 Version 5 (7 of 7) if( game.getGuessesLeft( ) == 1 ) { BackgroundFragment background = ( BackgroundFragment ) fragmentManager.findFragmentByTag( "background" ); GameResultFragment grFragment = ( GameResultFragment ) fragmentManager.findFragmentById( R.id.game_result ); // retrieve warning and display it grFragment.setResult( background.warning( ) ); }

85 Version 6 (1 of 4) Fragments should be reusable (so they can be reused in either the same app or other apps). A fragment class using a MainActivity reference is NOT reusable. MainActivity fragmentActivity = ( MainActivity ) getActivity( ); gameStateTV.setText( fragmentActivity.getGame( ) currentIncompleteWord( ) ); Thus, the GameStateFragment class (of Version 5) is not reusable.

86 Version 6 (2 of 4) Furthermore, the MainActivity reference calls the getGame method, which returns a Game reference (with which we call the currentIncompleteWord method). Thus, not only the GameStateFragment class is dependent on MainActivity but it is also (indirectly) dependent on the Game class.

87 Version 6 (3 of 4) Inside the GameStateFragment class, we include an inner interface (Callbacks) that defines a method named getGame; it returns a WordGame. WordGame is an interface. In this way, we make GameStateFragment reusable with any game class that implements WordGame and any Activity class that implements Callbacks.

88 Version 6 (4 of 4) See Examples 9.20, 9.21, 9.22, and 9.23 for full implementation.

89 Version 7 (1 of 8) In Version 7, we improve the app.
Whenever the user closes the keyboard, we enable play (without clicking on the PLAY button). The onEditorAction method of the TextView.OnEditorActionListener interface is called when a key event happens inside an EditText (provided that a TextView.OnEditorActionListener is registered on the EditText).

90 Version 7 (2 of 8) In order to implement event handling inside the GameStateFragment class, we do (as usual): Write an event handler (a class extending a listener interface); Instantiate an object of that class; Register that object listener on one or more GUI components.

91 Version 7 (3 of 8) private class OnEditorHandler implements TextView.OnEditorActionListener { public boolean onEditorAction( TextView v, int keyCode, KeyEvent event ) { // hide the keyboard // play return true; } }

92 Version 7 (4 of 8) Method Description
We can hide the keyboard using the hideSoftInputFromWindow method of the InputMethodManager class. Method Description boolean hideSoftInputFromWindow( IBinder token, int flags ) token is the token of the Window making the request; flags specifies additional condition for hiding the soft input.

93 Version 7 (5 of 8) Thus, we need an InputMethodManager reference.
We use the getSystemService method of the Context class (and therefore inherited by Activity) Object getSystemService( String nameOfService )

94 Version 7 (6 of 8) The Context class includes String constants (the parameter of the getSystemService method is a String) that parallel the return type of getSystemService.

95 Version 7 (7 of 8) Selected constants of the Context class and corresponding return types of the getSystemService method. String constant String value getSystemService Return Type POWER_SERVICE power PowerManager LOCATION_SERVICE location LocationManager WIFI_SERVICE wifi WifiManager DOWNLOAD_SERVICE download DownloadManager INPUT_METHOD_SERVICE input_method InputMethodManager

96 Version 7 (8 of 8) To get an InputMethodManager reference, we pass the INPUT_METHOD_SERVICE constant of the Context class.

97 onEditorAction Method: Hide the Keyboard (1 of 3)
InputMethodManager inputManager = ( InputMethodManager ) getActivity( ).getSystemService( Context.INPUT_METHOD_SERVICE ); Now we call the hideSoftInputFromWindow method with inputManager in order to hide the keyboard.

98 onEditorAction Method: Hide the Keyboard (2 of 3)
The first parameter of hideSoftInputFromWindow is the window token. We get the window token by accessing the current View in focus and calling getWindowToken with it getActivity( ).getCurrentFocus( ).getWindowToken( )

99 onEditorAction Method: Hide the Keyboard (3 of 3)
Since the user opened the keyboard, we should use the HIDE_NOT_ALWAYS constant and not the HIDE_IMPLICIT_ONLY constant of the InputMethodManager class as the second argument of hideSoftInputFromWindow inputManager.hideSoftInputFromWindow( getActivity( ).getCurrentFocus( ).getWindowToken( ), InputMethodManager.HIDE_NOT_ALWAYS );

100 onEditorAction method: To Play, Call the Play Method

101 Inside onStart Method: Register the Listener
// set up event handling for the keyboard EditText answerET = ( EditText ) fragmentView.findViewById( R.id.letter ); OnEditorHandler editorHandler = new OnEditorHandler( ); answerET.setOnEditorActionListener( editorHandler );


Download ppt "Chapter 9: Fragments."

Similar presentations


Ads by Google