Monday, June 4, 2012

Asynchronous tasks using AsyncTask

After SDK 1.5, it was made available an API for executing asynchronous tasks in Android, without worrying with threads and manners to access the UI. For that, one must use AsyncTasks. Here it is provided a simple example of how to proper use this API.

The mechanims to execute this API is the following:
  1. Create a class which extends AsyncTask.
  2. Fill in the generic types available as generics in the class for:
    1. the task execution array parameters 
    2. progress array parameters
    3. result array parameters
  3. Implement the method doInBackground(Parameters... parameters). This method must execute the job which is supposed to be quite demanding.
  4. Optionally, on can implement methods for: 
    1. cancelling the task - onCancelled(...)
    2. executing tasks before the demanding task - onPreExecute(...)
    3. reporting progress - onProgressUpdate(...)
    4. execute activities after the demanding task is finished - onPostExecute(...).
Below is displayed two sets of codes: the first one shows the layout xml and the second one the Activity which is implemented using  AsyncTasks.

Android Layout XML

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    >
<TextView 
    android:id="@+id/txtMessage"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:text="@string/hello"
    />


<ProgressBar
    android:id="@+id/progressBar"
    style="?android:attr/progressBarStyleHorizontal"
    android:layout_width="304dp"
    android:layout_height="wrap_content" />


<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="horizontal" >


    <Button
        android:id="@+id/btnRestart"
        android:onClick="restartOnclick"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Restart" />


    <Button
        android:id="@+id/btnCancel"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:onClick="cancelOnclick"
        android:text="Cancel" />


</LinearLayout>


</LinearLayout>

Activity Implementation

package com.asynctask;


import java.text.MessageFormat;


import android.app.Activity;
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.ProgressBar;
import android.widget.TextView;


public class MainActivity extends Activity {
    private Button btnRestart;
    private Button btnCancel = null;
    private TextView txtMessage =  null;
    private ProgressBar mProgressBar =  null;
    private HugeWork task = null;
    private static final int MAX_PROGRESS = 10;


    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
       
        btnRestart = (Button) findViewById(R.id.btnRestart);
        btnCancel = (Button) findViewById(R.id.btnCancel);
        txtMessage = (TextView) findViewById(R.id.txtMessage);
        mProgressBar = (ProgressBar) findViewById(R.id.progressBar);
       
