Tutorial Details
- Technology: Eclipse + Android SDK
- Difficulty: Intermediate
- Estimated Completion Time: 60-90 Minutes
- Android User Interface Design: Layout Basics
- Android User Interface Design: Basic Buttons
- Android User Interface Design: Linear Layouts
- Android UI Fundamentals Challenge: LinearLayout
- Android User Interface Design: Relative Layouts
- Android UI Fundamentals Challenge: RelativeLayout
- Android User Interface Design: Table Layouts
- Android User Interface Design: Frame Layouts
- Android User Interface Design: Building a ListView Application
- Android User Interface Design: Working With Fragments
- Android User Interface Design: Building Application Preference Screens
- Android User Interface Design: Basic Text Controls
- Android User Interface Design: Basic Image Controls
- Android User Interface Design: Working With Dialogs
- Android User Interface Design: Working With Date Picker Dialogs
- Android User Interface Design: Password Confirmation
- Android User Interface Design: The Basics of Control Focus Order
- Android User Interface Design: Radio Buttons
- Android User Interface Design: Horizontal View Paging
- Android User Interface Design: Icon Design
- Android User Interface Design: Creating a Numeric Keypad with GridLayout
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.
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:
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:
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.
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.






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) {
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.
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….
@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…
Can we just cast the result of getActivity() instead of overriding onAttach() ?
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
Did you ever heard something about pastbin??
Make sure your Activity extends FragmentActivity.
Keeps crashing in emulator. Any known issues using the emulator?
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
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.
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)
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!).
Sorry, forget that last comment I was looking at wrong tut version.
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.
i think this is have to know for all android user, i will call my friend for this.
I’m sorry to tell you this, but this tutorial is so bad, not the quality we’re used to from this site
I agree with you completely….
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
I second Mina, this tutorial is incomplete and has too many errors.
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.
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.
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
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
hi to all mobile.tutsplus.comers this is my frst post and thought i would say hi –
thank yous speak soon
g moore
WOW…luvd dis…one of the best examples of fragments Ive seen……..plus beautifully structured…LuV iT!
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……
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
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.
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.