Download presentation
Presentation is loading. Please wait.
1
ListView: Part 2
2
Emergency Contacts The slides in this section and the following section on content providers present four versions of an emergency contacts application that uses an SQLite database. The functionality and screens for all examples are exactly the same. The differences lie in how each version is implemente. ©SoftMoore Consulting
3
Emergency Contacts ©SoftMoore Consulting
4
Versions of the Emergency Contacts Application
Version 1: Uses an SQLite database and a modified ArrayAdapter. Version 2: Uses an SQLite database and a SimpleCursorAdapter. Version 3: Uses an SQLite database, a SimpleCursorAdapter, and a modified CursorLoader. Version 4: Uses a content provider, a CursorLoader, and a SimpleCursorAdapter. (Version 4 is postponed to section on content providers.) Versions 1 and 2 load the data into the ListView synchronously; i.e., the UI thread is blocked while the data is being loaded. (not suitable for large databases) Versions 3 and 4 use a CursorLoader to load the data asynchronously; i.e., the UI thread is not blocked while the data is being loaded. ©SoftMoore Consulting
5
Example: Emergency Contacts Version 1
Special considerations for this version: Implements an entity class for emergency contacts Uses extra helper methods in EmergencyDbOpenHelper Uses a custom array adapter to map values for name and phone number to the appropriate text views Using logic from previous slides for requesting permission to make a phone call ©SoftMoore Consulting
6
Example: Emergency Contacts Version 1 (Entity Class for Emergency Contacts)
public class EmergencyContact implements Serializable { private static final long serialVersionUID = ...; private long id; private String name; private String phoneNum; public EmergencyContact() this(-1, null, null); } public EmergencyContact(String name, String phoneNum) this(-1, name, phoneNum); (continued on next slide) ©SoftMoore Consulting
7
Example: Emergency Contacts Version 1 (Entity Class for Emergency Contacts – continued)
public EmergencyContact(long id, String name, String phoneNum) { this.id = id; this.name = name; this.phoneNum = phoneNum; } public long getId() return id; public void setId(long id) (continued on next slide) ©SoftMoore Consulting
8
Example: Emergency Contacts Version 1 (Entity Class for Emergency Contacts – continued)
... // other get/set methods for name and phoneNum ... // override methods from class Object such as // toString(), hashCode(), and equals() } ©SoftMoore Consulting
9
Example: Emergency Contacts Version 1 (EmergencyDbOpenHelper)
public class EmergencyDbOpenHelper extends SQLiteOpenHelper { ... public List<EmergencyContact> getAllContacts() SQLiteDatabase db = this.getReadableDatabase(); List<EmergencyContact> contacts = new ArrayList<>(20); String query = "select * from " + EmergencyDbContract.TABLE_NAME; Cursor cursor = db.rawQuery(query, null); (continued on next slide) ©SoftMoore Consulting
10
Example: Emergency Contacts Version 1 (EmergencyDbOpenHelper – continued)
while (cursor.moveToNext()) { int id = cursor.getInt(0); String name = cursor.getString(1); String phoneNum = cursor.getString(2); contacts.add(new EmergencyContact(id, name, phoneNum)); } cursor.close(); return contacts; (continued on next slide) ©SoftMoore Consulting
11
Example: Emergency Contacts Version 1 (EmergencyDbOpenHelper – continued)
public EmergencyContact insert(String name, String phoneNum) { // Note: no error checking SQLiteDatabase db = this.getWritableDatabase(); ContentValues values = new ContentValues(2); values.put(EmergencyDbContract.COLUMNS[1], name); values.put(EmergencyDbContract.COLUMNS[2], phoneNum); long id = db.insert(EmergencyDbContract.TABLE_NAME, null, values); EmergencyContact result = new EmergencyContact(id, name, phoneNum); db.close(); return result; } (continued on next slide) ©SoftMoore Consulting
12
Example: Emergency Contacts Version 1 (EmergencyDbOpenHelper – continued)
public void delete (EmergencyContact contact) { delete(contact.getId()); } public void delete (long id) // Note: no error checking SQLiteDatabase db = this.getWritableDatabase(); db.delete(EmergencyDbContract.TABLE_NAME, "_id = " + id, null); ©SoftMoore Consulting
13
Example: Emergency Contacts Version 1 (Layout for Each Item in the List)
<LinearLayout ... android:orientation="vertical" <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:textStyle="bold" /> /> </LinearLayout> ©SoftMoore Consulting
14
Example: Emergency Contacts Version 1 (Custom Array Adapter for Emergency Contacts)
/** * Custom array adapter to map emergency contacts to views. */ public class ContactAdapter extends ArrayAdapter<EmergencyContact> { public ContactAdapter(Context context, int layoutId, List<EmergencyContact> contacts) super(context, layoutId, contacts); public View getView(int position, View convertView, ViewGroup parent) // Get the data item for this position EmergencyContact contact = getItem(position); (continued on next slide) ©SoftMoore Consulting
15
Example: Emergency Contacts Version 1 (Custom Array Adapter – continued)
// Check if an existing view is being reused, // otherwise inflate the view if (convertView == null) { convertView = LayoutInflater.from(getContext()) .inflate(R.layout.contact_layout, parent, false); } // Look up views for data population TextView name = (TextView) convertView.findViewById(R.id.name); TextView phoneNum = (TextView) convertView.findViewById(R.id.phoneNum); name.setText(contact.getName()); phoneNum.setText(contact.getPhoneNum()); (continued on next slide) ©SoftMoore Consulting
16
Example: Emergency Contacts Version 1 (Custom Array Adapter – continued)
// Return the completed view to render on screen return convertView; } ©SoftMoore Consulting
17
Example: Emergency Contacts Version 1 (Main Activity)
public class MainActivity extends AppCompatActivity { ... private EmergencyDbOpenHelper openHelper; private List<EmergencyContact> contacts = new ArrayList<>(20); private ContactAdapter adapter; private ListView protected void onCreate(Bundle savedInstanceState) openHelper = new EmergencyDbOpenHelper(this); contacts = openHelper.getAllContacts(); (continued on next slide) ©SoftMoore Consulting
18
Example: Emergency Contacts Version 1 (Main Activity – continued)
adapter = new ContactAdapter(this, R.layout.contact_layout, contacts); lv.setAdapter(adapter); lv.setOnItemClickListener( new AdapterView.OnItemClickListener() public void onItemClick(AdapterView<?> parent, View view, int position, long id) EmergencyContact contact = (EmergencyContact) lv.getItemAtPosition(position); nameToCall = contact.getName(); phoneNumToCall = contact.getPhoneNum(); checkCallPhonePermission(); } }); (continued on next slide) ©SoftMoore Consulting
19
Example: Emergency Contacts Version 1 (Main Activity – continued)
lv.setOnItemLongClickListener( new AdapterView.OnItemLongClickListener() { // in the onClick listener for dialog's positive button EmergencyContact contact = (EmergencyContact) lv.getItemAtPosition(position); openHelper.delete(contact); contacts.remove(position); adapter.notifyDataSetChanged(); }); // in the onClick listener for the add button Intent intent = new Intent(MainActivity.this, AddContactActivity.class); startActivityForResult(intent, ADD_CONTACT_ACTIVITY); } (continued on next slide) ©SoftMoore Consulting
20
Example: Emergency Contacts Version 1 (Main Activity – continued)
@Override protected void onActivityResult(int requestCode, int resultCode, Intent intent) { if (requestCode == ADD_CONTACT_ACTIVITY && resultCode == RESULT_OK) EmergencyContact contact = (EmergencyContact) intent.getSerializableExtra("contact"); adapter.add(contact); adapter.notifyDataSetChanged(); } ©SoftMoore Consulting
21
Example: Emergency Contacts Version 1 (Second “Add Contact” Activity)
// in the onClick listener for the submit button EmergencyContact contact = addContact(); if (contact != null) { Intent intent = new Intent(); intent.putExtra("contact", contact); setResult(RESULT_OK, intent); finish(); } else String message = getString(R.string.emptyNameOrPhone); Toast toast = Toast.makeText(AddContactActivity.this, message, Toast.LENGTH_SHORT); toast.show(); defined on next slide (continued on next slide) ©SoftMoore Consulting
22
Example: Emergency Contacts Version 1 (Second “Add Contact” Activity – continued)
private EmergencyContact addContact() { EditText nameEditText = (EditText) findViewById(R.id.name); String name = nameEditText.getText().toString(); EditText phoneNumEditText = (EditText) findViewById(R.id.phoneNum); String phoneNum = phoneNumEditText.getText().toString(); if (name.length() > 0 && phoneNum.length() > 0) EmergencyDbOpenHelper openHelper = new EmergencyDbOpenHelper(this); EmergencyContact contact = openHelper.insert(name, phoneNum); openHelper.close(); return contact; } else return null; ©SoftMoore Consulting
23
Example: Emergency Contacts Version 2
Same layouts and screen shots as with Version 1 of Emergency Contacts Special considerations for this version: no entity class for emergency contacts fewer helper methods in EmergencyDbOpenHelper methods insert(String name, String phoneNum) and delete (long id) are retained other methods such as getAllContacts() are no longer required uses a SimpleCursorAdapter rather than an ArrayAdapter ©SoftMoore Consulting
24
Class SimpleCursorAdapter
Class CursorAdapter maps columns from a cursor to TextViews or ImageViews defined in an XML file. Class SimpleCursorAdapter is a subclass of CursorAdapter that is relatively simple and easy to use. To use a SimpleCursorAdapter, specify the columns from the cursor, the views to display the columns (e.g., TextViews), and the XML files that defines the appearance of these views (i.e., the default layout and the row layout). Note: The Cursor must include a column named "_id" or this class will not work. ©SoftMoore Consulting
25
Example: Emergency Contacts Version 2 (Main Activity)
... private static final String[] COLUMNS = { "name", "phone_num" }; private static final int[] VIEWS = { R.id.name, R.id.phoneNum }; private EmergencyDbOpenHelper openHelper; private SimpleCursorAdapter adapter; private ListView protected void onCreate(Bundle savedInstanceState) { lv = (ListView) findViewById(R.id.contactListView); lv.setEmptyView(findViewById(R.id.empty_list)); openHelper = new EmergencyDbOpenHelper(this); (continued on next slide) ©SoftMoore Consulting
26
Example: Emergency Contacts Version 2 (Main Activity – continued)
lv.setOnItemClickListener(new AdapterView.OnItemClickListener() public void onItemClick(AdapterView<?> parent, View view, int position, long id) ViewGroup vg = (ViewGroup) view; TextView nameView = (TextView) vg.getChildAt(0); nameToCall = nameView.getText().toString(); TextView phoneNumView = (TextView) vg.getChildAt(1); phoneNumToCall = phoneNumView.getText().toString(); checkCallPhonePermission(); } }); (continued on next slide) ©SoftMoore Consulting
27
Example: Emergency Contacts Version 2 (Main Activity – continued)
lv.setOnItemLongClickListener( new AdapterView.OnItemLongClickListener() { ... // in the onClick listener for dialog's positive button openHelper.delete(id); resetAdapter(); }); Button addButton = (Button)findViewById(R.id.addButton); addButton.setOnClickListener(new View.OnClickListener() ... // start AddContactActivity for result (continued on next slide) ©SoftMoore Consulting
28
Example: Emergency Contacts Version 2 (Main Activity – continued)
// Create an initially empty adapter adapter = new SimpleCursorAdapter(this, R.layout.contact_layout, null, COLUMNS, VIEWS, 0); lv.setAdapter(adapter); resetAdapter(); } these columns get mapped to these views ©SoftMoore Consulting
29
Example: Emergency Contacts Version 2 (Main Activity – continued)
private void resetAdapter() { try // get a cursor for the emergency contacts table String query = "select * from " + EmergencyDbContract.TABLE_NAME; SQLiteDatabase db = openHelper.getReadableDatabase(); Cursor cursor = db.rawQuery(query, null); adapter.changeCursor(cursor); } catch (Exception ex) String errorMsg = "Error ... "; Log.e(LOG_TAG, errorMsg, ex); ©SoftMoore Consulting
30
Example: Emergency Contacts Version 2 (Main Activity – continued)
@Override protected void onActivityResult(int requestCode, int resultCode, Intent intent) { if (requestCode == ADD_CONTACT_ACTIVITY && resultCode == RESULT_OK) resetAdapter(); } ©SoftMoore Consulting
31
Comments on Using a SimpleCursorAdapter
Note that method getCursor() returns three columns (_id, name, and phone_num) Not every column returned by the cursor needs to be mapped to a view; e.g., _id is not mapped to a view in this example. ©SoftMoore Consulting
32
Example: Emergency Contacts Version 2 (Second “Add Contact” Activity)
// in the onClick listener for the submit button EditText nameEditText = (EditText) findViewById(R.id.name); String name = nameEditText.getText().toString(); EditText phoneNumEditText = (EditText) findViewById(R.id.phoneNum); String phoneNum = phoneNumEditText.getText().toString(); if (name.length() > 0 && phoneNum.length() > 0) { EmergencyDbOpenHelper openHelper = new EmergencyDbOpenHelper(AddContactActivity.this); openHelper.insert(name, phoneNum); openHelper.close(); Intent intent = new Intent(); setResult(RESULT_OK, intent); finish(); } (continued on next slide) ©SoftMoore Consulting
33
Example: Emergency Contacts Version 2 (Second “Add Contact” Activity – continued)
else { String message = getString(R.string.emptyNameOrPhone); Toast toast = Toast.makeText(AddContactActivity.this, message, Toast.LENGTH_SHORT); toast.show(); } ©SoftMoore Consulting
34
Example: Emergency Contacts Version 3
Same layouts and screen shots as with Version 1 of Emergency Contacts Special considerations for this version: no entity class for emergency contacts fewer helper methods in EmergencyDbOpenHelper methods insert(String name, String phoneNum) and delete (long id) are retained other methods such as getAllContacts() are no longer required uses a SimpleCursorAdapter rather than an ArrayAdapter uses a custom CursorLoader ©SoftMoore Consulting
35
CursorLoader The “recommended” way to query a database cursor is to use a CursorLoader and to implement interface LoaderManager.LoaderCallbacks<Cursor>. Advantages of using CursorLoader and LoaderManager Data is loaded asynchronously – does not block the UI thread. The loader monitors the source of the data and delivers new results when the content changes. The loader automatically reconnects to the last loader’s cursor when being recreated after a configuration change; i.e., it does not need to re-query the data. However, … class CursorLoader was designed for use with a content provider, and some workarounds are required when using a database without a content provider. ©SoftMoore Consulting
36
Example: Emergency Contacts Version 3 (AbstractCustomCursorLoader)
public abstract class AbstractCustomCursorLoader extends CursorLoader { private final Loader.ForceLoadContentObserver mObserver = new Loader.ForceLoadContentObserver(); public AbstractCustomCursorLoader(Context context) super(context); public Cursor loadInBackground() Cursor cursor = getCursor(); (continued on next slide) ©SoftMoore Consulting
37
Example: Emergency Contacts Version 3 (AbstractCustomCursorLoader)
if (cursor != null) { // Ensure the cursor window is filled cursor.getCount(); cursor.registerContentObserver(mObserver); } cursor.setNotificationUri(getContext().getContentResolver(), getContentUri()); return cursor; protected abstract Cursor getCursor(); protected abstract Uri getContentUri(); (continued on next slide) ©SoftMoore Consulting
38
Using AbstractCustomCursorLoader
Two rules for using this class: Extend the abstract class and implement methods getCursor() and getContentUri(). Any time that the underlying database changes (e.g., after an insert or delete), make sure to call getContentResolver().notifyChange(myUri, null) where myUri is the same one returned from your implementation of method getContentUri(). ©SoftMoore Consulting
39
Example: Emergency Contacts Version 3 (EmergencyDbCursorLoader)
public class EmergencyDbCursorLoader extends AbstractCustomCursorLoader { private EmergencyDbOpenHelper openHelper; public EmergencyDbCursorLoader(Context context) super(context); openHelper = new EmergencyDbOpenHelper(context); } (continued on next slide) ©SoftMoore Consulting
40
Example: Emergency Contacts Version 3 (EmergencyDbCursorLoader – continued)
protected Cursor getCursor() { // get a cursor for the emergency contacts table String query = "select * from " + EmergencyDbContract.TABLE_NAME; SQLiteDatabase db = openHelper.getReadableDatabase(); Cursor cursor = db.rawQuery(query, null); return cursor; } protected Uri getContentUri() return EmergencyDbContract.CONTENT_URI; ©SoftMoore Consulting
41
Example: Emergency Contacts Version 3
Implementations for classes MainActivity and AddContactActivity are very similar to the Version 2 implementations. Summary of main differences for Version 3: Class MainActivity implements LoaderManager.LoaderCallbacks<Cursor> For the last line of onCreate() in the main activity Version 2 calls resetAdapter() Version 3 calls getLoaderManager().initLoader(0, null, this) When the data changes via database inserts or deletes Version 3 calls notifyDataSetChanged(). ©SoftMoore Consulting
42
Example: Emergency Contacts Version 3 (Main Activity)
public void notifyDataSetChanged() { getContentResolver(). notifyChange(EmergencyDbContract.CONTENT_URI, null); } // the next three methods implement public Loader<Cursor> onCreateLoader(int id, Bundle args) return new EmergencyDbCursorLoader(this); ©SoftMoore Consulting
43
Example: Emergency Contacts Version 3 (Main Activity – continued)
@Override public void onLoadFinished(Loader<Cursor> loader, Cursor data) { // swap in the cursor adapter.swapCursor(data); } public void onLoaderReset(Loader<Cursor> loader) adapter.swapCursor(null); ©SoftMoore Consulting
44
Relevant Links List View Loaders
Loaders Using Lists in Android with ListView – Tutorial Using and ArrayAdapter with ListView Making ListView Scrolling Smooth ©SoftMoore Consulting
Similar presentations
© 2025 SlidePlayer.com. Inc.
All rights reserved.