        // set an arbitrary max value for the progress bar
        mProgressBar.setMax(MAX_PROGRESS);
        // start the async task
        start();
    }
   
    // Cancel the async task and handle buttons enablement. Note that
    // the Cancel button is disabled because the task is finished and the
    // restart button is enabled so one can execute the process again.
    //
    // this is the listener for the Cancel Button.
    public void cancelOnclick(View v) {
        task.cancel(true);
        btnCancel.setEnabled(false);
        btnRestart.setEnabled(true);
    }
   
    // Restart the process execution. This is the listener to the Restart button.
    public void restartOnclick(View v) {
        start();
    }


    // Here we start the big task. For that, we reset the progress bar, set the
    // cancel button to be enable so one can stop the operation at any time and
    // finally we disable the restart button because the task is on-going.
    private void start() {
        // instantiate a new async task
        task = new HugeWork();
        // start async task setting the progress to zero
        task.execute(0);
        // reset progress
        mProgressBar.setProgress(0);
        // handle buttons
        btnCancel.setEnabled(true);
        btnRestart.setEnabled(false);
    }
   
    // execute the hard will which will take a lot of time. For our example,
    // 1 second.
    private void executeHardWork() {
        try {
            Thread.sleep(1000);
        }
         catch (InterruptedException e) {
            e.printStackTrace();
        }
    }


    // This class implements the methods for an async task to be executed
    // The only required method is the doInBackground(Params... params). This
    // method execute the big job in background. The other methods are not
    // required but they are implemented here so you can better understand how
    // tye work.
    //
    // Note that this class has three generic types assigned to Integer. These
    // types represents the arguments of the implemented methods.
    //
    // The first one, is passed when the async task is executed. It is an array
    // of necessary elements to be passed for the async task to be executed, in
    // case there is a need to do so. This parameter is used in the method doInBackground(...).
    //
    // The second parameter is eh type used for progress. Thus, when onProgressUpdate(...) is called,
    // the parameters for this methods are of the type of this second parameter.
    //
    // The third parameter is used for when the task is complete. Note that this parameter is the
    // return type of the method doInBackground(...) and the parameter of the methods onPostExecute(...)
    // and onCancelled(...).
    class HugeWork extends AsyncTask<Integer, Integer, Integer> {


        // Method executed before the async task start. All things needed to be
        // setup before the async task must be done here. In this example we
        // simply display a message.
        @Override
        protected void onPreExecute() {
            txtMessage.setText("Executing async task...");
            super.onPreExecute();
        }
       
        // Here is where all the hard work is done. We simulate it by executing
        // a sleep for 1 second, 10 times. Each time the sleep is performed, we update
        // our progress in the method publishProgress(...). This method executes the
        // overridden method onProgressUpdate(...) which updates the progress.
        @Override
        protected Integer doInBackground(Integer... params) {
           
            // get the initial parameters. For us, this is the initial bar progress = 0
            int progress = ((Integer[])params)[0];
           
            do {
               
                // only keep going in case the task was not cancelled
                if (!this.isCancelled()) {
                    // execute hard work - sleep
                    executeHardWork();
                }
                else {
                    // in case the task was cancelled, break the loop
                    // and finish this task
                    break;
                }
                   
                // upgrade progress
                progress++;
                publishProgress(progress);
            } while (progress <= MAX_PROGRESS);
           
            return progress;
        }


        // Every time the progress is informed, we update the progress bar
        @Override
        protected void onProgressUpdate(Integer... values) {
            int progress = ((Integer[])values)[0];
            mProgressBar.setProgress(progress);
            super.onProgressUpdate(values);
        }
       
        // If the cancellation occurs, set the message informing so
        @Override
        protected void onCancelled(Integer result) {
            txtMessage.setText(MessageFormat.format("Async task has been cancelled at {0} seconds.", result - 1));
            super.onCancelled(result);
        }
       
        // Method executed after the task is finished. If the task is cancelled this method is not
        // called. Here we display a finishing message and arrange the buttons.
        @Override
        protected void onPostExecute(Integer result) {
            txtMessage.setText(MessageFormat.format("Async task execution finished in {0} seconds.", result - 1));
            btnCancel.setEnabled(false);
            btnRestart.setEnabled(true);
            super.onPostExecute(result);
        }
    }


   
}


One interesting discussion is the reason for AsyncTasks. Imagine you have a task which takes a long time, for instance 3 seconds. If you simply execute this task without any UI treatment, the mobile window will freeze and the user will probably think the application has crashed. To avoid so, the UI should display a message, alternatively with a progress bar, stating the application is running but it is waiting for a task to finish. This increases the User Experience and makes your application much more trustworthy.

The code above does that. It executes a simulated long task (10 seconds) informing the user of the progress. Note that the AsyncTasks provides a nice way of treating the problem because it emcapsulates the the asynchronous task execution. Morover, using this API one does not have to worry where is the correct place to treat UI events, because one is made available - onProgressUpdate(...).

Now, the code will be explained in more details. See the code below:



       // Here is where all the hard work is done. We simulate it by executing
        // a sleep for 1 second, 10 times. Each time the sleep is performed, we update
        // our progress in the method publishProgress(...). This method executes the
        // overridden method onProgressUpdate(...) which updates the progress.
        @Override
        protected Integer doInBackground(Integer... params) {
           
            // get the initial parameters. For us, this is the initial bar progress = 0
            int progress = ((Integer[])params)[0];
           
            do {
               
                // only keep going in case the task was not cancelled
                if (!this.isCancelled()) {
                    // execute hard work - sleep
                    executeHardWork();
                }
                else {
                    // in case the task was cancelled, break the loop
                    // and finish this task
                    break;
                }
                   
                // upgrade progress
                progress++;
                publishProgress(progress);
            } while (progress <= MAX_PROGRESS);
           
            return progress;
        }

