Presentation is loading. Please wait.

Presentation is loading. Please wait.

ListView: Part 2.

Similar presentations


Presentation on theme: "ListView: Part 2."— Presentation transcript:

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


Download ppt "ListView: Part 2."

Similar presentations


Ads by Google