Android User Interface Design: Working With Fragments

Android User Interface Design: Working With Fragments

Tutorial Details
  • Technology: Eclipse + Android SDK
  • Difficulty: Intermediate
  • Estimated Completion Time: 60-90 Minutes
This entry is part 10 of 21 in the series Android User Interface Design

The new Fragment API for Android, introduced in Android 3.0, allows for easier dynamic user interfaces. In this tutorial, learn how to convert a two-screen ListView to WebView workflow into a single screen workflow designed for large screens, such as those found on tablets.

Subsequent Changes to Techniques & Software

Certain aspects of applications or techniques used in this tutorial have changed since it was originally published. This might make it a little difficult to follow along. We'd recommend looking at these more recent tutorials on the same topic:

The pacing of this tutorial is going to be faster than some of our beginner tutorials; you may have to review some of the other Android tutorials on this site or even in the Android SDK reference if you are unfamiliar with any of the basic Android concepts and classes discussed in this tutorial. The final sample code that accompanies this tutorial is available for download as open-source from the Google code hosting.

Introducing Fragments

Before we get started, let’s define what a Fragment is, at a high level. A Fragment is, generally, a chunk of user interface with its own life cycle. If that sounds a lot like an Activity, that’s because it is a lot like an Activity. However, a Fragment is different from an Activity, in that a Fragment must exist within an Activity. A Fragment doesn’t have to be paired with the same Activity each time it’s instantiated, which gives it some flexibility. Also like an Activity, a Fragment need not contain any user interface.

Step 0: Getting Started

This tutorial assumes you will start where our ListView tutorial left off. You can download that code and build from there, though you will have some tasks you’ll have to do unassisted, or you can download the code for this tutorial and follow along.

Step 1: Redesigning the Screens

The following figure illustrates the existing workflow of our Mobiletuts+ article reader app (the ListView tutorial) before a Fragment design was considered and applied:

Android SDK Fragments - Figure 1

This workflow works fine on a relatively small phone screen. However, on a large screen, like the 10″ screen of the Motorola Xoom, and there’s a lot of wasted space on the ListView screen. The WebView screen looks fine, if a bit boring.

This is where Fragments come into play: on larger screens, we could provide a more effective user interface if we could display the ListView on the same screen as the WebView. When the user clicks a specific ListView element in the lefthand “pane”, the WebView on the right-hand side updates to display the appropriate content. This type of workflow is frequently used in email or document feed readers. The following figure illustrates just such a redesign:

Android SDK Fragments - Figure 2

Step 2: Converting to a Fragments-Based Design

Now that we know how the new screen workflow will be designed, we also know that the two current activities will need to be converted to fragments. We’ll do the conversion in several steps. The first step involves leaving the screens visually unchanged, but modifying each screen to use a fragment. One fragment will contain the current ListView and another will contain the WebView. Then we’ll switch to a single screen implementation, which involves modifying the messaging between the ListView and WebView activities-turned-fragments.

First, though, change the Project Build Target of your application to Android 3.0. To do this from within Eclipse, right-click on the project and choose Properties. Navigate to the Android section and check the checkbox next to Android 3.0. We’re not using any Google APIs, so the Android Open Source Project version is sufficient. Then click the OK button.

Now you’ll have access to the new APIs, including the Fragments API.

Note: In a future tutorial, we’ll talk about using the new compatibility layer to enable technologies like the Fragment API to work on earlier versions of Android. For now, though, they will require a device with Android 3.0, Honeycomb.

Step 3: Creating the Fragment Classes

Create two new Java classes to represent the two fragments: the ListView and the WebView screens. Name them TutListFragment and TutViewerFragment. TutListFragment will extend the ListFragment class and TutViewerFragment will just extend the Fragment class.

Within the TutListFragment class, we need to override two methods: onListItemClick() and onCreate(). The contents of these methods should look familiar; they match what we previously had in the TutListActivity class. This will change shortly, but not just yet. Here’s a listing of the TutListFragment class, for now:

@Override
public void onListItemClick(ListView l, View v, int position, long id) {
    String[] links = getResources().getStringArray(R.array.tut_links);
    String content = links[position];
    Intent showContent = new Intent(getActivity().getApplicationContext(),
            TutViewerActivity.class);
    showContent.setData(Uri.parse(content));
    startActivity(showContent);
}
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setListAdapter(ArrayAdapter.createFromResource(getActivity()
            .getApplicationContext(), R.array.tut_titles,
            R.layout.list_item));
}

The TutViewerFragment class is a little simpler. We use the fact that we know (for now) that the fragment is running under the same activity it used to and grab the intent data directly from within the Fragment class. Add an override method for the onCreateView() method. This methodshould now look like this:

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
        Bundle savedInstanceState) {
    Intent launchingIntent = getActivity().getIntent();
    String content = launchingIntent.getData().toString();
    WebView viewer = (WebView) inflater.inflate(R.layout.tut_view, container, false);
    viewer.loadUrl(content);
    return viewer;
}