Here is whee the "magic" happens. This method executes the long-time task (calling the method executeHardWork()) and report its progress using the method publishProgress(progress) - which makes the event onProgressUpdate(...) to be executed.. Note also that here it is verified whether the task was cancelled, before it poceeds.

Now, have a look at the method below:


       // Every time the progress is informed, we update the progress bar
        @Override
        protected void onProgressUpdate(Integer... values) {
            int progress = ((Integer[])values)[0];
            mProgressBar.setProgress(progress);
            super.onProgressUpdate(values);
        }


This event is called, as mentioned before, if the method publishProgress(progress) is executed. The method onProgressUpdate(...) simply updates the progress into the progress bar.

Another important event is displayed below:

       // If the cancellation occurs, set the message informing so
        @Override
        protected void onCancelled(Integer result) {
            txtMessage.setText(MessageFormat.format("Async task has been cancelled at {0} seconds.", result - 1));
            super.onCancelled(result);
        }


This event is called and the cancellation is perfomed. This method simply displays a message stating the new status (cancellation). Notice also, that when the cancellation is dispatched, the method doInBackground(...)  stops executing when the isCancelled() verification returns true. It is important to emphasize that, when the call off occurs, the method onPostExecute(...) is not called. In the code, the cancellation was triggered by the Cancel Button event cancelOnclick(View v). The method called in the AsyncTask object was AsyncTask.cancel(boolean).

It is also important to discuss the method is displayed below:


        // Method executed after the task is finished. If the task is cancelled this method is not
        // called. Here we display a finishing message and arrange the buttons.
        @Override
        protected void onPostExecute(Integer result) {
            txtMessage.setText(MessageFormat.format("Async task execution finished in {0} seconds.", result - 1));
            btnCancel.setEnabled(false);
            btnRestart.setEnabled(true);
            super.onPostExecute(result);
        }

Here tasks are executed after the long-time task is executed. For this case, the buttons are redefined and a message is displayed.

If you think about the code, the methods explained above are the more important ones. Note that the code provided is complete and well commented. Therefore, I strongly advise you to create an android project and insert the code into it. You will be able to observe how it works properly and see it in action.

Saturday, May 5, 2012

List Activity using checkboxes - an issue

One common List Activity using android is the one which uses check boxes. On may note, however, every this list is created using the CheckBox component, one cannot have an item selected. The only thing one can do is simply to check or uncheck the Check Box. One cannot, for instance, select an item or do any operations regarding this very selection. For instance, one cannot open a menu for a desired item.

The first thought one might have is to customize several features of the Activity List itself. However, this would take quite some time and would be a huge effort in order to accomplish a simple thing: select an item.

Another solution, which is quite a good one, is to, instead of adding a CheckBox component, add an Image component for a check box. This image would hold two figures: one for a selected check box and another for a unselected check box. They would be changed whenever this image was clicked. Therefore, one would have the behavior of the check box implemented and the list would behave naturally, allowing items selection.

A third solution, and the simplest one, would be to use the CheckedTextView component. This is actually a check box with text component. One simply omits the text by providing none. This component behaves exactly like a CheckBox with the advantage of allowing the Activity List to behave naturally, allowing items selection. Thus, a substitution of a CheckBox component for a CheckedTextView would be straightforward.

When one simply add the CheckedTextView into the xml layout file, it may not appear correctly or not appear at all, because some layout definitions are required. One that works is displayed below:

<CheckedTextView android:id="@+id/ckb"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                   android:textAppearance="?android:attr/textAppearanceLarge"
                android:layout_gravity="right"
                android:checked="false"
                android:clickable="false"
                android:checkMark="?android:attr/listChoiceIndicatorMultiple"
            />

