Android fragment example

What is an Android Fragment?

Well as the name suggests it just a piece of something and in case of android its a piece of an Activity. Just like an activity the fragment also has a very similar life cycle onCreate(), onStart(), onStop(), onDestroy(), etc. In addition to that it has onCreateView() and onActivityCreated(). The system calls the onCreateView() when it's time for the fragment to draw its user interface for the first time. In this method you must inflate your fragment view return it. You can return null if the fragment does not provide a UI. The onActivityCreated() method is called when the fragment's activity has been created.

Why would we use a fragment?

You can create all your logic in an Activity and then manipulate the screen based on device size and orientation but the amount of code to programmatically draw views and implement all the logic based on layout and/or orientation will be make the whole project more complex than it needs to be. This is where fragments come to rescue, you can separate out the logic based on a functional entity rather than how the whole application looks to the end user. The concept is similar to the Portal technology where you create more than one portlet and put them on a given page.

The example

we are going to implement how to display a list view and a detail view displayed side by side when the user is in a landscape mode and in the case of portrait mode we just display the list and then when the user clicks on the given entry we display the detail view. The list entries in this tutorial are web URLs and actual web page is the detail view. The objective is to create the two fragments that are totaly independent and don't talk to each other which was done with the help of implementing an interface on the list activity. The activity is notified when the user select an URL and it alerts the detail fragment to updates its view. In addition to that we dynamically add and remove fragments from the activity based on the layout and the user action. So in the case of the portrait mode we only inflate the list view and then swap it out when the user clicks on the URL link whereas in the landscape mode we inflate both views the frame layouts. This example doesn't use another activity to display the detail page as some other tutorials have used, the objective is to have a simple and easy to understand tutorial that covers all the dynamics of the power of Android Fragments and how to use them effectively without complicating the matters.

Fragments in Portrait Mode

android fragment portrait mode listview
android fragment portrait mode detail view

Fragments in Landscape Mode

android fragment landscape mode

Android Manifest

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.as400samplecode"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk android:minSdkVersion="15" />
    <uses-permission android:name="android.permission.INTERNET" />

    <application
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name" 
        android:theme="@android:style/Theme.Holo.Light">>
        <activity
            android:name=".AndroidFragmentActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

String values - strings.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>

    <string name="app_name">Fragment Example</string>
    <string name="detail_heading">Web Page Detail</string>
    <string name="list_heading">Web Page Listing</string>

</resources>

Layout for Portrait mode - main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >


    <FrameLayout
        android:id="@+id/displayList"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" >

    </FrameLayout>
  
</LinearLayout>

Layout for Landscape mode - main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:baselineAligned="false"
    android:orientation="horizontal" >



    <FrameLayout
        android:id="@+id/displayList"
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_weight="2" >

    </FrameLayout>
   

   <FrameLayout
       android:id="@+id/displayDetail"
       android:layout_width="0dp"
       android:layout_height="match_parent"
       android:layout_weight="3" >

    </FrameLayout>

</LinearLayout>

Listview XML resource - list_view.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >



    <TextView
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:padding="5dp"
        android:text="@string/list_heading"
        android:textSize="20sp" />
    
    <ListView android:id="@+id/listofURLs" android:layout_width="match_parent"
  android:layout_height="wrap_content" />
    

</LinearLayout>

Listview Row Layout - url_list.xml

<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:padding="10dp"
    android:textSize="16sp" >
</TextView>

Detail Web view XML resource - detail_view.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >

    <TextView
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="@string/detail_heading" android:padding="5dp" 
        android:textSize="20sp" />

    <WebView
        android:id="@+id/pageInfo"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</LinearLayout>

Android fragment for the Webview - DetailFragment.java

package com.as400samplecode;

import android.app.Fragment;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.webkit.WebView;
import android.webkit.WebViewClient;

public class DetailFragment extends Fragment {

 String mURL = "";

