title: IndexOutOfBoundsException in ListView
body: <p>I've seen this question a couple of times before but none of the answers seem to fit my case.
  As with the others, the exception is withing the Android code and not mine.</p>
  
  <p>The weird thing is it only happens with Android 4.1 and 4.2. My Galaxy 3 recently updated to 4.3 and the problem disappeared.
  OTOH, on a Nexus with 4.4 it still happens!</p>
  
  <p>We don't have any headers in the view. 
  The other point is that it only happens when there are not enough rows to fill the screen.</p>
  
  <pre><code>FATAL EXCEPTION: main
  java.lang.IndexOutOfBoundsException: Invalid index 0, size is 0
      at java.util.ArrayList.throwIndexOutOfBoundsException(ArrayList.java:251)
      at java.util.ArrayList.get(ArrayList.java:304)
      at android.widget.HeaderViewListAdapter.isEnabled(HeaderViewListAdapter.java:164)
      at android.widget.ListView.dispatchDraw(ListView.java:3207)
      at android.view.View.draw(View.java:13715)
      at android.widget.AbsListView.draw(AbsListView.java:3653)
      at android.view.View.draw(View.java:13596)
      at android.view.ViewGroup.drawChild(ViewGroup.java:2928)
      at android.view.ViewGroup.dispatchDraw(ViewGroup.java:2797)
      at android.view.View.draw(View.java:13715)
      at android.widget.FrameLayout.draw(FrameLayout.java:467)
      at android.view.View.draw(View.java:13596)
      at android.view.ViewGroup.drawChild(ViewGroup.java:2928)
      at android.view.ViewGroup.dispatchDraw(ViewGroup.java:2797)
      at android.view.View.draw(View.java:13594)
      at android.view.ViewGroup.drawChild(ViewGroup.java:2928)
      at android.view.ViewGroup.dispatchDraw(ViewGroup.java:2797)
      at android.view.View.draw(View.java:13594)
      at android.view.ViewGroup.drawChild(ViewGroup.java:2928)
      at android.view.ViewGroup.dispatchDraw(ViewGroup.java:2797)
      at android.view.View.draw(View.java:13594)
      at android.view.ViewGroup.drawChild(ViewGroup.java:2928)
      at android.view.ViewGroup.dispatchDraw(ViewGroup.java:2797)
      at android.view.View.draw(View.java:13715)
      at android.view.View.draw(View.java:13596)
      at android.view.ViewGroup.drawChild(ViewGroup.java:2928)
      at android.view.ViewGroup.dispatchDraw(ViewGroup.java:2797)
      at android.view.View.draw(View.java:13594)
      at android.view.ViewGroup.drawChild(ViewGroup.java:2928)
      at android.view.ViewGroup.dispatchDraw(ViewGroup.java:2797)
      at android.view.View.draw(View.java:13594)
      at android.view.ViewGroup.drawChild(ViewGroup.java:2928)
      at android.view.ViewGroup.dispatchDraw(ViewGroup.java:2797)
      at android.view.View.draw(View.java:13715)
      at android.widget.FrameLayout.draw(FrameLayout.java:467)
      at com.android.internal.policy.impl.PhoneWindow$DecorView.draw(PhoneWindow.java:2211)
      at android.view.ViewRootImpl.drawSoftware(ViewRootImpl.java:2281)
      at android.view.ViewRootImpl.draw(ViewRootImpl.java:2177)
      at android.view.ViewRootImpl.performDraw(ViewRootImpl.java:2045)
      at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1854)
      at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:989)
      at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:4351)
      at android.view.Choreographer$CallbackRecord.run(Choreographer.java:749)
      at android.view.Choreographer.doCallbacks(Choreographer.java:562)
      at android.view.Choreographer.doFrame(Choreographer.java:532)
      at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:735)
      at android.os.Handler.handleCallback(Handler.java:725)
      at android.os.Handler.dispatchMessage(Handler.java:92)
      at android.os.Looper.loop(Looper.java:137)
      at android.app.ActivityThread.main(ActivityThread.java:5041)
      at java.lang.reflect.Method.invokeNative(Native Method)
      at java.lang.reflect.Method.invoke(Method.java:511)
      at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:793)
      at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:560)
      at dalvik.system.NativeStart.main(Native Method)
  </code></pre>
  
  <p>We have a base class that extends ArrayAdapter and then each activity uses its own adapter to extend that one.</p>
  
  <p>This is the code that appears in the base class:</p>
  
  <pre><code>public abstract class MeuhedetListAdapter extends ArrayAdapter implements ListScreenAdapterInterface, IList {
      // Constants:
      protected final static String TAG = "MeuhedetListAdapter ";
      protected final String SERVLET_NAME_FOR_VISIT_DETAILS = "PDFPatientVisitSummary";
  
      public static final String SELECTED_ITEM = "selected_item";
      public static final int NUM_OF_VIEW_TYPES = 2;
      public static final int ROW_WITH_DATA = 0;
      public static final int ROW_WITHOUT_DATA = 1;
  
      boolean superCalled;
  
      @SuppressWarnings("serial")
  
  
      private boolean _moreResultsButtonDisplayed = false;
  
  
      // Variables:
      /** Should the connector be run in the foreground */
      protected boolean _showProgressDialog = true;
      /** The list view this adapter is connected to */
      protected ListView _lv;
      /** Contains references to GUI components of the list's items so that findViewById() won't be called every time anew */
      protected ViewHolder _viewHolder;
      /* The selected record from the list in this screen */
      protected Serializable _selectedItem = null;
      protected View _selectedView;
      /* The footer view of the list representing the add more results item */
      private RelativeLayout _footerView;
      /** This is the data that will be displayed */
      protected ArrayList&lt;Serializable&gt; _results = new ArrayList&lt;Serializable&gt;();
      /* An instance of LayoutInflater to be used throughout the class */
      private LayoutInflater _li;
      /* The number of items in the ListView of this screen which are visible when this screen is displayed. Used to determine how many empty items the list will contain */
      private int _maxNumOfItemsToDisplay = setInitialNumOfItems();
      /* This variable will hold the number of items in the list that the user can see as this screen is started, which is equal to the number of items that have been initialized */
      private int _numOfItemsDisplayedOnStart;
  
      protected ListAdapterParams _params;
  
      /* Whether the servlet returned at least one result */
      private boolean _dataRetrieved = false;
      private SessionBasedServletConnector connector;
      /* Whether an item has been clicked. This will be used to prevent the user from clicking an item in the list multiple times before the Activity is
       * displayed. */
      protected boolean _itemClicked = false;
      OnGlobalLayoutListener l = null;
  
  
      // Abstract methods:
      /**
       * 
       * @return The connector to be used for obtaining data that should be displayed in the list
       */
      protected abstract SessionBasedServletConnector getConnector();
  
  
      // Constructors:
      public MeuhedetListAdapter(Activity context) {
          this(context, null);
      }
  
      public MeuhedetListAdapter(Activity context, ListAdapterParams params) {
          super(context, 0);
          _params = params;
  
          // Will need it a lot so do it once and save.   
          this._li = context.getLayoutInflater();
      }
  
  
      // Methods:
      @Override
      public boolean displayData(Serializable[] data, View lv, boolean showProgressDialog) {
          this._lv = (ListView) lv;
  
          // Wait until the initialization process of the ListView is over. We know it's over when the ListView becomes visible to the user:
          l = new OnGlobalLayoutListener() {
              @Override
              public void onGlobalLayout() {
                  Screen.getContext().runOnUiThread(new Runnable() {
                      @SuppressWarnings("deprecation")  // removeGlobalOnLayoutListener replace by removeOnGlobalLayoutListener from API16
                      @Override
                      public void run() {
                          // Now that we know exactly how many items are visible at the start of this screen, change the getCount() method of the list adapter to be
                          // affected by this number, so that we won't have redundant or missing elements from the list, resulting in a ListView which is exactly the size
                          // it should be:
                          _maxNumOfItemsToDisplay = _numOfItemsDisplayedOnStart;
                          MeuhedetListAdapter.this._lv.getViewTreeObserver().removeGlobalOnLayoutListener(l);
                          MeuhedetListAdapter.this.notifyDataSetChanged();
                      }
                  });
              }
          };
          MeuhedetListAdapter.this._lv.getViewTreeObserver().addOnGlobalLayoutListener(l);
  
          this._showProgressDialog = showProgressDialog;
          // Set the add more results item before setting the adapter, so that you can add / remove it later on (Android
          // platform requirement for ListView):
          this._footerView = (RelativeLayout) this._li.inflate(getFooterViewResource(), null);
          this._lv.addFooterView(this._footerView);
          setItemClicked(false);
  
          if (data == null) {
              connector = getConnector();
              connector.addListener(new MySessionBasedConnectionListener(getContext(), null));
              connector.connect();
          } else {
              this.addDataRows(data,false);
          }
  
          return this._dataRetrieved;
      }
  
  
      @Override
      public boolean displayData(View lv, boolean showProgressDialog) {
          this._lv = (ListView) lv;
          setItemClicked(false);
          this._showProgressDialog = showProgressDialog;
          // Set the add more results item before setting the adapter, so that you can add / remove it later on (Android
          // platform requirement for ListView):
          this._footerView = (RelativeLayout) this._li.inflate(getFooterViewResource(), null);
          this._lv.addFooterView(this._footerView);
  
          connectAdapter();
  
          return this._dataRetrieved;
      }
  
  
      @SuppressWarnings("serial")
      private class MySessionBasedConnectionListener extends SessionBasedConnectionListener {
          public MySessionBasedConnectionListener(Context ctx,Class&lt;?&gt; nextActivity) {
              super(ctx, nextActivity);
          }
  
          /**
           * This listener functions only as the listener for the first chunk of results. For later results, I attach another listener, 
           * because a different behavior is required.
           */
          @Override
          public void connectionFinished(ServletConnector connector, boolean success, Object data) {
              // If failed, report and exit:
              if (success == false) {
                  Log.d(getClass().getName(), "connectionFinished() : operation failed");
              } else {
                  if ((data != null) &amp;&amp; (((Serializable[]) data).length &gt; 0)) {
                      // Save connection listener for future reference:
  //                  SessionBasedConnectionListener._sc = (SessionBasedServletConnector) connector;
  
                      // Save new time stamp:
                      ((SessionBasedServletConnector) connector).inpTimestamp = StaticDataManager.getInstance()._receivedTimestamp;
  
                      // Casting is required in order to use checkStatusAndShowError(), defined in MeuhedetServletConnector:
                      if (connector instanceof MeuhedetServletConnector) {
                          if (((MeuhedetServletConnector) connector).checkStatusAndShowError() == false) {
                              addDataRows((Serializable[]) data,false);
                              MeuhedetListAdapter.this._dataRetrieved = true;
                          }
                      }
                  }
  
                  // Remove listener after first chunk is retrieved:
                  connector.removeListener(this);
              }
          }
      }
  
      /*
       * Removes the footer row that enables the user to add more results from the list
       */
      protected void removeAddMoreResultsItem() {
          if (this._footerView != null) {// &amp;&amp; _lv.getAdapter() != null) {
              Log.d(getClass().getName(), "removeAddMoreResultsItem() : this._footerView != null");
              this._lv.removeFooterView(this._footerView);
              this._footerView = null;
          }
      }
  
  
      private void checkMoreResultsItemNecessary(int sizeOfChunk){
          this._moreResultsButtonDisplayed = (sizeOfChunk &gt; getMaxNumberOfItems());
      }
  
      /*
       * If there are more than the max items then add an item that searches for more results when clicked.
       * 
       * @param sizeOfChunk The number of results returned by the servlet in the current chunk
       */
      protected void addMoreResultsItemIfNecessary() {
          if (this._moreResultsButtonDisplayed) {
              // This is not the last chunk
              // Add a footer view for adding additional results if not added already:
              if (this._footerView == null) {
                  this._footerView = (RelativeLayout) this._li.inflate(getFooterViewResource(), null);
                  this._lv.addFooterView(this._footerView);
              }
          } else {
              // This is the last chunk
              // Remove the footer view for adding more results if available in the list:
              this.removeAddMoreResultsItem();
          }
      }
  
      // We want to force at least NUM_OF_ITEMS_DISPLAYED rows on the screen. So, we set getCount to return NUM_OF_ITEMS_DISPLAYED
      // if there are less than NUM_OF_ITEMS_DISPLAYED rows.
      // getView then chooses the required view for the row depending on whether it is a row with data or an empty one.
      // However, if there is no data at all then we show just one "row" which is the "no data" message
      @Override
      public int getCount() {
          Log.d(TAG,"getCount. getActualNumOfItemsInList() = " + getActualNumOfItemsInList());
          return Math.max(_maxNumOfItemsToDisplay, getActualNumOfItemsInList());
      }
  
      /**
       * Determines the behavior when the user selects an item in the list that is NOT the "add more results" item
       * 
       * @param parent The adapter of the ListView that contains the selected item
       * @param selectedRecord The selected row in the ListView
       */
      protected void onNonAddMoreResultsFooterClick(AdapterView&lt;?&gt; parent, View selectedRecord) {
          // User selected an item in the list that is not the add more results footer. Get the selected item:
          this._selectedItem = this._results.get(parent.getPositionForView(selectedRecord));
          this._selectedView = selectedRecord;
  
          // Perform an action on the clicked item
          this.onItemClicked();
      }
  
      @Override
      public View getView(int position, View convertView, ViewGroup parent) {
          // Update the number of items that are visible as this screen is displayed:
          _numOfItemsDisplayedOnStart = Math.max(_numOfItemsDisplayedOnStart, position);
  
          // Choose the view to use depending on the type of row to be displayed
          // The input convertview, if it is not null, will always be the one that matches the type given.
          // This is due to the code in getItemViewType returning the type of view required for this row.
          int viewType = (position &lt; _results.size() ? getItemViewType(position) : ROW_WITHOUT_DATA);
          boolean isTouchable = isClickable(position);
          Log.d(TAG,"getView - position = " + position + "     viewType = " + viewType + "     isTouchable = " + isTouchable);
          switch (viewType) {
              case ROW_WITH_DATA:  // Normal data view
              default:
                  Activity context = (Activity) this.getContext();
                  if (convertView == null) {
                      int itemLayout = viewType==ROW_WITH_DATA?getItemLayout():getItemLayout(viewType);
                      convertView = (RelativeLayout) context.getLayoutInflater().inflate(itemLayout, parent, false);
                      _viewHolder = createViewHolder(convertView, viewType);
                      convertView.setTag(_viewHolder);
                  } else {
                      _viewHolder = getViewHolder(convertView);
                  }
  
                  MeuchedetApplication.setBackgroundDrawable(convertView,context.getResources().getDrawable(isTouchable ? R.drawable.list_item_selector :
                                                                                       R.drawable.listview_unselected_item_background));
  
                  setRecordData(position, (ViewGroup) convertView, _viewHolder);
                  break;
              case ROW_WITHOUT_DATA:  // Empty row
                  if (convertView == null) {
                      convertView = (RelativeLayout) this._li.inflate(getEmptyItemLayout(), parent, false);
                  }
                  break;
          }
  
          // Determine whether the item is clicakble:
          setClickable(convertView, isTouchable);
  
          return convertView;
      }
  
      public void setClickable(View view, boolean isTouchable){
          MeuchedetApplication.setBackgroundDrawable(view, getContext().getResources().getDrawable(isTouchable ? R.drawable.list_item_selector :
                                                                                                                 R.drawable.listview_unselected_item_background));
          view.setClickable(!isTouchable);
          view.setFocusable(!isTouchable);
          view.setFocusableInTouchMode(!isTouchable);
          view.setEnabled(!isTouchable);
  
      }
      protected int getItemLayout(int viewType){
          return 0;
      }
  
      @SuppressWarnings("serial")
      protected void getMoreData() {
  
              // Only first chunk has been read. Attach the new connection listener (which has a different behavior than the first
              // connection listener that actually starts this Activity):
              connector.clearListeners();
              connector.addListener(new ConnectionListener() {
                  /**
                   * A second connection listener required because the behavior in the connectionFinished() method should change after the
                   * first chunk is read
                   */
                  @Override
                  public void connectionFinished(ServletConnector connector, boolean success, Object data) {
                      // If failed, report and exit:
                      if (success == false) {
                          Log.d(getClass().getName(), "connectionFinished() : Failed to receive additional data");
                          return;
                      }
  
                      // Casting is required in order to use checkStatusAndShowError(), defined in MeuhedetServletConnector:
                      if (connector instanceof MeuhedetServletConnector) {
                          if (((MeuhedetServletConnector) connector).checkStatusAndShowError() == false) {
                              // The third argument, data, contains the data returned by the server, in the form of: Searchable[].
                              if (data == null) {
                                  ((Activity) MeuhedetListAdapter.this.getContext()).runOnUiThread(new Runnable() {
                                      @Override
                                      public void run() {
                                          // No new data is available:
                                          removeAddMoreResultsItem();
                                      }
                                  });
  
                                  return;
                              } else {
                                  // Add new views:
                                  final Serializable[] searchableData = (Serializable[]) data;
                                  addDataRows(searchableData,(MeuhedetListAdapter.this._results.get(MeuhedetListAdapter.this._results.size()-1).equals(searchableData[0])));
                              }
                          }
                      }
                  }
              });
          ((SerializableSearchServletConnector) connector).getNextResults();
      }
  
      /**
       * 
       * @return The selected item in the list
       */
      public Serializable getSelectedItem() {
          return this._selectedItem;
      }
  
      @Override
      /**
       * This method indicates that we have two different view layouts with the ListView.
       * In our case, one if for the normal row and one is for the empty row
       */
      public int getViewTypeCount() {
          return MeuhedetListAdapter.NUM_OF_VIEW_TYPES;
      }
  
      @Override
      /**
       * This method returns which type of view to use for which row.
       * We will use the normal type for the original rows and the empty type for any overflow rows.
       * So, type 0 = normal, type 1 = empty, 2 = A "No data to display" entry.
       * 
       * This method is called automatically by ListView to determine what type of view to fetch from the recycler.
       * It is then called in our getView code to determine what type of view we have or should create.
       */
      public int getItemViewType(int position) {
          if (position &lt; _results.size())
              return ROW_WITH_DATA;
          else
              return ROW_WITHOUT_DATA;
      }
  
  
      /*
       * This method returns the view holder that is connected to the specific view.
       */
      protected ViewHolder getViewHolder(View convertView) {
          return (ViewHolder) convertView.getTag();
      }
  
      /**
       * 
       * @return The ID of the empty item layout to be used in this screen whenever empty items are required
       */
      protected abstract int getEmptyItemLayout();
  
      /**
       * 
       * @return The ID of the layout for an (non-empty) item in the list
       */
      protected abstract int getItemLayout();
  
      /**
       * By overriding this method, additional actions can be performed on the initial layout of this screen.
       */
      protected void performAdditionalChores() {
      }
  
      /**
       * The maximum number of rows that should be shown in the listview before a "get more" button is added.
       */
      protected int getMaxNumberOfItems() {
          return SerializableSearchServletConnector.DEFAULT_MAX_RESULTS_LENGTH;
      }
  
      /**
       * Called when a row is inserted so as to define if the row is clickable or not. Override this if you wish to change what is clickable.
       * Empty rows are never clickable.
       */
      protected boolean itemIsClickable(int position) {
          return false;
      }
  
      /**
       * Defines whether a row in the list is clickable. Override this if you wish to change the clickability of an entry.
       */
      protected boolean isClickable(int position) {
          return false;
      }
  
      /**
       * By overriding this method, you can define which view to put the border round. The default is to put it round the list view itself.
       */
      protected int getViewToBorderId(){
          return R.id.list_view;
      }
  
      /**
       * 
       * @return The number of items that should be included in the list
       */
      protected int getActualNumOfItemsInList() {
          Log.d(TAG,"_results.size() = " + _results.size());
          return this._results.size();
      }
  
      /**
       * 
       * Create a view holder to hold on to the links to the views.
       * 
       * @param viewGroup ViewGroup containing the views
       * @param viewType  Type of view. This is used when more than one type of view is required within the list
       * @return The new ViewHolder relevant to the current screen
       */
      protected abstract ViewHolder createViewHolder(View viewGroup, int viewType);  // If there is more than one type of view then "viewType" contains which one to create.
  
      /**
       * 
       * Fills a certain row in the list with the correct data.
       * 
       * @param position  Which row in the data to display
       * @param row       ViewGroup to receive the data
       * @return
       */
      protected abstract void setRecordData(int position, ViewGroup row, ViewHolder viewHolder);
  
      /* Starts the next Activity */
      public abstract void onItemClicked();
  
      protected void addDataRows(final Serializable[] data, boolean skipFirstRow) {
          // Add the data views to the list:
          int prevNumOfItems = this._results.size();
          int position;
          int startPos = (skipFirstRow?1:0);
          for (int i = startPos; i &lt; data.length; i++) {
              // Add the Serializable to the _results data structure for future reference:
              position = prevNumOfItems + i - startPos;
              this._results.add(position, data[i]);
          }
          // Check if the add more items view is needed
          checkMoreResultsItemNecessary(data.length);
          // Connect this Adapter to the list:
          connectAdapter();
  
      }
  
  
      /**
       * Connects this Adapter to its ListView and sets the onItemClickListener for the list.
       */
      private void connectAdapter() {
          // Note that we do the connecting to the view INSIDE the adapter because it has to be done AFTER the footer has been added.
          // Since the call to the connector is asynchronous we must be sure we have the data first before connecting.
          // We will only do it the first time data is added. Otherwise, adding the adapter again will send the list back to the top.
          ((Activity) MeuhedetListAdapter.this.getContext()).runOnUiThread(new Runnable() {
              public void run() {     
                  if (MeuhedetListAdapter.this._lv.getAdapter() == null) {
                      MeuhedetListAdapter.this._lv.setAdapter(MeuhedetListAdapter.this);
  
                      MeuhedetListAdapter.this._lv.setOnItemClickListener(new OnItemClickListener() {
                          @Override
                          public synchronized void onItemClick(AdapterView&lt;?&gt; parent, View view, int position, long id) {
                              if ((MeuhedetListAdapter.this._itemClicked == false) &amp;&amp; (view.equals(_footerView) == false)) {
                                  setItemClicked(true);
                                  onNonAddMoreResultsFooterClick(parent, view);
                              } else if (view.equals(_footerView)) {
                                  setItemClicked(false);
                                  // The add more results item is selected
                                  // Search for more results:
                                  getMoreData();
                              }
                          }
                      });
                  }               
  
                  // Remove the footer view for adding more results, if added to the list already. This is necessary because otherwise the new views will appear after
                  // this special footer:
                  MeuhedetListAdapter.this.removeAddMoreResultsItem();
                  MeuhedetListAdapter.this.addMoreResultsItemIfNecessary();
  
                  // Refresh the list:
                  notifyDataSetChanged();
              }
          });
      }
  
  
      /**
       * By overriding this method, you can define which view to use as the footer view (the "get more results" view)
       */
      protected int getFooterViewResource(){
          return R.layout.add_more_results_item;
      }
  
      @Override
      public void setItemClicked(boolean itemClicked) {
          this._itemClicked = itemClicked;
      }
  
      @Override
      public boolean areAllItemsEnabled() {
          return false;
      }
  
      protected int setInitialNumOfItems() {
          return 20;  // 20 by default
      }
  }
  </code></pre>
  
  <p>A note of explaination:
  The data is fetched from a server via the "ServletCoonector". When the data returns the method "connectionFinished" of the listener is invoked with the data passed as a parameter. </p>
  
  <p>The extended class:</p>
  
  <p>public class PurchasedMedicinesListAdapter extends MeuhedetListAdapter {</p>
  
  <pre><code>// Variables:
  /** The context in which this adapter is created */
  protected Context _ctx;
  protected String _type;
  
  
  // Constructors:
  public PurchasedMedicinesListAdapter(Activity ctx) {
      super(ctx);
  }
  
  public PurchasedMedicinesListAdapter(Activity context, PurchasedMedicinesListAdapterParams params) {
      super(context, params);
      _type = params.requestType;
      this._ctx = context;
  }
  
  private PurchasedMedicinesListAdapter(Activity context, AttributeSet attrs) {
      super(context);
  }
  
  
  public static class PurchasedMedicinesListAdapterParams extends ListAdapterParams{
      /**
       * 
       */
      private static final long serialVersionUID = -125845514634158323L;
      public PurchasedMedicinesListAdapterParams() {
      }
      public PurchasedMedicinesListAdapterParams(String requestType){
          this.requestType = requestType;
      }
      public String requestType = PurchasedMedicinesServletConnector.SERVLET_NAME_DETAILED;
  }   
  
  
  @Override
  protected SessionBasedServletConnector getConnector() {
      return new PurchasedMedicinesServletConnector(new PurchasedMedicinesServletConnector.PurchasedMedicinesServletConnectorParams(_type), _showProgressDialog);
  }
  
  
  @Override
  protected ViewHolder createViewHolder(View viewGroup, int viewType) {
      return PurchasedMedicine.createViewHolder(viewGroup);
  }
  
  @Override
  protected void setRecordData(int position, ViewGroup row, ViewHolder viewHolder) {
      Log.d(TAG,"setRecordData - position = " + position);
      final PurchasedMedicine medicine = (PurchasedMedicine) super._results.get(position);
      medicine.setRecordData(viewHolder, _ctx);
      medicine.setViewClickable(viewHolder);
  }
  
  @Override
  public void onItemClicked() {
      super.startNextActivity(_ctx, MedicinePurchaseDetailsScreen.class);
  }
  
  /**
   * The maximum number of rows that should be shown in the listview before a "get more" button is added.
   */
  protected int getMaxNumberOfItems() {
      int maxNumber = 27;
      if (_type.equals(PurchasedMedicinesServletConnector.SERVLET_NAME_SUMMARY)){
          maxNumber = Integer.MAX_VALUE;
      }
  
      return maxNumber;
  }
  </code></pre>
  
  <p>}</p>