Now a full example using CheckedTextView is displayed below. The first box shows the layout of xml of the main Activity. The second one depicts the layout xml of the list row. Finally, the third one displays the code of the activity.


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


    <ImageView android:id="@+id/img"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:padding="6dip"/>


    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        android:layout_weight="4" >


        <TextView android:id="@+id/text1"
            android:textSize="12sp"
            android:textStyle="bold"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:paddingLeft="10dip"
            android:paddingTop="6dip"/>


        <TextView android:id="@+id/text2"
            android:textSize="12sp"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:paddingLeft="10dip"/>
    </LinearLayout>
   
    <LinearLayout
        android:id="@+id/cbxLayout"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:gravity="right"
        >
       
        <CheckedTextView android:id="@+id/ckb"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textAppearance="?android:attr/textAppearanceLarge"
            android:layout_gravity="right"
            android:checked="false"
            android:clickable="false"
            android:checkMark="?android:attr/listChoiceIndicatorMultiple"
        />
    </LinearLayout>
</LinearLayout>


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


    <ListView
         android:id="@id/android:list"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:layout_weight="1"
         android:drawSelectorOnTop="false"
     />
    <Button
        android:id="@+id/button"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="@string/button_label"
        android:gravity="center_horizontal"       
        />


</LinearLayout>

package com.checkboxlist;


import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


import android.app.ListActivity;
import android.content.Context;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.CheckedTextView;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.SimpleAdapter;
import android.widget.TextView;
import android.widget.Toast;