 @Override
 public void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  Log.v("DetailFragment", "onCreate()");
 }

 @Override
 public void onActivityCreated(Bundle savedInstanceState) {
  super.onActivityCreated(savedInstanceState);
  Log.v("DetailFragment", "onActivityCreated()");
  if (savedInstanceState != null) {
   mURL = savedInstanceState.getString("currentURL", "");
  }
  if(!mURL.trim().equalsIgnoreCase("")){
   WebView myWebView = (WebView) getView().findViewById(R.id.pageInfo);
   myWebView.getSettings().setJavaScriptEnabled(true);
   myWebView.setWebViewClient(new MyWebViewClient());
   myWebView.loadUrl(mURL.trim());
  }
 }

 @Override
 public void onSaveInstanceState(Bundle outState) {
  super.onSaveInstanceState(outState);
  outState.putString("currentURL", mURL);
 }

 @Override
 public View onCreateView(LayoutInflater inflater, ViewGroup container,
   Bundle savedInstanceState) {
  Log.v("DetailFragment", "onCreateView()");
  View view = inflater.inflate(R.layout.detail_view, container, false);
  return view;
 }

 public void setURLContent(String URL) {
  mURL = URL;
 }

 public void updateURLContent(String URL) {
  mURL = URL;
  WebView myWebView = (WebView) getView().findViewById(R.id.pageInfo);
  myWebView.getSettings().setJavaScriptEnabled(true);
  myWebView.setWebViewClient(new MyWebViewClient());
  myWebView.loadUrl(mURL.trim());
 }
 
 private class MyWebViewClient extends WebViewClient {
     @Override
     public boolean shouldOverrideUrlLoading(WebView view, String url) {
             return false;
     }
 }
}

Android fragment for the Listview - ListFragment.java

package com.as400samplecode;

import java.util.ArrayList;
import java.util.List;

import android.app.Activity;
import android.app.Fragment;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.AdapterView.OnItemClickListener;

public class ListFragment extends Fragment {

 OnURLSelectedListener mListener;
    
 @Override
 public void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  Log.v("ListFragment", "onCreate()");
 }

 @Override
 public void onActivityCreated(Bundle savedInstanceState) {
  super.onActivityCreated(savedInstanceState);
  Log.v("ListFragment", "onActivityCreated().");
  Log.v("ListsavedInstanceState", savedInstanceState == null ? "true" : "false");
  
  //Generate list View from ArrayList
  displayListView();
  
 }

 @Override
 public View onCreateView(LayoutInflater inflater, ViewGroup container,
   Bundle savedInstanceState) {
  Log.v("ListFragment", "onCreateView()");
  Log.v("ListContainer", container == null ? "true" : "false");
  Log.v("ListsavedInstanceState", savedInstanceState == null ? "true" : "false");
  if (container == null) {
            return null;
        }
  View view = inflater.inflate(R.layout.list_view, container, false);
  return view;
 }
 
 
 // Container Activity must implement this interface
    public interface OnURLSelectedListener {
        public void onURLSelected(String URL);
    }
    
    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);
        try {
            mListener = (OnURLSelectedListener) activity;
        } catch (ClassCastException e) {
            throw new ClassCastException(activity.toString() + " must implement OnURLSelectedListener");
        }
    }
 
 private void displayListView() {

  //Array list of countries
  List<String> urlList = new ArrayList<String>();
  urlList.add("http://www.google.com");
  urlList.add("http://mail.google.com");
  urlList.add("http://maps.google.com");
  
  //create an ArrayAdaptar from the String Array
  ArrayAdapter<String> dataAdapter = new ArrayAdapter<String>(getActivity(),
    R.layout.url_list, urlList);
  ListView listView = (ListView) getView().findViewById(R.id.listofURLs);
  // Assign adapter to ListView
  listView.setAdapter(dataAdapter);
  
  //enables filtering for the contents of the given ListView
  listView.setTextFilterEnabled(true);

  listView.setOnItemClickListener(new OnItemClickListener() {
   public void onItemClick(AdapterView<?> parent, View view,
     int position, long id) {
    // Send the URL to the host activity
          mListener.onURLSelected(((TextView) view).getText().toString());
    
   }
  });
  
 }
 
}

Android activity for the application - AndroidFragmentActivity.java

