Skip to main content

Using a list fragment with cursor adapter

All these days, I avoided using fragments. But then I realized for my this particular applications fragments are ideal. I have a master - detail list in my app.
Let us say you want to have two fragments - one is a fragment which contains a list of elements and second one expands one element of the list. Both of them share the same cursor from the activity.

Let us start with list fragment.

Do not try creating list fragment using a wizard. It unnecearrily adds too many methods and classes.

Let us start writing our own fragment like this

class MyListFragment extends ListFragment{

}

Next using code menu override option, override the following method

onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)

This method should be used for inflating the layout file for the fragment.  I have a framelayout in parent activity of this fragment with the id as container. So I will specify that for inflating. The framelayout will be the parent viewgroup for fragment. 


@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        return inflater.inflate(R.layout.listfragment,container,false);
 }

R.layout.listfragment is my layout  file which for the fragment. Here it is


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

    <ListView
        android:id="@android:id/list"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

    <TextView
        android:id="@android:id/empty"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="No items in list" />
</LinearLayout>

Note that the ids of both ListView and TextView are android ids. This is needed because we want to use listfragment methods for most of our works, instead of getting listview with the help of findviewbyid etc.

How about the adapter for the list? I am having a database cursor for my list. So I can use simple cursor adapter. The adapter should be set in onActivityCreated() method.

Where is the cursor for the adapter? Instead of trying to fetch the cursor all over again, you can access the cursor from the activity. (Make sure it is not private). Using getActivity() and typecasting it to parent activity name, you get access to parent activity. Next you access cursor from there.


@Override
    public void onActivityCreated(@Nullable Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        MyActivity act = (MyActivity) getActivity();
        mCursor = act.mCursor;
        SimpleCursorAdapter adapter = new SimpleCursorAdapter(act,
                android.R.layout.simple_list_item_1, mCursor,
                new String[]{"name"}, new int[]{android.R.id.text1}, 0);
        setListAdapter(adapter);
        }

OK. The first parameter to SimpleCursorAdapter is context. Second parameter is the layout for each row of the list. You can use android.R.layout.simple_list_item_1. Or you can write your own layout file.
 

Third parameter is cursor. And fourth and fifth are mapping of columns in cursor to views in listview.

Now how do we handle item clicks?

You can write an interface in the fragment. And when item is clicked from list, call the function of this interface. Now the parent activity must implement this interface in order to listen to itemclick of this fragment.

Let us write the interface.


package your.package.name;

public interface OnListItemSelectedListener{
    public void OnItemSelected(int position);
}

Create an instance of this interface in onActivityCreated method. Developers tutorial asks you to create call back instance in onAttach() method. I faced some difficulties. So I am writing it in onActivityCreated() method like this.

public void onActivityCreated(@Nullable Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        ........
        try {
            mCallback = (OnListItemSelectedListener) act;
        }
        catch (ClassCastException e){
            Toast.makeText(act,"Class must implement OnListItemSelectedListener",Toast.LENGTH_SHORT).show();
        }
    }

Now the thing remaining is how do we use this interface.

Override the OnListItemClick() method of ListFragment and here call the OnItemSelected method of interface.


@Override
    public void onListItemClick(ListView l, View v, int position, long id) {
        super.onListItemClick(l, v, position, id);
        if(mCallback!=null) mCallback.OnItemSelected(position);
    }

OK. Now our onclick method is ready to go to the parent activity.

Parent activity needs few lines of code.

public class MyActivity extends FragmentActivity implements OnListItemSelectedListener { 
        private MySqliteHelper mSqliteHelper;
        private int mPos;
        private MyListFragment fragment;
 
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.listact);
            mCursor=mSqliteHelper.getallrows();  
            fragment = new MyListFragment(); 
            getSupportFragmentManager().beginTransaction().add(R.id.list_container,fragment).commit(); 
        }
}

In order to use Fragments with support library, you need to extend your class from FragmentActivity.

Here is the layout file of the activity - R.layout.listact

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent"> 
  
        <FrameLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_marginLeft="5dp"
            android:layout_marginRight="5dp"
            android:id="@+id/list_container"
            /> 
</LinearLayout>


In oncreate method of  we are fetching the cursor and then creating a fragment and adding it to frame layout.

Notice that we are implementing the interface here. Android studio forces you to implement the method of the OnListItemSelectedListener interface. We complete its code.


@Override
    public void OnItemSelected(int position) {
        mPos = position;
       //do something
    }


Comments

Popular posts from this blog

Copy to clipboard

In my upcoming app, I have codes which I display. These are some times lengthy, and I want the app to be able to copy this to clipboard. Once it is in clipboard, users can paste it anywhere. So how do you copy some text from your app to clipboard. You need to use clipboard manager. Clipboard Manager This class sets and gets data for the clipboard using Clipdata objects.  You can get the object of this class using system service.  - using statement context.getSystemService(Context.CLIPBOARD_SERVICE) Example I have a dummy project with a button, onclick of which copies content to clipboard. Here is my activity file package com . hegdeapps . testapp ; import android.content.ClipData ; import android.content.ClipboardManager ; import android.support.v7.app.AppCompatActivity ; import android.os.Bundle ; import android.view.View ; import android.widget.Button ; import android.widget.TextView ; public class MainActivity extends ...

Drawables in Android - Layer drawable

Let us see how to use layer drawable. You can have two or more bitmaps on different layers to create such a drawable Using xml : You should use layer-list in your xml file to create layerdrawable. Here is layer.xml <?xml version="1.0" encoding="utf-8"?> <layer-list xmlns:android="http://schemas.android.com/apk/res/android"> <item> <bitmap android:src="@drawable/whiteicon" android:gravity="top|left"/> </item> <item> <bitmap android:src="@drawable/blueicon" android:gravity="top|left"/> </item> <item> <bitmap android:src="@drawable/redicon" android:gravity="top|left"/> </item> </layer-list> We are using three different bitmaps whiteicon.png, redicon.png and blueicon.png which are present in /res/drawable/mdpi folder. All these are of different sizes and aligned to top left. Thi...