public class CheckBoxList extends ListActivity implements OnClickListener {
    private ArrayList<Integer> selectedItems = new ArrayList<Integer>();
    private final String SELECTED_ITEM_KEY = "selected_items";
    public final String TEXT_KEY_1 = "title";
    public final String TEXT_KEY_2 = "description";
    public final String ITEM_ID = "id";
    public final String IMG_KEY = "img";


    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.listviewmult);


        findViewById(R.id.button).setOnClickListener(this);


        // list data
        List<Map<String, Object>> resourceNames = new ArrayList<Map<String, Object>>();
        generateData(resourceNames);


        MyAdapter notes = new MyAdapter(this, resourceNames,
                R.layout.listrowmult, new String[] { TEXT_KEY_1, TEXT_KEY_2,
                        IMG_KEY, ITEM_ID }, new int[] { R.id.text1, R.id.text2,
                        R.id.img }, selectedItems);


        setListAdapter(notes);
    }


    private void generateData(List<Map<String, Object>> resourceNames) {
        // TODO here you will fill resourceNames with your own data


        Map<String, Object> data;
        int NUM_ITEMS = 50;


        for (int i = 0; i <= NUM_ITEMS; i++) {
            data = new HashMap<String, Object>();
            data.put(ITEM_ID, i);
            data.put(TEXT_KEY_1,
                    getString(R.string.list_item) + " " + Integer.toString(i));
            data.put(TEXT_KEY_2, getString(R.string.description));
            data.put(IMG_KEY, R.drawable.listicon);
            resourceNames.add(data);
        }
    }


    /*
     * Restores list selection
     */
    @Override
    protected void onRestoreInstanceState(Bundle state) {
        super.onRestoreInstanceState(state);
        selectedItems.addAll(state.getIntegerArrayList(SELECTED_ITEM_KEY));
    }


    /*
     * When the device is rotated, this activity is killed This method is called
     * when activity is about to be killed and saves the current list selection
     */
    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        outState.putIntegerArrayList(SELECTED_ITEM_KEY, selectedItems);
    }


    /*
     * Prints on screen the currently selected items
     */
    public void onClick(View target) {
        // TODO execute your action here


        StringBuilder strText = new StringBuilder();
        strText.append(getString(R.string.selected));


        Collections.sort(selectedItems);


        boolean first = true;
        for (Integer cur : selectedItems) {
            if (first) {
                strText.append(cur);
                first = false;
            } else {
                strText.append(", " + cur);
            }
        }


        Toast.makeText(getApplicationContext(), strText.toString(),
                Toast.LENGTH_LONG).show();
    }


    class MyAdapter extends SimpleAdapter {
        List<? extends Map<String, ?>> resourceNames;
        OnItemClickListener listener = null;
        ArrayList<Integer> selectedItems;
        String[] strKeys;
        int[] ids;


        public MyAdapter(Context context, List<? extends Map<String, ?>> data,
                int resource, String[] from, int[] to,
                ArrayList<Integer> selectedItems) {
            super(context, data, resource, from, to);
            this.selectedItems = selectedItems;
            resourceNames = data;
            strKeys = from;
            ids = to;
        }


        /*
         * Returns a view to be added on the list When we scroll the list, some
         * items leave the screen becoming invisible to the user. Since creating
         * views is an expensive task, we'd rather recycle these not visible
         * views, that are referenced by convertView, updating its fields
         * values.
         */
        @Override
        public View getView(int position, View convertView, ViewGroup parent) {


            // used to improve performance, since we call findViewById
            // only once for each created, but not recycled, view
            ViewHolder holder;


            if (listener == null)
                listener = new OnItemClickListener(selectedItems);


            // view to be recycled
            if (convertView == null) {
                holder = new ViewHolder();
                convertView = LayoutInflater.from(parent.getContext()).inflate(
                        R.layout.listrowmult, null);


                holder.tv1 = (TextView) convertView.findViewById(R.id.text1);
                holder.tv2 = (TextView) convertView.findViewById(R.id.text2);
                holder.img = (ImageView) convertView.findViewById(R.id.img);
                holder.ckb = (CheckedTextView) convertView.findViewById(R.id.ckb);
                holder.cbxLayout = (LinearLayout) convertView.findViewById(R.id.cbxLayout);


                convertView.setTag(holder);
            } else {
                holder = (ViewHolder) convertView.getTag();
            }
            Map<String, ?> currentData = resourceNames.get(position);


            // updates list items values
            holder.tv1.setText(currentData.get(strKeys[0]).toString());
            holder.tv2.setText(currentData.get(strKeys[1]).toString());
            holder.img.setImageResource((Integer) currentData.get(strKeys[2]));
            holder.ckb.setChecked(selectedItems.contains((Integer) currentData
                    .get(strKeys[3])));


            holder.cbxLayout.setId((Integer) currentData.get(strKeys[3]));
            holder.cbxLayout.setOnClickListener(listener);


            return convertView;
        }
    }


    /*
     * Holds references to list items
     */
    class ViewHolder {
        TextView tv1, tv2;
        ImageView img;
        CheckedTextView ckb;
        LinearLayout cbxLayout;
    }


    /*
     * Called when a list item is clicked
     */
    class OnItemClickListener implements OnClickListener {
        ArrayList<Integer> selectedItems;


        public OnItemClickListener(ArrayList<Integer> selectedItems) {
            this.selectedItems = selectedItems;
        }


        public void onClick(View v) {
            // handles list item click
            CheckedTextView  ckb = (CheckedTextView ) v.findViewById(R.id.ckb);
            boolean checked = ckb.isChecked();
            // updates selected list
            if (checked) {
                selectedItems.remove(new Integer(v.getId()));
            } else {
                selectedItems.add(v.getId());
            }
            // update check box value
            ckb.setChecked(!checked);
        }
    }
}


Now, the most importat details of the code will be explained.

private void generateData(List<Map<String, Object>> resourceNames) {
        // TODO here you will fill resourceNames with your own data

        Map<String, Object> data;
        int NUM_ITEMS = 50;

        for (int i = 0; i <= NUM_ITEMS; i++) {
            data = new HashMap<String, Object>();
            data.put(ITEM_ID, i);
            data.put(TEXT_KEY_1,
                    getString(R.string.list_item) + " " + Integer.toString(i));
            data.put(TEXT_KEY_2, getString(R.string.description));
            data.put(IMG_KEY, R.drawable.listicon);
            resourceNames.add(data);
        }
    }