package com.as400samplecode;

import com.as400samplecode.ListFragment.OnURLSelectedListener;

import android.app.Activity;
import android.app.FragmentTransaction;
import android.os.Bundle;
import android.util.Log;

public class AndroidFragmentActivity extends Activity
implements OnURLSelectedListener {

 boolean detailPage = false;

 @Override
 public void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  Log.v("AndroidFragmentActivity", "onCreate()");
  Log.v("AndroidFragmentsavedInstanceState", savedInstanceState == null ? "true" : "false");

  setContentView(R.layout.main);

  if(savedInstanceState == null) {
   FragmentTransaction ft = getFragmentManager().beginTransaction();
   ListFragment listFragment = new ListFragment();
   ft.add(R.id.displayList, listFragment, "List_Fragment");
   ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
   ft.commit();
  }

  if(findViewById(R.id.displayDetail) != null){
   detailPage = true;
   getFragmentManager().popBackStack();

   DetailFragment detailFragment = (DetailFragment) getFragmentManager().findFragmentById(R.id.displayDetail);
   if(detailFragment == null){
    FragmentTransaction ft = getFragmentManager().beginTransaction();
    detailFragment = new DetailFragment();
    ft.replace(R.id.displayDetail, detailFragment, "Detail_Fragment1");
    ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
    ft.commit();
   }
  }

 }

 
 @Override
 public void onURLSelected(String URL) {
  Log.v("AndroidFragmentActivity",URL);

  if(detailPage){
   DetailFragment detailFragment = (DetailFragment)
   getFragmentManager().findFragmentById(R.id.displayDetail);
   detailFragment.updateURLContent(URL);
  }
  else{
   DetailFragment detailFragment = new DetailFragment();
   detailFragment.setURLContent(URL);
   FragmentTransaction ft = getFragmentManager().beginTransaction();
   ft.replace(R.id.displayList, detailFragment, "Detail_Fragment2");
   ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
   ft.addToBackStack(null);
   ft.commit();
  }
 }

}

You can read more about fragments here - http://developer.android.com/guide/components/fragments.html