The ability to access the activity instance directly is useful, but will create a problem later on. What if this fragment is on the screen with the list fragment? In that scenario, there will be no launching Intent to get the URL from. Similarly, in TutListFragment, we launch a new Activity directly whenever the user clicks an item in the list. What if the TutViewFragment existed within the same activity? If so, launching a new activity would make no sense.We’ll return to resolve these issues later in this tutorial.

Step 4: Adding the Fragment Layout Resources

Now create a new layout file called tutlist_fragment.xml to represent the Fragment containing the list of articles. A Fragment layout resource uses the tag and references the Fragment class you created.

<?xml version="1.0" encoding="utf-8"?>
<fragment
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:name="com.mamlambo.tutorial.tutlist.TutListFragment"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:id="@+id/tutlist_fragment">
</fragment>

Next, create a similar layout file called tutview_fragment.xml:

<?xml version="1.0" encoding="utf-8"?>
<fragment
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:name="com.mamlambo.tutorial.tutlist.TutViewerFragment"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:id="@+id/tutview_fragment">
</fragment>

Step 5: Updating the Activity Classes

The TutListActivity and TutViewerActivity classes must now be updated. The TutListActivity class has a single method, onCreate(), which should now be updated to load the appropriate Fragment layout resource you created in the previous step, like this:

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.tutlist_fragment);
}

Also, of note, the TutListActivity should inherit from the Activity class, not ListActivity.

The TutViewerActivity class requires a similar change. Its onCreate() method should now look like this:

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.tutview_fragment);
}

Step 6: Checking Your Progress

Try running the application now. You’ll note that it does exactly what it used to do. Not very exciting yet, is it? However, the entire user interface is now run using fragments. This will allow the next changes you need to make to go smoothly as we add a new layout to combine the two fragments for larger displays to show to the user on a single screen. However, as you may have noticed, the communication between fragments is handled identically to how we communicate between activities. In fact, we used the knowledge that the activity each fragment was paired with remained unchanged. This will not be the case when we have a single activity that contains and manages both fragments. Let’s fix this first.

Step 7: Changing the Communication for TutListFragment

As you learned in Step 3, launching an activity directly from the TutListFragment object doesn’t make sense any longer. The WebView UI may, in fact, be part of the same activity as the List—that’s our plan anyway for larger screens. In that case, we just want to update the URL of the WebView in the second fragment.

To make this change, we need to do several things. First, let’s make the fragments independent of the activity in which they reside. To do this, add a listener interface to the TutListFragment class, as such:

public interface OnTutSelectedListener {
    public void onTutSelected(Uri tutUri);
}

And then trigger it by updating the onListItemClickListener() method as follows:

@Override
public void onListItemClick(ListView l, View v, int position, long id) {
    String[] links = getResources().getStringArray(R.array.tut_links);
    String content = links[position];
    tutSelectedListener.onTutSelected(Uri.parse(content));
}

Next, have the TutListActivity class implement the OnTutSelectedListener interface, like this:

public class TutListActivity extends Activity implements
        TutListFragment.OnTutSelectedListener {
...
@Override
public void onTutSelected(Uri tutUri) {
    Intent showContent = new Intent(getApplicationContext(),
            TutViewerActivity.class);
    showContent.setData(tutUri);
    startActivity(showContent);
}

So now we have the functionality split up between the fragment, which handles the user interface actions, and the activity, which can be a controller, passing the data on to the next activity. We’ll modify the onTutSelected() method later to decide whether or not to launch a new Activity instance or update the existing fragment instance.

Step 8: Changing the Communication for TutViewerFragment

Now let’s move our attention to the TutViewerFragment class, which needs to be updated as well. Instead of querying the launch intent to find out which URL to load, the fragment will wait to be told what URL to load. In this way, we can update the WebView directly and not recreate the fragment with each load.

First, modify the TutViewerFragment class to contain a new method called updateUrl():

public void updateUrl(String newUrl) {
    if (viewer != null) {
        viewer.loadUrl(newUrl);
    }
}

Next, remove all functionality from the onCreateView() method, except the inflate() call. Over in the TutViewerActivity class, add the functionality back to retrieve the Intent and then call the updateUrl() method, like so:

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.tutview_fragment);
    Intent launchingIntent = getIntent();
    String content = launchingIntent.getData().toString();
    TutViewerFragment viewer = (TutViewerFragment) getFragmentManager()
            .findFragmentById(R.id.tutview_fragment);
    viewer.updateUrl(content);
}

At this point, the application behavior remains unchanged. The fragments, however, can now exist within the same Activity or separate ones without further code changes.