The code above shows where the data is generated. A dumny collection of Map is created. This method should be replaced by the actual data retrieving of ones implementation.

    /*
     * Prints on screen the currently selected items
     */
    public void onClick(View target) {
        // TODO execute your action here

        StringBuilder strText = new StringBuilder();
        strText.append(getString(R.string.selected));

        Collections.sort(selectedItems);

        boolean first = true;
        for (Integer cur : selectedItems) {
            if (first) {
                strText.append(cur);
                first = false;
            } else {
                strText.append(", " + cur);
            }
        }

        Toast.makeText(getApplicationContext(), strText.toString(),
                Toast.LENGTH_LONG).show();
    }


 The code above display the selected items. Note that is uses the list selectedItems which stores the the elements which were checkec by the user.

class MyAdapter extends SimpleAdapter {
        List<? extends Map<String, ?>> resourceNames;
        OnItemClickListener listener = null;
        ArrayList<Integer> selectedItems;
        String[] strKeys;
        int[] ids;

        public MyAdapter(Context context, List<? extends Map<String, ?>> data,
                int resource, String[] from, int[] to,
                ArrayList<Integer> selectedItems) {
            super(context, data, resource, from, to);
            this.selectedItems = selectedItems;
            resourceNames = data;
            strKeys = from;
            ids = to;
        }

        /*
         * Returns a view to be added on the list When we scroll the list, some
         * items leave the screen becoming invisible to the user. Since creating
         * views is an expensive task, we'd rather recycle these not visible
         * views, that are referenced by convertView, updating its fields
         * values.
         */
        @Override
        public View getView(int position, View convertView, ViewGroup parent) {

            // used to improve performance, since we call findViewById
            // only once for each created, but not recycled, view
            ViewHolder holder;

            if (listener == null)
                listener = new OnItemClickListener(selectedItems);

            // view to be recycled
            if (convertView == null) {
                holder = new ViewHolder();
                convertView = LayoutInflater.from(parent.getContext()).inflate(
                        R.layout.listrowmult, null);

                holder.tv1 = (TextView) convertView.findViewById(R.id.text1);
                holder.tv2 = (TextView) convertView.findViewById(R.id.text2);
                holder.img = (ImageView) convertView.findViewById(R.id.img);
                holder.ckb = (CheckedTextView) convertView.findViewById(R.id.ckb);
                holder.cbxLayout = (LinearLayout) convertView.findViewById(R.id.cbxLayout);

                convertView.setTag(holder);
            } else {
                holder = (ViewHolder) convertView.getTag();
            }
            Map<String, ?> currentData = resourceNames.get(position);

            // updates list items values
            holder.tv1.setText(currentData.get(strKeys[0]).toString());
            holder.tv2.setText(currentData.get(strKeys[1]).toString());
            holder.img.setImageResource((Integer) currentData.get(strKeys[2]));
            holder.ckb.setChecked(selectedItems.contains((Integer) currentData
                    .get(strKeys[3])));

            holder.cbxLayout.setId((Integer) currentData.get(strKeys[3]));
            holder.cbxLayout.setOnClickListener(listener);

            return convertView;
        }
    }


The code above is the custom implementation of the Base Adapter. Basically, for every row displayed it sets the appropriate layout, by inflating it, and set the content values and listeners appropriated to make the list work. Take a time to understand it. Note that the this Adapter was bound in the onCreate(Bundle) event. Also, oberve how it saves data in a Value Object structure, called ViewHolder. It does that to improve performance.

Concluding, studying the posted code one can accomplish to develop a List Activity enabling selection, using Check Boxes by the use of CheckedTextView component.