36 comments :

  1. I'm new to Android,
    These are code for the different files,
    could you also share the file tree?
    Thanks! these sample codes are very helpful for beginners

    ReplyDelete
  2. I don't believ this works does it? Doesn't the ListFragment require that your listview be specified with an id as from the documentation:

    "To do this, your view hierarchy must contain a ListView object with the id "@android:id/list" (or list if it's in code)"

    ReplyDelete
  3. hey

    i got an error when i implement OnURLSelectedListener, the error shows that define interface OnURLSelectedListener,change to onItemSelectedListener and somethingmore.i got error on most URL related statement.don't know what to do?

    with regards
    ajay

    ReplyDelete
  4. Love the tutorial, any chance you could provide the project zipped?

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

    ReplyDelete
  6. A quick check showed two main.xml files, and only one has a home in layout.main.xml.
    How can this possibly run like this?

    ReplyDelete
    Replies
    1. Put the other one in /res/layout-land

      Delete
    2. how i can write it ?
      setContentView(R.layout.activity_main); ??

      Delete
    3. when device is in landscape ,it will take from layout-land folder.no need to specify it.

      Delete
  7. This comment has been removed by the author.

    ReplyDelete
    Replies
    1. what u have written

      Delete
  8. awesome tutorial plz provide the project zipped my mail id is:mangalpsingh@yahoo.com

    ReplyDelete
    Replies
    1. Hey, the above code is working for anyone..

      Delete
  9. It works fine for a Tablet ,but not a Handset. Reason being that the code does not support fragment switching on a single mode. Since, we create two frames in Tab, there is a connectivity with the xml files as per the code. The code will work fine for a handset,provided there's a switching mechanism of the frames from list view to detailed view. For more details refer : http://www.vogella.com/articles/AndroidFragments/article.html and
    http://www.techrepublic.com/blog/app-builder/get-started-with-android-fragments/1050

    ReplyDelete
  10. My name is Mark.
    I am new to android.
    I need help: In which sub-directories must save the codes.
    I thank you

    ReplyDelete
  11. Nice explanation... and is there project zip file.?

    ReplyDelete
  12. To do this, your view hierarchy must contain a ListView object with the id "@android:id/list" (or list if it's in code)
    Agen Poker Online Indonesia Terpercaya

    ReplyDelete

  13. how to Android fragment use : http://www.androidinterview.com/android-fragment-tutorial-example/

    ReplyDelete
  14. đồng tâm
    game mu
    cho thuê nhà trọ
    cho thuê phòng trọ
    nhac san cuc manh
    số điện thoại tư vấn pháp luật miễn phí
    văn phòng luật
    tổng đài tư vấn pháp luật
    dịch vụ thành lập công ty trọn gói

    đáng ngờ tập hợp lại cùng một chỗ như vậy thì quả thật quá không bình thường rồi! Nếu nói là tất cả những cái này đều chỉ là trùng hợp… hừm… giờ ngay cả Ô Thiến Thiến cũng chẳng thể tin thế giới còn có cái loại trùng hợp này rồi.

    "Nếu quả người này chính là gian tế, như vậy rất có khả năng đây chính là con cá lớn nhất mà Bổ Thiên Các ta tóm được từ trước tới nay rồi!" Sở Dương âm trầm nói.

    Ô Thiến Thiến rùng mình mãnh liệt một cái, nàng cực kỳ rõ ràng ý nghĩa của từ ‘cá lớn’ mà Sở Dương nói này… Nếu đúng thật như hắn suy đoán thì đám người dính vào vụ này từ trên xuống dưới chỉ sợ ít nhất cũng phải hơn mấy trăm người đấy!

    Lại sẽ là một cảnh máu chảy thành sông nữa!

    "Sở Dương, cho dù hắn có là gian tế đi nữa, nhưng… nhưng chúng ta cũng không thể tùy tiện giết a..." Ô Thiến Thiến nói: "Người này vốn có danh tiếng quá tốt, trong dân gian của Thiết Vân uy vọng cực cao, nếu cứ tùy tiện bắt giết thì chỉ sợ sẽ khiến cả nước rung chuyển mất."

    Trong khoảng thời gian Ô Thiến Thiến đi theo Sở Dương, mỗi ngày đều tham gia phân tích quân chính dân sinh của cả Thiết Vân Quốc nên kinh nghiệm xử lý sự việc của nàng so với khi còn ở Thiên Ngoại Lâu đã vững vàng sâu sắc hơn nhiều.

    ReplyDelete
  15. I appreciate your idea here. Definitely it has a good content. Thank you for imparting more of your own thoughts. Good job!assignment help australia

    ReplyDelete
  16. Not working. Getting crashed at runtime. [Fatal Exception Main]

    ReplyDelete
  17. gud job...thanks......

    ReplyDelete
  18. Adzet is the world's leading Marketing Platform - providing marketing strategy and business development strategy to small and medium businesses worldwide

    ReplyDelete
  19. The best part about reading blogs versus mainstream content is that they dive into real-life experiences and render lessons which add value other lives. This blog not only offer an insightful viewpoint on marketing E20-357 dumps, but also delivered solutions on how to to a attain this philosophy. Great post. If you ever need online video tutorials or a platform let us know. Let’s collaborate on something soon.

    ReplyDelete
  20. This comment has been removed by the author.

    ReplyDelete
  21. This comment has been removed by the author.

    ReplyDelete
  22. Please refer to my fragments sample app:
    -Add Fragment dynamically
    -Remove Fragment dynamically
    -Replace Fragment dynamically
    -Fragment to Fragment communication via the Activity
    -Retained Fragment example which retains its state on configuration changes

    https://github.com/amitAnvay/Fragment_Examples

    ReplyDelete
  23. Pleaqse let me know if you run into anything.
    I truly enjoy reading your blog and I look forward to your new updates.

    Splash PRO

    ReplyDelete
  24. Great info. I would like more information about this, because it is very nice. Thanks for sharing : contact form | snapchat emoji

    ReplyDelete