במדריך הזה תלמדו איך לאחזר פרטים של איש קשר, כמו כתובות אימייל, מספרי טלפון וכו'. אלו הפרטים שמשתמשים מחפשים כשהם מחפשים איש קשר. אתם יכולים לתת להם את כל הפרטים של איש הקשר, או להציג רק פרטים מסוג מסוים, כמו כתובות אימייל.
בשיעור הזה נניח שכבר יש לכם שורה ContactsContract.Contacts
של איש קשר שהמשתמש בחר.
במדריך אחזור שמות של אנשי קשר מוסבר איך מאחזרים רשימת אנשי קשר.
אחזור כל הפרטים של איש קשר
כדי לאחזר את כל הפרטים של איש קשר, מחפשים בטבלה ContactsContract.Data
שורות שמכילות את הערך של LOOKUP_KEY
של איש הקשר. העמודה הזו זמינה בטבלה ContactsContract.Data
כי ספק אנשי הקשר יוצר צירוף משתמע בין הטבלה ContactsContract.Contacts
לטבלה ContactsContract.Data
. תיאור מפורט יותר של העמודה LOOKUP_KEY
מופיע במדריך אחזור שמות של אנשי קשר.
הערה: אחזור כל הפרטים של איש קשר מפחית את הביצועים של
במכשיר, מכיוון שהוא צריך לאחזר את כל העמודות
טבלה ContactsContract.Data
. לפני שמשתמשים בשיטה הזו, חשוב להביא בחשבון את ההשפעה על הביצועים.
בקשת הרשאות
כדי לקרוא מ-Contacts Provider, לאפליקציה צריכה להיות ההרשאה READ_CONTACTS
.
כדי לבקש את ההרשאה הזו, מוסיפים לקובץ המניפסט את רכיב הצאצא הבא של
<manifest>
:
<uses-permission android:name="android.permission.READ_CONTACTS" />
הגדרת היטל
בהתאם לסוג הנתונים שכולל שורה מסוימת, ניתן לכלול בה רק מספר עמודות או מספר גדול של עמודות. In addition,
הנתונים מוצגים בעמודות שונות, בהתאם לסוג הנתונים.
כדי להבטיח שתקבלו את כל העמודות האפשריות לכל סוגי הנתונים האפשריים, צריך להוסיף את כל שמות העמודות להקרנה. אחזר תמיד
Data._ID
אם מתבצע קישור של התוצאה
Cursor
לListView
; אחרת, הקישור
לא יעבוד. אפשר גם לאחזר את השדה Data.MIMETYPE
כדי לזהות את סוג הנתונים של כל שורה שאוחזרה. לדוגמה:
Kotlin
private val PROJECTION: Array<out String> = arrayOf( ContactsContract.Data._ID, ContactsContract.Data.MIMETYPE, ContactsContract.Data.DATA1, ContactsContract.Data.DATA2, ContactsContract.Data.DATA3, ContactsContract.Data.DATA4, ContactsContract.Data.DATA5, ContactsContract.Data.DATA6, ContactsContract.Data.DATA7, ContactsContract.Data.DATA8, ContactsContract.Data.DATA9, ContactsContract.Data.DATA10, ContactsContract.Data.DATA11, ContactsContract.Data.DATA12, ContactsContract.Data.DATA13, ContactsContract.Data.DATA14, ContactsContract.Data.DATA15 )
Java
private static final String[] PROJECTION = { ContactsContract.Data._ID, ContactsContract.Data.MIMETYPE, ContactsContract.Data.DATA1, ContactsContract.Data.DATA2, ContactsContract.Data.DATA3, ContactsContract.Data.DATA4, ContactsContract.Data.DATA5, ContactsContract.Data.DATA6, ContactsContract.Data.DATA7, ContactsContract.Data.DATA8, ContactsContract.Data.DATA9, ContactsContract.Data.DATA10, ContactsContract.Data.DATA11, ContactsContract.Data.DATA12, ContactsContract.Data.DATA13, ContactsContract.Data.DATA14, ContactsContract.Data.DATA15 };
ההצגה הזו מאחזרת את כל העמודות של שורה בטבלה ContactsContract.Data
, באמצעות שמות העמודות שמוגדרים בכיתה ContactsContract.Data
.
לחלופין, ניתן גם להשתמש בקבועים אחרים של עמודות המוגדרים ב-
כיתה אחת (ContactsContract.Data
). עם זאת, חשוב לזכור שהעמודות SYNC1
עד SYNC4
מיועדות לשימוש במתאמי סנכרון, ולכן הנתונים שלהן לא שימושיים.
הגדרת הקריטריונים לבחירה
מגדירים קבוע לאופרטור הבחירה, מערך לארגון ארגומנטים של בחירה ומשתנה לאחסון ערך הבחירה. מחפשים את איש הקשר בעמודה Contacts.LOOKUP_KEY
. לדוגמה:
Kotlin
// Defines the selection clause private const val SELECTION: String = "${ContactsContract.Data.LOOKUP_KEY} = ?" ... // Defines the array to hold the search criteria private val selectionArgs: Array<String> = arrayOf("") /* * Defines a variable to contain the selection value. Once you * have the Cursor from the Contacts table, and you've selected * the desired row, move the row's LOOKUP_KEY value into this * variable. */ private var lookupKey: String? = null
Java
// Defines the selection clause private static final String SELECTION = Data.LOOKUP_KEY + " = ?"; // Defines the array to hold the search criteria private String[] selectionArgs = { "" }; /* * Defines a variable to contain the selection value. Once you * have the Cursor from the Contacts table, and you've selected * the desired row, move the row's LOOKUP_KEY value into this * variable. */ private lateinit var lookupKey: String
שימוש בתו '?' בתור placeholder בביטוי הטקסט שנבחר, מבטיח שהחיפוש שיוביל נוצר על ידי קישור ולא על ידי הידור SQL. הגישה הזו מבטלת את האפשרות של הזרקת SQL זדונית.
הגדרת סדר המיון
מגדירים את סדר המיון הרצוי ב-Cursor
שנוצר. כדי שכל השורות של סוג נתונים מסוים יישארו יחד, אפשר למיין לפי Data.MIMETYPE
. הארגומנט הזה של השאילתה מקבצ את כל שורות האימייל יחד, את כל שורות הטלפון יחד וכן הלאה. לדוגמה:
Kotlin
/* * Defines a string that specifies a sort order of MIME type */ private const val SORT_ORDER = ContactsContract.Data.MIMETYPE
Java
/* * Defines a string that specifies a sort order of MIME type */ private static final String SORT_ORDER = ContactsContract.Data.MIMETYPE;
הערה: סוגים מסוימים של נתונים לא משתמשים בתת-סוג, ולכן אי אפשר למיין לפי סוג משנה.
במקום זאת, צריך לחזור על הפעולה באמצעות ה-Cursor
שהוחזר,
לקבוע את סוג הנתונים של השורה הנוכחית ולאחסן נתונים עבור שורות שמשתמשות בתת-סוג. כשמסיימים לקרוא את הסמן, אפשר למיין כל סוג נתונים לפי תת-סוג ולהציג את התוצאות.
איך מפעילים את ה-Loader
תמיד לאחזר נתונים מספק אנשי הקשר (וכל ספקי התוכן האחרים)
שרשור ברקע. משתמשים במסגרת ה-Loader שהוגדרה על ידי
כיתה אחת (LoaderManager
) וגם
ממשק LoaderManager.LoaderCallbacks
לביצוע רקע
אחזורים.
כשתהיו מוכנים לאחזר את השורות, תוכלו להפעיל את מסגרת הטעינה באמצעות קריאה ל-initLoader()
. לעבור
מספר שלם ל-method; המזהה הזה מועבר אל
LoaderManager.LoaderCallbacks
אמצעי תשלום. המזהה עוזר לכם
להשתמש בכמה מטענים באפליקציה בכך שהוא מאפשר להבחין ביניהם.
קטע הקוד הבא מראה איך לאתחל את מסגרת הטעינה:
Kotlin
// Defines a constant that identifies the loader private const val DETAILS_QUERY_ID: Int = 0 class DetailsFragment : Fragment(), LoaderManager.LoaderCallbacks<Cursor> { ... override fun onCreate(savedInstanceState: Bundle?) { ... // Initializes the loader framework loaderManager.initLoader(DETAILS_QUERY_ID, null, this)
Java
public class DetailsFragment extends Fragment implements LoaderManager.LoaderCallbacks<Cursor> { ... // Defines a constant that identifies the loader static int DETAILS_QUERY_ID = 0; ... @Override public void onCreate(Bundle savedInstanceState) { ... // Initializes the loader framework getLoaderManager().initLoader(DETAILS_QUERY_ID, null, this);
הטמעה ב-onCreateLoader()
מטמיעים את השיטה onCreateLoader()
, שנקראת על ידי מסגרת הטעינה מיד אחרי שמפעילים את initLoader()
. מחזירים את הערך CursorLoader
מהשיטה הזו. מכיוון שאתם מחפשים בטבלה ContactsContract.Data
, צריך להשתמש בערך הקבוע Data.CONTENT_URI
כ-URI של התוכן.
לדוגמה:
Kotlin
override fun onCreateLoader(loaderId: Int, args: Bundle?): Loader<Cursor> { // Choose the proper action mLoader = when(loaderId) { DETAILS_QUERY_ID -> { // Assigns the selection parameter selectionArgs[0] = lookupKey // Starts the query activity?.let { CursorLoader( it, ContactsContract.Data.CONTENT_URI, PROJECTION, SELECTION, selectionArgs, SORT_ORDER ) } } ... } return mLoader }
Java
@Override public Loader<Cursor> onCreateLoader(int loaderId, Bundle args) { // Choose the proper action switch (loaderId) { case DETAILS_QUERY_ID: // Assigns the selection parameter selectionArgs[0] = lookupKey; // Starts the query CursorLoader mLoader = new CursorLoader( getActivity(), ContactsContract.Data.CONTENT_URI, PROJECTION, SELECTION, selectionArgs, SORT_ORDER ); }
הטמעת onLoadFinished() ו-onLoaderReset()
מטמיעים את השיטה onLoadFinished()
. תוכנת ה-framework של טעינה
onLoadFinished()
כשהספק של אנשי הקשר מחזיר את תוצאות השאילתה. לדוגמה:
Kotlin
override fun onLoadFinished(loader: Loader<Cursor>, data: Cursor) { when(loader.id) { DETAILS_QUERY_ID -> { /* * Process the resulting Cursor here. */ } ... } }
Java
@Override public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) { switch (loader.getId()) { case DETAILS_QUERY_ID: /* * Process the resulting Cursor here. */ } break; ... } }
השיטה onLoaderReset()
מופעלת כשמסגרת הטוענים מזהה שהנתונים שמגובים בתוצאה
Cursor
השתנה. בשלב הזה צריך להסיר את כל קובצי העזר הקיימים
ל-Cursor
על ידי הגדרת הערך כ-null. אם לא תעשו זאת, מסגרת הטעינה לא תהרוס את Cursor
הישן ותגרום לדליפת זיכרון. לדוגמה:
Kotlin
override fun onLoaderReset(loader: Loader<Cursor>) { when (loader.id) { DETAILS_QUERY_ID -> { /* * If you have current references to the Cursor, * remove them here. */ } ... } }
Java
@Override public void onLoaderReset(Loader<Cursor> loader) { switch (loader.getId()) { case DETAILS_QUERY_ID: /* * If you have current references to the Cursor, * remove them here. */ } break; }
אחזור פרטים ספציפיים של איש קשר
אחזור של סוג נתונים ספציפי של איש קשר, כמו כל הודעות האימייל, מתבצע באותו אופן כמו אחזור של כל הפרטים. אלה השינויים היחידים שצריך לבצע בקוד שמפורט בקטע אחזור כל הפרטים של איש קשר:
- תחזית
-
משנים את ההיטל כדי לאחזר את העמודות שספציפיות
סוג הנתונים. צריך גם לשנות את ההקרנה כך שתשתמש בערכי הקבועים של שמות העמודות שמוגדרים בתת-הסוג
ContactsContract.CommonDataKinds
שתואם לסוג הנתונים. - בחירה
-
משנים את טקסט הבחירה כדי לחפש את הערך
MIMETYPE
שספציפי לסוג הנתונים. - סדר מיון
-
מאחר שבחרת רק סוג פרטים אחד, אין לקבץ את המידע המוחזר
Cursor
עדData.MIMETYPE
.
השינויים האלה מתוארים בסעיפים הבאים.
הגדרת הקרנה
מגדירים את העמודות שרוצים לאחזר באמצעות הקבועים של שמות העמודות במחלקה המשנית
של ContactsContract.CommonDataKinds
לסוג הנתונים.
אם אתם מתכננים לקשר את Cursor
ל-ListView
, הקפידו לאחזר את העמודה _ID
. לדוגמה, כדי לאחזר נתוני אימייל, מגדירים את
התחזית הבאה:
Kotlin
private val PROJECTION: Array<String> = arrayOf( ContactsContract.CommonDataKinds.Email._ID, ContactsContract.CommonDataKinds.Email.ADDRESS, ContactsContract.CommonDataKinds.Email.TYPE, ContactsContract.CommonDataKinds.Email.LABEL )
Java
private static final String[] PROJECTION = { ContactsContract.CommonDataKinds.Email._ID, ContactsContract.CommonDataKinds.Email.ADDRESS, ContactsContract.CommonDataKinds.Email.TYPE, ContactsContract.CommonDataKinds.Email.LABEL };
שימו לב שההיטל הזה משתמש בשמות העמודות שהוגדרו במחלקה
ContactsContract.CommonDataKinds.Email
, במקום שמות העמודות
מוגדר במחלקה ContactsContract.Data
. באמצעות כתובות האימייל הספציפיות
שמות העמודות הופכים את הקוד לקריא יותר.
בהיטל, אפשר גם להשתמש בכל אחת מהעמודות האחרות שמוגדרות
תת-מחלקה אחת (ContactsContract.CommonDataKinds
).
הגדרת קריטריונים לבחירה
להגדיר ביטוי טקסט לחיפוש שמאחזר שורות של איש קשר ספציפי
LOOKUP_KEY
וגם
Data.MIMETYPE
מהפרטים
רוצה. צריך לתחום את הערך MIMETYPE
ב-
מירכאות בודדות באמצעות שרשור "'
" (מירכאות יחידות) בהתחלה ובסוף
של הקבוע; אחרת, הספק מפרש את הקבוע כשם משתנה
מאשר כערך מחרוזת. אין צורך להשתמש ב-placeholder לערך הזה, כי אתם משתמשים בערך קבוע ולא בערך שמשתמשים מספקים. לדוגמה:
Kotlin
/* * Defines the selection clause. Search for a lookup key * and the Email MIME type */ private const val SELECTION = "${ContactsContract.Data.LOOKUP_KEY} = ? AND " + "${ContactsContract.Data.MIMETYPE} = '${Email.CONTENT_ITEM_TYPE}'" ... // Defines the array to hold the search criteria private val selectionArgs: Array<String> = arrayOf("")
Java
/* * Defines the selection clause. Search for a lookup key * and the Email MIME type */ private static final String SELECTION = Data.LOOKUP_KEY + " = ?" + " AND " + Data.MIMETYPE + " = " + "'" + Email.CONTENT_ITEM_TYPE + "'"; // Defines the array to hold the search criteria private String[] selectionArgs = { "" };
הגדרה של סדר מיון
מגדירים סדר מיון ל-Cursor
שהוחזרו. מכיוון שאתם מאחזרים סוג נתונים ספציפי, צריך להשמיט את המיון לפי MIMETYPE
.
במקום זאת, אם סוג נתוני הפירוט שאתם מחפשים כולל תת-סוג, אפשר למיין לפיו.
לדוגמה, בנתוני אימייל אפשר למיין לפי Email.TYPE
:
Kotlin
private const val SORT_ORDER: String = "${Email.TYPE} ASC"
Java
private static final String SORT_ORDER = Email.TYPE + " ASC ";