ListActivity.java revision 54b6cfa9a9e5b861a9930af873580d6dc20f773c
1/* 2 * Copyright (C) 2006 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package android.app; 18 19import android.os.Bundle; 20import android.os.Handler; 21import android.view.KeyEvent; 22import android.view.View; 23import android.widget.Adapter; 24import android.widget.AdapterView; 25import android.widget.ListAdapter; 26import android.widget.ListView; 27 28/** 29 * An activity that displays a list of items by binding to a data source such as 30 * an array or Cursor, and exposes event handlers when the user selects an item. 31 * <p> 32 * ListActivity hosts a {@link android.widget.ListView ListView} object that can 33 * be bound to different data sources, typically either an array or a Cursor 34 * holding query results. Binding, screen layout, and row layout are discussed 35 * in the following sections. 36 * <p> 37 * <strong>Screen Layout</strong> 38 * </p> 39 * <p> 40 * ListActivity has a default layout that consists of a single, full-screen list 41 * in the center of the screen. However, if you desire, you can customize the 42 * screen layout by setting your own view layout with setContentView() in 43 * onCreate(). To do this, your own view MUST contain a ListView object with the 44 * id "@android:id/list" (or {@link android.R.id#list} if it's in code) 45 * <p> 46 * Optionally, your custom view can contain another view object of any type to 47 * display when the list view is empty. This "empty list" notifier must have an 48 * id "android:empty". Note that when an empty view is present, the list view 49 * will be hidden when there is no data to display. 50 * <p> 51 * The following code demonstrates an (ugly) custom screen layout. It has a list 52 * with a green background, and an alternate red "no data" message. 53 * </p> 54 * 55 * <pre> 56 * <?xml version="1.0" encoding="UTF-8"?> 57 * <LinearLayout 58 * android:orientation="vertical" 59 * android:layout_width="fill_parent" 60 * android:layout_height="fill_parent" 61 * android:paddingLeft="8" 62 * android:paddingRight="8"> 63 * 64 * <ListView id="android:list" 65 * android:layout_width="fill_parent" 66 * android:layout_height="fill_parent" 67 * android:background="#00FF00" 68 * android:layout_weight="1" 69 * android:drawSelectorOnTop="false"/> 70 * 71 * <TextView id="android:empty" 72 * android:layout_width="fill_parent" 73 * android:layout_height="fill_parent" 74 * android:background="#FF0000" 75 * android:text="No data"/> 76 * </LinearLayout> 77 * </pre> 78 * 79 * <p> 80 * <strong>Row Layout</strong> 81 * </p> 82 * <p> 83 * You can specify the layout of individual rows in the list. You do this by 84 * specifying a layout resource in the ListAdapter object hosted by the activity 85 * (the ListAdapter binds the ListView to the data; more on this later). 86 * <p> 87 * A ListAdapter constructor takes a parameter that specifies a layout resource 88 * for each row. It also has two additional parameters that let you specify 89 * which data field to associate with which object in the row layout resource. 90 * These two parameters are typically parallel arrays. 91 * </p> 92 * <p> 93 * Android provides some standard row layout resources. These are in the 94 * {@link android.R.layout} class, and have names such as simple_list_item_1, 95 * simple_list_item_2, and two_line_list_item. The following layout XML is the 96 * source for the resource two_line_list_item, which displays two data 97 * fields,one above the other, for each list row. 98 * </p> 99 * 100 * <pre> 101 * <?xml version="1.0" encoding="utf-8"?> 102 * <LinearLayout 103 * android:layout_width="fill_parent" 104 * android:layout_height="wrap_content" 105 * android:orientation="vertical"> 106 * 107 * <TextView id="text1" 108 * android:textSize="16" 109 * android:textStyle="bold" 110 * android:layout_width="fill_parent" 111 * android:layout_height="wrap_content"/> 112 * 113 * <TextView id="text2" 114 * android:textSize="16" 115 * android:layout_width="fill_parent" 116 * android:layout_height="wrap_content"/> 117 * </LinearLayout> 118 * </pre> 119 * 120 * <p> 121 * You must identify the data bound to each TextView object in this layout. The 122 * syntax for this is discussed in the next section. 123 * </p> 124 * <p> 125 * <strong>Binding to Data</strong> 126 * </p> 127 * <p> 128 * You bind the ListActivity's ListView object to data using a class that 129 * implements the {@link android.widget.ListAdapter ListAdapter} interface. 130 * Android provides two standard list adapters: 131 * {@link android.widget.SimpleAdapter SimpleAdapter} for static data (Maps), 132 * and {@link android.widget.SimpleCursorAdapter SimpleCursorAdapter} for Cursor 133 * query results. 134 * </p> 135 * <p> 136 * The following code from a custom ListActivity demonstrates querying the 137 * Contacts provider for all contacts, then binding the Name and Company fields 138 * to a two line row layout in the activity's ListView. 139 * </p> 140 * 141 * <pre> 142 * public class MyListAdapter extends ListActivity { 143 * 144 * @Override 145 * protected void onCreate(Bundle icicle){ 146 * super.onCreate(icicle); 147 * 148 * // We'll define a custom screen layout here (the one shown above), but 149 * // typically, you could just use the standard ListActivity layout. 150 * setContentView(R.layout.custom_list_activity_view); 151 * 152 * // Query for all people contacts using the {@link android.provider.Contacts.People} convenience class. 153 * // Put a managed wrapper around the retrieved cursor so we don't have to worry about 154 * // requerying or closing it as the activity changes state. 155 * mCursor = People.query(this.getContentResolver(), null); 156 * startManagingCursor(mCursor); 157 * 158 * // Now create a new list adapter bound to the cursor. 159 * // SimpleListAdapter is designed for binding to a Cursor. 160 * ListAdapter adapter = new SimpleCursorAdapter( 161 * this, // Context. 162 * android.R.layout.two_line_list_item, // Specify the row template to use (here, two columns bound to the two retrieved cursor 163 * rows). 164 * mCursor, // Pass in the cursor to bind to. 165 * new String[] {People.NAME, People.COMPANY}, // Array of cursor columns to bind to. 166 * new int[]); // Parallel array of which template objects to bind to those columns. 167 * 168 * // Bind to our new adapter. 169 * setListAdapter(adapter); 170 * } 171 * } 172 * </pre> 173 * 174 * @see #setListAdapter 175 * @see android.widget.ListView 176 */ 177public class ListActivity extends Activity { 178 /** 179 * This field should be made private, so it is hidden from the SDK. 180 * {@hide} 181 */ 182 protected ListAdapter mAdapter; 183 /** 184 * This field should be made private, so it is hidden from the SDK. 185 * {@hide} 186 */ 187 protected ListView mList; 188 189 private Handler mHandler = new Handler(); 190 private boolean mFinishedStart = false; 191 192 private Runnable mRequestFocus = new Runnable() { 193 public void run() { 194 mList.focusableViewAvailable(mList); 195 } 196 }; 197 198 /** 199 * This method will be called when an item in the list is selected. 200 * Subclasses should override. Subclasses can call 201 * getListView().getItemAtPosition(position) if they need to access the 202 * data associated with the selected item. 203 * 204 * @param l The ListView where the click happened 205 * @param v The view that was clicked within the ListView 206 * @param position The position of the view in the list 207 * @param id The row id of the item that was clicked 208 */ 209 protected void onListItemClick(ListView l, View v, int position, long id) { 210 } 211 212 /** 213 * Ensures the list view has been created before Activity restores all 214 * of the view states. 215 * 216 *@see Activity#onRestoreInstanceState(Bundle) 217 */ 218 @Override 219 protected void onRestoreInstanceState(Bundle state) { 220 ensureList(); 221 super.onRestoreInstanceState(state); 222 } 223 224 /** 225 * Updates the screen state (current list and other views) when the 226 * content changes. 227 * 228 * @see Activity#onContentChanged() 229 */ 230 @Override 231 public void onContentChanged() { 232 super.onContentChanged(); 233 View emptyView = findViewById(com.android.internal.R.id.empty); 234 mList = (ListView)findViewById(com.android.internal.R.id.list); 235 if (mList == null) { 236 throw new RuntimeException( 237 "Your content must have a ListView whose id attribute is " + 238 "'android.R.id.list'"); 239 } 240 if (emptyView != null) { 241 mList.setEmptyView(emptyView); 242 } 243 mList.setOnItemClickListener(mOnClickListener); 244 if (mFinishedStart) { 245 setListAdapter(mAdapter); 246 } 247 mHandler.post(mRequestFocus); 248 mFinishedStart = true; 249 } 250 251 /** 252 * Provide the cursor for the list view. 253 */ 254 public void setListAdapter(ListAdapter adapter) { 255 synchronized (this) { 256 ensureList(); 257 mAdapter = adapter; 258 mList.setAdapter(adapter); 259 } 260 } 261 262 /** 263 * Set the currently selected list item to the specified 264 * position with the adapter's data 265 * 266 * @param position 267 */ 268 public void setSelection(int position) { 269 mList.setSelection(position); 270 } 271 272 /** 273 * Get the position of the currently selected list item. 274 */ 275 public int getSelectedItemPosition() { 276 return mList.getSelectedItemPosition(); 277 } 278 279 /** 280 * Get the cursor row ID of the currently selected list item. 281 */ 282 public long getSelectedItemId() { 283 return mList.getSelectedItemId(); 284 } 285 286 /** 287 * Get the activity's list view widget. 288 */ 289 public ListView getListView() { 290 ensureList(); 291 return mList; 292 } 293 294 /** 295 * Get the ListAdapter associated with this activity's ListView. 296 */ 297 public ListAdapter getListAdapter() { 298 return mAdapter; 299 } 300 301 private void ensureList() { 302 if (mList != null) { 303 return; 304 } 305 setContentView(com.android.internal.R.layout.list_content); 306 307 } 308 309 private AdapterView.OnItemClickListener mOnClickListener = new AdapterView.OnItemClickListener() { 310 public void onItemClick(AdapterView parent, View v, int position, long id) 311 { 312 onListItemClick((ListView)parent, v, position, id); 313 } 314 }; 315} 316 317