mobappdev (fall 2014): fragments
DESCRIPTION
TRANSCRIPT
MobAppDev
Fragments & ViewGroups, Fragment Management, Fragment Creation,
Activity vs Fragment Lifecycles
Vladimir Kulyukin
www.vkedco.blogspot.com
Outline
● Fragments & ViewGroups● Fragment Management● Fragment Creation● Activity vs. Fragment Lifecycle
Fragments & ViewGroups
Fragment Lifecycle
source image at http://developer.android.com/guide/components/fragments.html
Fragments & ViewGroups
● When a fragment is added to an activity layout, it becomes a component in a ViewGroup (a container that may contain other views called children) inside the activity's view hierarchy
● A fragment may define its own view layout● A fragment can be inserted into the activity's layout file via the
tags <fragment></fragment>
Example: ListFragment Inside LinearLayout<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<fragment class="org.vkedco.mobappdev.rumi_quatrain_fragments.QuatrainNumberListFragment"
android:id="@+id/quatrain_numbers"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
Fragments & ViewGroups● Fragments are not required to be a part of the activity layout; there
may be fragments w/o UIs as background workers for activities● A Fragment should be designed as a modular and reusable activity
component● Why? Since fragments may define their own layouts and have their
own lifecycle callbacks, one fragment may be included in multiple activities
● Direct manipulation of one fragment from another fragment should be avoided: breaks modularity and leads to cycle-related errors
Fragments on Tablets
Here is a useful link to the design and implementation practices of how to design fragments for reuse if you want to develop for multiple screen sizes:
http://developer.android.com/guide/practices/tablets-and-handsets.html
Fragment Management
Managing Fragments● Fragments are managed with the FragmentManager class
● FragmentManager object can be obtained via Activity. getFragmentManager()
● FragmentManager is used to:
Find fragments in an activity either with findFragmentById() (for fragments that have IDs) or findFragmentByTag() (for fragments that do not have UIs)
Pop fragments off the back stack, with popBackStack() (this is the same as the user's pressing Back button)
Register a listener for changes to the back stack, with addOnBackStackChangedListener()
open FragmentTransaction objects to add and remove fragments
Fragment Transactions● FragmentTransactions are used to add, remove, replace, and
perform other actions with them, in response to UI gestures● A transaction is a set of changes that must be committed with respect
to the activity● It is also possible to save each transaction to a back stack managed
by the activity● The user can navigate navigate back through the fragment changes
Beginning & Ending Transactions
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
// some code
// each transaction must be committed to take effect
fragmentTransaction.commit();
A Typical Transaction Sequence
// 1) create new fragment and transaction
Fragment newFrgmnt = new SomeFragment();
FragmentTransaction trans = getFragmentManager().beginTransaction();
// 2) replace the contents of the view container with the newly created fragment,
// 3) add the transaction to the back stack
trans.replace(R.id.view_container, newFrgmnt);
trans.addToBackStack(null);
// 4) commit the transaction
transaction.commit();
Fragment Creation
Fragment Creation
● To create a fragment, the developer must either create a subclass of Fragment or a subclass of an existing subclass of Fragment
● The Fragment class has code that looks a lot like an Activity in that it contains callbacks such as onCreate(), onStart(), onPause(), & onStop()
● In many cases, converting existing activities to fragments is as simple as moving code from the activities' callback methods into the corresponding methods of fragments
Fragment Layouts
● To provide a layout for a fragment, the onCreateView() callback must be implemented
● Android system calls this method when the fragment is ready to draw its layout
● The implementation of this method must return the View root of the fragment's layout
● Fragments typically implement UI parts of the host activity
Programmatic Addition of Fragments
// getFragmentManager() is a method of the Activity class
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
// Create a fragment and use the transaction to add the fragment to the view container
SomeFragment frgmnt = new SomeFragment();
fragmentTransaction.add(R.id.view_container, frgmnt);
fragmentTransaction.commit();
Order of Multiple Fragments
● A call to commit() must be last● When multiple fragments are added to the same container, then the
order in which they are added determines the order they appear in the view hierarchy
● If there is no call to addToBackStack() in a transaction removes a fragment, the removed fragment is destroyed after the transaction is committed and the user cannot navigate back to it
Finding Fragments w/in Activity
FragmentManager fm = getFragmentManager();
SomeFragment fragment =
(SomeFragment) fm.findFragmentById(R.id.some_fragment);
Three Important States
● Resumed: fragment is visible● Paused: another activity is in the foreground and has
focus.● Stopped: fragment is not visible
Activity vs Fragment Lifecycles
source image at http://developer.android.com/guide/components/fragments.html
Rumi's Quatrains with Fragments
source code is at https://github.com/VKEDCO/RumiQuatrainFragments
Application Requirements
● Develop an application that uses fragments to display texts of several fragments by Rumi
● The application should work in two modes: landscape and portrait● In portrait mode, only one quatrain can be displayed● In landscape mode, the user can select the quatrains to display
Sample Screenshots
landscape
portrait
Application Class Contents
● RumiQuatrainMainActivity.java – main activity● QuatrainNumberListFragment.java – ListFragment associated with
main activity● QuatrainTextDisplayActivity.java – host activity for
QuatrainTextDisplayFragment.java● QuatrainTextDisplayFragment.java – fragment to display quatrain
texts● The texts of the quatrains and their numbers are in quatrains.xml
AndroidManifest.xml<application android:icon="@drawable/rumi" android:label="Rumi's Quatrains">
<activity android:name="org.vkedco.mobappdev.rumi_quatrain_fragments.RumiQuatrainMainActivity"
android:label="Rumi's Fragments">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name="org.vkedco.mobappdev.rumi_quatrain_fragments.QuatrainTextDisplayActivity"
android:label="Quatrain's Text">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
</application>
AndroidManifest.xml<application android:icon="@drawable/rumi" android:label="Rumi's Quatrains">
<activity android:name="org.vkedco.mobappdev.rumi_quatrain_fragments.RumiQuatrainMainActivity"
android:label="Rumi's Fragments">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name="org.vkedco.mobappdev.rumi_quatrain_fragments.QuatrainTextDisplayActivity"
android:label="Quatrain's Text">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
</application>
XML Layout of the Main Activity: Main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<fragment class="org.vkedco.mobappdev.rumi_quatrain_fragments.QuatrainNumberListFragment"
android:id="@+id/quatrain_numbers"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
XML Layout of the Secondary Activity: quatrain_text_display.xml
<LinearLayout>
<ScrollView android:id="@+id/scvQuatrainText"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/tvQuatrainText"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</ScrollView>
</LinearLayout>
RumiQuatrainMainActivity.javapublic class RumiQuatrainMainActivity extends Activity {
static final String LOGTAG = RumiQuatrainMainActivity.class.getSimpleName() + "_TAG";
static Resources mRes = null;
static FragmentManager mFrgmntMngr = null;
static RumiQuatrainMainActivity mThisAct = null;
public void onCreate(Bundle savedInstanceState) {
Log.d(LOGTAG, "onCreate()");
super.onCreate(savedInstanceState);
FragmentManager.enableDebugLogging(true);
setContentView(R.layout.main);
mRes = getResources();
mFrgmntMngr = getFragmentManager();
mThisAct = this;
}
Determining Device's Orientation
static boolean isInLandscapeOrientation() {
return mRes.getConfiguration().orientation
== Configuration.ORIENTATION_LANDSCAPE;
}
RumiQuatrainMainActivity.java
● The real workhorse of is displayQuatrainText(int quatrain_index)● It finds a fragment by id and replaces it with a newly created fragment● It also shows how to check the orientation● If the orientation is landscape, then two fragments are displayed● If the orientation is portrait, then a new activity is launched
Displaying Quatrain's Text in Landscape Orientation if ( isInLandscapeOrientation() ) {
// Check what fragment is shown, replace if needed.
QuatrainTextDisplayFragment qTxtFrgmnt = (QuatrainTextDisplayFragment)
mFrgmntMngr.findFragmentById(R.id.quatrain_text);
if (qTxtFrgmnt == null || qTxtFrgmnt.getDisplayedQuatrainIndex() != quatrain_index) {
// Make new fragment to show this selection.
qTxtFrgmnt = QuatrainTextDisplayFragment.newInstance(quatrain_index);
// Execute a transaction, replacing any existing
// fragment inside the frame with the new one.
FragmentTransaction frag_trans = mFrgmntMngr.beginTransaction();
frag_trans.setCustomAnimations(R.animator.bounce_in_down, R.animator.fade_out);
frag_trans.setCustomAnimations(R.animator.bounce_in_down, R.animator.slide_out_right);
frag_trans.replace(R.id.quatrain_text, qTxtFrgmnt);
frag_trans.commit();
}
Displaying Quatrain's Text in Portrait Orientation
Intent intent = new Intent();
intent.setClass(mThisAct, QuatrainTextDisplayActivity.class);
intent.putExtra(mRes.getString(R.string.quat_index_key), quatrain_index);
this.startActivity(intent);
XML Animations
Animating Bounces
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@android:interpolator/bounce"
android:valueFrom="-1200"
android:valueTo="0"
android:valueType="floatType"
android:propertyName="Y"
android:duration="2000" />
Animating Left Slides
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@android:interpolator/accelerate_decelerate"
android:valueFrom="-1200"
android:valueTo="0"
android:valueType="floatType"
android:propertyName="X"
android:duration="2000" />
Animating Right Slides
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android" android:interpolator="@android:interpolator/accelerate_decelerate" android:valueFrom="0" android:valueTo="1280" android:valueType="floatType" android:propertyName="X" android:duration="2000" />
Animating Left Slides
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@android:interpolator/accelerate_decelerate"
android:valueFrom="-1280"
android:valueTo="0"
android:valueType="floatType"
android:propertyName="X"
android:duration="2000" />
References● http://developer.android.com/guide/components/fragments.html
● S. Komatineni & D. MaClean. Pro Android 4. APRESS
● R. Meier. Pro Android 4 Application Development. WROX