Step 9: Adding a Dual Fragment Layout

Now let’s create a layout with both fragments, for use in certain situations. In the layout-land folder (which you may need to create), add a copy of tutlist_fragment.xml. This will provde a different layout for landscape orientation on any landscape screen. Portrait mode will remain unchanged. Edit the file to look like the following layout with both fragments:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="horizontal">
    <fragment
        android:name="com.mamlambo.tutorial.tutlist.TutListFragment"
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:id="@+id/tutlist_fragment"
        android:layout_weight="45">
    </fragment>
    <fragment
        android:name="com.mamlambo.tutorial.tutlist.TutViewerFragment"
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:id="@+id/tutview_fragment"
        android:layout_weight="55">
    </fragment>
</LinearLayout>

This will divide the screen horizontally between both fragments.

Step 10: Adding a Dynamic Choice

Now we can add some simple logic to the application to choose between launching a new activity (the two screen workflow) and updating an existing fragment (the one screen workflow).

To do this, update the onTutSelected() method of the TutListActivity class as follows:

@Override
public void onTutSelected(String tutUrl) {
    TutViewerFragment viewer = (TutViewerFragment) getFragmentManager()
            .findFragmentById(R.id.tutview_fragment);
    if (viewer == null || !viewer.isInLayout()) {
        Intent showContent = new Intent(getApplicationContext(),
                TutViewerActivity.class);
        showContent.setData(Uri.parse(tutUrl));
        startActivity(showContent);
    } else {
        viewer.updateUrl(tutUrl);
    }
}

All this does is grab the fragment and check to see if it’s part of the existing layout for the Activity. If not, the viewer activity is launched, otherwise the existing fragment is updated instead.

Step 11: Running the Newly Fragment-Aware App

At this point, the application will now function in two different modes: portrait is unchanged, while landscape displays the ListView to the left of the WebView. There are several improvements that could be made at this point, but they are of the tweaking, optimizing, and nit-picking variety and mostly for polish. For instance, if you are in portrait WebView mode and rotate the screen, the result is still just the WebView screen. You have to press back to get to the dual view. Polishing is beyond the scope of this tutorial, but you can see how, with the judicisious use of layouts and a little bit of activity logic, you can achieve powerful but flexible screen workflows for a variety of screens and devices.

Android SDK Fragments - Tutorial 3

Conclusion

The Fragment API helps organize user interface components so that they can be reused across activities. In this way, an application can dynamically adjust its workflow and user interfaces with relatively little coding overhead. You’ve also seen that an application that builds upon fragments is easier to reorganize. Even better, just about any application can leverage fragments now that they are available via a compatibility library provided by Google that is compatible as far back as Android 1.6.
Now go out and fragment your apps user interface and make awesome user interfaces for every screen size and shape!

About the Authors

Mobile developers Lauren Darcey and Shane Conder have coauthored several books on Android development: an in-depth programming book entitled Android Wireless Application Development and Sams Teach Yourself Android Application Development in 24 Hours. When not writing, they spend their time developing mobile software at their company and providing consulting services. They can be reached at via email to androidwirelessdev+mt@gmail.com, via their blog at androidbook.blogspot.com, and on Twitter @androidwireless.

Need More Help Writing Android Apps? Check out our Latest Books and Resources!

Buy Android Wireless Application Development, 2nd Edition  Buy Sam's Teach Yourself Android Application Development in 24 Hours  Mamlambo code at Code Canyon

Series Navigation«Android User Interface Design: Building a ListView ApplicationAndroid User Interface Design: Building Application Preference Screens»

Note: Want to add some source code? Type <pre><code> before it and </code></pre> after it. Find out more
  • Matt

    I’ve got this working with the AVD up to step 7.

    The one line that Eclispe complains about is:
    tutSelectedListener.onTutSelected(Uri.parse(content));

    It seems as if this is calling the method in TutListActivity, but if I change tutSelectedListener to TutListActivity it complains I’m trying to call a non-static method and if I make onTutSelected a static methods it breaks the interface. Is tutSelectedListener making reference to an object that isn’t documented. The link to the Google Code hosting only contains the starting code and not the final code.

    Any help would be greatly appreciated.

    Also the I think there is some crossed types in step 10
    public void onTutSelected(String tutUrl) {
    should be
    public void onTutSelected(Uri tutUrl) {

    • http://androidbook.blogspot.com/ Shane Conder & Lauren Darcey
      Author

      The full source code is now available at the Google code site. I apologize for the delay in uploading it.

      Step 7 has an error; the Url is passed as a String to onTutSelected, as shown in step 10. This was a late change and led to a copy/paste error earlier. This saved a couple of conversions.

      More specifics:

      Make sure to define the interface in the TutListFragement, as shown in the first code block.

      Next, make sure that TutListActivity implements TutListFragment.OnTutsSelectedListener (the highlighted line in the 3rd code black of Step 7).

      The code download — or viewer (http://j.mp/eu0qP1) — should clear things up if this doesn’t make sense.

      If you have further questions, just let us know here.

  • Leo

    Ok heres your solution to the missing info in step7… Finally figured it out (still learning myself)

    You can’t call a static method using a no-static call so… you need to istantiate your interface. Problem is that interfaces can’t de instantiated by definition. The solution is to instantiate whatever implements your interface in this case TutListActivity.

    Your code is missing this

    OnTutSelectedListener tutSelectedListener = new TutListActivity();

    It is obviously missing though….

    • http://androidbook.blogspot.com/ Shane Conder & Lauren Darcey
      Author

      @Leo:

      Not exactly. If you do that, you won’t be calling the right instance of the Activity.

      But I do finally see what I missed in Step 7.

      In the TutListFragment, add a private member variable:

      private OnTutSelectedListener tutSelectedListener;

      Then override onAttach() (within TutListFragment):

      @Override
      public void onAttach(Activity activity) {
      super.onAttach(activity);
      try {
      tutSelectedListener = (OnTutSelectedListener) activity;
      } catch (ClassCastException e) {
      throw new ClassCastException(activity.toString()
      + ” must implement OnTutSelectedListener”);
      }
      }

      Sorry about this missing piece…

      • mlt

        Can we just cast the result of getActivity() instead of overriding onAttach() ?

  • Saketkumar Srivastav

    When I run the app on Android 3.0 emulator it just dies off. This is the Log. Please help to run it successfully.

    03-28 14:03:29.212: ERROR/AndroidRuntime(625): FATAL EXCEPTION: main
    03-28 14:03:29.212: ERROR/AndroidRuntime(625): android.view.InflateException: Binary XML file line #3: Error inflating class fragment
    03-28 14:03:29.212: ERROR/AndroidRuntime(625): at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:581)
    03-28 14:03:29.212: ERROR/AndroidRuntime(625): at android.view.LayoutInflater.inflate(LayoutInflater.java:386)
    03-28 14:03:29.212: ERROR/AndroidRuntime(625): at android.view.LayoutInflater.inflate(LayoutInflater.java:320)
    03-28 14:03:29.212: ERROR/AndroidRuntime(625): at android.widget.ArrayAdapter.createViewFromResource(ArrayAdapter.java:332)
    03-28 14:03:29.212: ERROR/AndroidRuntime(625): at android.widget.ArrayAdapter.getView(ArrayAdapter.java:323)
    03-28 14:03:29.212: ERROR/AndroidRuntime(625): at android.widget.AbsListView.obtainView(AbsListView.java:1430)
    03-28 14:03:29.212: ERROR/AndroidRuntime(625): at android.widget.ListView.makeAndAddView(ListView.java:1745)
    03-28 14:03:29.212: ERROR/AndroidRuntime(625): at android.widget.ListView.fillDown(ListView.java:670)
    03-28 14:03:29.212: ERROR/AndroidRuntime(625): at android.widget.ListView.fillFromTop(ListView.java:727)
    03-28 14:03:29.212: ERROR/AndroidRuntime(625): at android.widget.ListView.layoutChildren(ListView.java:1598)
    03-28 14:03:29.212: ERROR/AndroidRuntime(625): at android.widget.AbsListView.onLayout(AbsListView.java:1260)
    03-28 14:03:29.212: ERROR/AndroidRuntime(625): at android.view.View.layout(View.java:7175)
    03-28 14:03:29.212: ERROR/AndroidRuntime(625): at android.widget.FrameLayout.onLayout(FrameLayout.java:338)
    03-28 14:03:29.212: ERROR/AndroidRuntime(625): at android.view.View.layout(View.java:7175)
    03-28 14:03:29.212: ERROR/AndroidRuntime(625): at android.widget.FrameLayout.onLayout(FrameLayout.java:338)
    03-28 14:03:29.212: ERROR/AndroidRuntime(625): at android.view.View.layout(View.java:7175)
    03-28 14:03:29.212: ERROR/AndroidRuntime(625): at android.widget.FrameLayout.onLayout(FrameLayout.java:338)
    03-28 14:03:29.212: ERROR/AndroidRuntime(625): at android.view.View.layout(View.java:7175)
    03-28 14:03:29.212: ERROR/AndroidRuntime(625): at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1254)
    03-28 14:03:29.212: ERROR/AndroidRuntime(625): at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1130)
    03-28 14:03:29.212: ERROR/AndroidRuntime(625): at android.widget.LinearLayout.onLayout(LinearLayout.java:1047)
    03-28 14:03:29.212: ERROR/AndroidRuntime(625): at android.view.View.layout(View.java:7175)
    03-28 14:03:29.212: ERROR/AndroidRuntime(625): at android.widget.FrameLayout.onLayout(FrameLayout.java:338)
    03-28 14:03:29.212: ERROR/AndroidRuntime(625): at android.view.View.layout(View.java:7175)
    03-28 14:03:29.212: ERROR/AndroidRuntime(625): at android.view.ViewRoot.performTraversals(ViewRoot.java:1140)
    03-28 14:03:29.212: ERROR/AndroidRuntime(625): at android.view.ViewRoot.handleMessage(ViewRoot.java:1859)
    03-28 14:03:29.212: ERROR/AndroidRuntime(625): at android.os.Handler.dispatchMessage(Handler.java:99)
    03-28 14:03:29.212: ERROR/AndroidRuntime(625): at android.os.Looper.loop(Looper.java:123)
    03-28 14:03:29.212: ERROR/AndroidRuntime(625): at android.app.ActivityThread.main(ActivityThread.java:3683)
    03-28 14:03:29.212: ERROR/AndroidRuntime(625): at java.lang.reflect.Method.invokeNative(Native Method)
    03-28 14:03:29.212: ERROR/AndroidRuntime(625): at java.lang.reflect.Method.invoke(Method.java:507)
    03-28 14:03:29.212: ERROR/AndroidRuntime(625): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:839)
    03-28 14:03:29.212: ERROR/AndroidRuntime(625): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:597)
    03-28 14:03:29.212: ERROR/AndroidRuntime(625): at dalvik.system.NativeStart.main(Native Method)
    03-28 14:03:29.212: ERROR/AndroidRuntime(625): Caused by: java.lang.ClassNotFoundException: android.view.fragment in loader dalvik.system.PathClassLoader[/data/app/com.android.saket.fragments-1.apk]
    03-28 14:03:29.212: ERROR/AndroidRuntime(625): at dalvik.system.PathClassLoader.findClass(PathClassLoader.java:240)
    03-28 14:03:29.212: ERROR/AndroidRuntime(625): at java.lang.ClassLoader.loadClass(ClassLoader.java:551)
    03-28 14:03:29.212: ERROR/AndroidRuntime(625): at java.lang.ClassLoader.loadClass(ClassLoader.java:511)
    03-28 14:03:29.212: ERROR/AndroidRuntime(625): at android.view.LayoutInflater.createView(LayoutInflater.java:471)
    03-28 14:03:29.212: ERROR/AndroidRuntime(625): at android.view.LayoutInflater.onCreateView(LayoutInflater.java:549)
    03-28 14:03:29.212: ERROR/AndroidRuntime(625): at com.android.internal.policy.impl.PhoneLayoutInflater.onCreateView(PhoneLayoutInflater.java:66)
    03-28 14:03:29.212: ERROR/AndroidRuntime(625): at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:568)
    03-28 14:03:29.212: ERROR/AndroidRuntime(625): … 33 more

    • http://bartinger.at Bartinger

      Did you ever heard something about pastbin??

    • St.Ryder

      Make sure your Activity extends FragmentActivity.

    • jose de jesus

      I have the same error

      android.view.InflateException: Binary XML file line #2: Error inflating class fragment

      Please help me.

    • bonehead

      I had the same problem. My mistake was having the wrong android:name in tutlist_fragment.xml

      <fragment
      xmlns:android="http://schemas.android.com/apk/res/android&quot;
      android:name="com.mamlambo.tutorial.tutlist.TutListFragment"

  • http://dev.saddacrackers.com John Cardwell

    Keeps crashing in emulator. Any known issues using the emulator?

  • Ajeet

    Hi,

    Thank you for submitting such a useful resource on Android Fragments, I have gone through each line of your article, It’s really interesting! But I am little confused

    about this article, that in TutListFragment class your are adding interface,

    public interface OnTutSelectedListener {
        public void onTutSelected(Uri tutUri);
    }

    Here, onTutSelected method taking Uri as parameter, ok it’s fine but when I am looking into onTutSelected() method of the TutListActivity class, this method is taking

    a String type parameter, which is not matching as mentioned within interface,

    @Override
    public void onTutSelected(String tutUrl) {
    TutViewerFragment viewer = (TutViewerFragment) getFragmentManager()
    .findFragmentById(R.id.tutview_fragment);

    if (viewer == null || !viewer.isInLayout()) {
    Intent showContent = new Intent(getApplicationContext(), TutViewerActivity.class);
    showContent.setData(Uri.parse(tutUrl));
    startActivity(showContent);
    } else {
    viewer.updateUrl(tutUrl);
    }
    }

    Also when I am considering about updateUrl method within TutViewerFragment class:

    public void updateUrl(String newUrl) {
    if (viewer != null) {
    viewer.loadUrl(newUrl);
    }
    }

    the upDateUrl method taking URL as a String type, ok it’s fine, but within override method onTutSelected:

    showContent.setData(Uri.parse(tutUrl));

    setData taking Uri.parseUrl(tutUrl) as parameter of type Uri, which is also correct, but you are passing String type data as a parameter in onTutSelected() method of

    the TutListActivity class

    I am doing this it flush me errors, do I have to following modification:

    1. Change parameter type as Uri instead of String type in onTutSelected() method of the TutListActivity class
    2. And then converting tutUrl to string as such:

    viewer.updateUrl(tutUrl.toSring());

    And finally modified the code and now out of error, but when excuting this program it throwing exception.

    Please tell me the solution.

    Thanks
    Ajeet

    • giroro99

      I really feel the interface is strange.

      so I read the android fragment sdk and modify the code–

      in TutViewerActivity just remove interface section, just use Fragment to find viewer fragment and call it’s updateUrl;

      public class TutViewerActivity extends Activity{
      @Override
      protected void onCreate(Bundle savedInstanceState) {
      // TODO Auto-generated method stub
      super.onCreate(savedInstanceState);
      setContentView(R.layout.tutviewer_fragment);
      Intent launchingIntent = getIntent();
      String content = launchingIntent.getData().toString();
      TutViewerFragment viewer=(TutViewerFragment)getFragmentManager().findFragmentById(R.id.tutViewer_fragment);
      viewer.updateUrl(content);
      }
      }

      and of couse modify all the code which use interface.

  • giroro99

    always a null point exception in this line

    tutSelectedListener.onTutSelected(Uri.parse(content));

    05-21 00:09:33.720: ERROR/AndroidRuntime(968): at com.yesmobi.Fragments.TutListFragment.onListItemClick(TutListFragment.java:29)

  • Steve Aniston

    I can only get this to run in compatibility mode and the source code is with support jar v4.

    If I try to run it in normal SDK 11 mode there appear to be issues ( a lot of them!).

  • Steve Aniston

    Sorry, forget that last comment I was looking at wrong tut version.

  • http://xcmeathead.com Rich

    PLEASE could you update this tutorial? Can’t seem to fix it where it’s gone wrong. I’ve been really enjoying working through this series, but don’t really want to start the next one without completing this first.

  • http://androidphone-tips.blogspot.com/ Android Phone Tips

    i think this is have to know for all android user, i will call my friend for this.

  • http://android-pro.blogspot.com Mina Samy

    I’m sorry to tell you this, but this tutorial is so bad, not the quality we’re used to from this site

    • Eduardo

      I agree with you completely….

  • Karoly Holczhauser

    Hello!

    So, if I need to write an app which have different gui on phone and tablet, shall I use fragments? The phones has 2.1 , 2.2,2.3 sdk and the tablets have 3.0.

    Cheers

  • Josh

    I second Mina, this tutorial is incomplete and has too many errors.

  • Martin

    It’s a shame that this tutorial is so plagued with errors and omissions because there is so very little information/help on Fragments elsewhere. The authors had a great opportunity to help change that, but failed… even with that being said, it’s not too late.

    My recommendation is to rewrite this tutorial rather than direct readers to code. I don’t have the time nor knowledge to reverse-engineer the code; it’d benefit me a lot more if I were guided the code, step-by-step.

    This is my first visit to this site. Because others have said great things about the other tutorials and at the same time appropriately bashed this tutorial, I’ll take try them out.

  • James Gilchrist

    So far I have learned a lot through this series of tutorials. However, little issues are littered everywhere, which does not say much about a tutorial (it’s hard to sift through peoples mistakes when you are trying to learn the ins and outs of the language). I’m not here to debug code. Given that there are errors in this tutorial, like everyone else I too am having trouble.

    1. In TutListActivity.java I try to @Override the onTutSelected, but it says “The method onTutSelected(String) of type TutsListActivity must override a superclass method” and suggests that I remove the @Override. Why is this?

    I removed the label and am wondering if removing it may have caused my errors to come.

    2. Upon running the application (I have triple checked that my code is the same as in the tutorial except for the @Override as mentioned above), the program crashes immediately with the following error in the emulator: “The application MT-List (process com.mtlist) has stopped unexpectedly. Please try again.”

    Here’s the debug log:

    http://pastebin.com/embed_js.php?i=vkrs3ACm

    I would really like to continue with this tutorial, but it doesn’t make sense to continue if the code doesn’t work. Please help me.

  • martin

    hi,

    thanks for the awesome tutorial!

    i have on question. when i am in landscape mode clicking on a list item. the webview becomes full screen and hides the list. can you tell me what’s the reason for this behaviour ???

    cheers from austria,
    martin

    • http://euandroid.com.br Tsuharesu

      Verifiy this code

      if (viewer == null || !viewer.isInLayout()) {
      Intent showContent = new Intent(getApplicationContext(),
      TutViewerActivity.class);
      showContent.setData(Uri.parse(tutUrl));
      startActivity(showContent);
      } else {
      viewer.updateUrl(tutUrl);
      }

      It must have ==, mine was != so everytime it was creating a new one =P

  • Alex

    Hi,

    there is only one thing missing to avoid the NullPointerException in line

    tutSelectedListener.onTutSelected(Uri.parse(content));

    In TutListFragment.java you have to add the method:

    @Override
    public void onAttach(Activity activity) {
    super.onAttach(activity);
    try {
    tutSelectedListener = (OnTutSelectedListener) activity;
    } catch (ClassCastException e) {
    throw new ClassCastException(activity.toString()
    + ” must implement OnTutSelectedListener”);
    }
    }

    After that the NullPointerException is gone and all work fine. The only thing is, that the app only works in landscape mode.

    Regards

  • garrymoore

    hi to all mobile.tutsplus.comers this is my frst post and thought i would say hi –
    thank yous speak soon
    g moore

  • Nitin

    WOW…luvd dis…one of the best examples of fragments Ive seen……..plus beautifully structured…LuV iT!

  • Eduard

    I agree with some of what others have said. The tutorial starts out looking as though it will really help with understanding some key implementations of the Android platform but falls pitifully short of the mark simply because of all the build and implementation errors.

    Frankly although I have only been using (or struggling with Android a couple of years) I would be completely embarrassed to has such a promising enterprise go so complete bad.

    How can you learn, expand and grow your knowledge when you have to spend so much time debugging somebody else’s code that supposed to be right from the start.

    If you start with a poor example how can you gain knowledge from that. You are just building on top of a poor example.

    It’s much like the blind leading the cripple and crazy……

  • Gabriel

    What if i want to make 2 ListFragments Instead of 1 listfragment and 1 webview? i’m trying to make an app that shows a list of categories and when i click on one of them, shows me another listfragment with the sub-categories of the one i clicked… this is a good approach but i can’t figure how to bend it to two listfragments

  • elisa

    And I thought I was the only one having trouble with the tutorial… had a lot of trouble because when I try to set my SDK to 3.0 on project properties, it doesn’t save, and keeps using Google APIs. Had a lot of trouble with this and just decided to DL the supplied code.

  • http://www.the-zet.com Rafal

    Finally after some struggling it works. One needs a lot of patience with so buggy tutorial. Up to 7. everything is perfect and then author(s) assume that we sit in his/her head I know all tiny devilish details ;)

    To author(s):
    - When you write you change some file, it would help a great deal if you would put small label with file name under/over snippet in slightly different style (italic f.ex)
    - When you make some class wide change, it doesn’t hurt to include whole class or just patches to it, like where I am suppose to “selectedListener” instance from??????

    I know writing tuts is pretty difficult and nasty task, but it is really rewarding when such tut can be understood by total beginner.

  • Jonathan

    Worst tutorial ever! Tonnes of holes

  • Shahzad Imam

    Really the worst approach……will confuse a newbie

  • chi

    this tutorial sux… it took 1 hour of my precious life. worst fragment tutorial ever. where can i rate this down`??

  • jhonny

    For those of you complaining: it takes 5 minutes to see through the source code to fill in the missing holes from this tutorial. Show a little more respect and support.

  • MeAndroid

    I have been trying to change the webview fragment to an imageview fragment, but i can not make it work.

    Does anyone know how to fix this….

  • iamdroid

    Hi Shane/Lauren,

    Thanks for this tutorial, it really help those of us that are just starting out with android. I have your code working but have a question in regards to loading the webview. In the links I am using to load the webview there is a small lag time for the web page to finish loading. How can I display a progress dialog to the user that displays “Loading…” I have tried putting the ProgressDialog in the view fragment but it never displays. How you you go about adding the “Loading” dialog?

  • Elezabeth

    It really helped….
    Thank you so much.

  • Droid

    Can someone point me to a tutorial like this, but where on screen rotation, I don’t go back to the list, but show the details activity with the data (If data is shown already)? Also if I press back in portrait an re- rotate to landscape, there should be no data shown? At least, that is what I would expect as a user, right?

    Been trying for days now on such an layout where the data state is kept :/

  • Maxrunner

    How do you use all this logic under a fragment activity that has tabs???imagine one tab is supposed to do all this?All the tutorials i’ve seen regarding tabs, use tabs as fragments. not fragmentactivities…

  • nelt

    i don’t get it i have the error in onTutSelected methode with @Override else it not display the content (got a white page)

  • washita

    hi
    thanks to posted artical
    i wan’t dowload source code, can you share link it
    thanks again

  • Douglass

    It’s a very good tutorial. It helps me get hold of Fragment class with a very comprehensive and clear way. Thanks Shane Conder & Lauren Darcey!

  • sujith

    worst Tutorial spoils Time

  • Mikko

    Nice tutorial, thank you.

    I encountered some problems, but I managed to solve them (I used 3.0 emulator and sdk 18):

    In step 6 I got lots of errors and for me problem was that I ran code in xml editing screen. Run your code in .java file (be editin .java, not .xml when you hit run button).

    This might be know by most, but for me it was new and made me some frustration.

  • http://androidtrainningcenter.blogspot.in Sameer

    It seems so easy to interact with fragment after reading your tutorial i have also taken a step to in the direction of helping other. please visit my blog and give me a feedback androidtrainningcenter.blogspot.in

  • http://lemonkoala.com Lem Lordje Ko

    How about this ((OnTutSelectedListener) this).onTutSelected(Uri.parse(content)); ?

  • http://www.facebook.com/maritova Daniel Andersen

    You need to go through and update this tutorial to match the actual working code. Considering the large number of tutorials on this site that are built from this line of projects, it’s pretty embarrassing that the first steps of MT-List are full of errors. A student should be able to follow the tutorials each step of the way to build the solution, not rely on looking at a completed solution that differs from the tutorial. To do so defeats the purpose of having tutorials for doing active learning.

  • Michael Mossman

    Maybe I’m a bit strange but, having just fallen over the tutSelectedListener bug, I have to disagree with most of the rants expressed. I actually find that I learn more from my own (and other people’s) mistakes than I do from all the perfectly expressed solutions. These errors make me really go into the code, rather than just copying like an automaton. While not condoning mistakes in tutorials, can I ask that we are not quite so hard on the tutor and just be grateful that they put themselves out in the first place.

  • http://www.facebook.com/wilsonbalderrama Wilson Raul Balderrama Gomez

    Thanks Shane Conder & Lauren Darcey for the tutorial I really enjoyed and learned about Fragments :).

    But there is one thing that would say that is you need to update the tutorial about the Step 7 because in that step the tutSelectedListener variable is not being setting up, I know that in the comments the solution is there for this problem but I think that I would be very clear and helpful for new readers to fix the issue from the source.

  • Jakob Harteg

    Horrible tutorial, filled with bugs and errors don’t waste your time, still appreciate the time the authors spend on this, but just to bad it didn’t come out very well.

  • Vasanth

    Thanks for your good tutorial.
    Faced some problem in step 7 but i corrected it.
    it could be nice if you give link to download this app.

  • Giancarlo Leonio

    Thank you for this very helpful tutorial! I compiled a list of some top resources on using fragments to build user interfaces in Android applications. I included your tutorial. Check it out out/ feel free to share. http://www.verious.com/board/Giancarlo-Leonio/android-sdk-using-fragments/ Hope other developers find this useful too. :)

  • Dwivedi Ji

    I have downloaded the code provided by this link – https://code.google.com/p/android-mtlist-tutorial/source/checkout , but it is giving me a class not found exception.

    Here is my LOGCAT output

    : FATAL EXCEPTION: main

    : java.lang.RuntimeException: Unable to instantiate activity ComponentInfo{com.mamlambo.tutorial.tutlist/com.mamlambo.tutorial.tutlist.TutListActivity}: java.lang.ClassNotFoundException: Didn’t find class “com.mamlambo.tutorial.tutlist.TutListActivity” on path: /data/app/com.mamlambo.tutorial.tutlist-2.apk

    : at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2106)
    : at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2230)
    : at android.app.ActivityThread.access$600(ActivityThread.java:141)
    : at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1234)
    : at android.os.Handler.dispatchMessage(Handler.java:99)
    : at android.os.Looper.loop(Looper.java:137)
    : at android.app.ActivityThread.main(ActivityThread.java:5039)
    : at java.lang.reflect.Method.invokeNative(Native Method)
    : at java.lang.reflect.Method.invoke(Method.java:511)
    : at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:793)
    : at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:560)
    : at dalvik.system.NativeStart.main(Native Method)
    : Caused by: java.lang.ClassNotFoundException: Didn’t find class “com.mamlambo.tutorial.tutlist.TutListActivity” on path: /data/app/com.mamlambo.tutorial.tutlist-2.apk
    : at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:65)
    : at java.lang.ClassLoader.loadClass(ClassLoader.java:501)
    : at java.lang.ClassLoader.loadClass(ClassLoader.java:461)
    : at android.app.Instrumentation.newActivity(Instrumentation.java:1054)
    : at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2097)
    : … 11 more

    • D Tim Cummings

      I got this error also. I created a new project and copied all files across. Then I fixed AndroidManifest.xml setting android:targetSdkVersion=”17″ and putting . in front of TutViewerActivity in
      <activity android:name=".TutViewerActivity"
      and it worked fine.

  • Aditya

    I got the aha moment about fragments when I read this post. Thank you