הוספת הצעות לחיפוש בהתאמה אישית

כדאי לנסות את הדרך של כתיבת אימייל
‫Jetpack Compose היא ערכת הכלים המומלצת לבניית ממשק משתמש ל-Android. כך מוסיפים פונקציית חיפוש בכלי הכתיבה.

אתם יכולים לספק הצעות לחיפוש על סמך שאילתות חיפוש אחרונות בתיבת הדו-שיח של החיפוש ב-Android או בווידג'ט החיפוש. לדוגמה, אם משתמש מחפש "גורים", השאילתה מופיעה כהצעה כשהוא מקליד את אותה שאילתה שוב. איור 1 מציג דוגמה לתיבת דו-שיח של חיפוש עם הצעות לשאילתות אחרונות.

לפני שמתחילים, מטמיעים את תיבת הדו-שיח של החיפוש או ווידג'ט חיפוש לחיפושים בסיסיים באפליקציה. במאמר יצירת ממשק חיפוש מוסבר איך עושים את זה.

העקרונות הבסיסיים

איור 1. צילום מסך של תיבת דו-שיח לחיפוש עם הצעות לשאילתות מהזמן האחרון.

הצעות לשאילתות אחרונות הן חיפושים שמורים. כשהמשתמש בוחר הצעה, הפעילות שניתן לחפש בה מקבלת ACTION_SEARCH כוונה עם ההצעה בתור שאילתת החיפוש שהפעילות שניתן לחפש בה כבר מטפלת בה.

כדי לספק הצעות לשאילתות אחרונות, צריך:

  • הטמעה של פעילות שאפשר לחפש בה.
  • יוצרים ספק תוכן שמרחיב את SearchRecentSuggestionsProvider ומצהירים עליו במניפסט של האפליקציה.
  • משנים את ההגדרה שאפשר לחפש בה עם מידע על ספק התוכן שמספק הצעות לחיפוש.
  • שמירת שאילתות אצל ספק התוכן בכל פעם שמבצעים חיפוש.

מערכת Android מציגה את תיבת הדו-שיח של החיפוש, וגם את הצעות החיפוש מתחת לתיבת הדו-שיח או לווידג'ט החיפוש. אתם מספקים את המקור שממנו המערכת מאחזרת את ההצעות.

כשהמערכת מזהה שהפעילות שלכם ניתנת לחיפוש ומציעה הצעות לחיפוש, קורה הדבר הבא כשמשתמש מקליד שאילתה:

  1. המערכת לוקחת את הטקסט של שאילתת החיפוש – כל מה שהמשתמש מתחיל להקליד – ומבצעת שאילתה לספק התוכן שמכילה את ההצעות שלכם.
  2. ספק התוכן מחזיר Cursor שמצביע על כל ההצעות שתואמות לטקסט של שאילתת החיפוש.
  3. המערכת מציגה את רשימת ההצעות שסופקו על ידי Cursor.

אחרי שההצעות לשאילתות האחרונות מוצגות, יכול להיות שיקרו הדברים הבאים:

  • אם המשתמש מקליד מקש אחר או משנה את השאילתה בכל דרך שהיא, השלבים הקודמים חוזרים על עצמם ורשימת ההצעות מתעדכנת.
  • אם המשתמש מבצע את החיפוש, המערכת מתעלמת מההצעות ומעבירה את החיפוש לפעילות שאפשר לחפש בה באמצעות הכוונה הרגילה ACTION_SEARCH.
  • אם המשתמש בוחר הצעה, מתבצעת פעולה מסוג ACTION_SEARCH בחיפוש הפעילות, והטקסט המוצע משמש כשאילתה.

המחלקות SearchRecentSuggestionsProvider שמרחיבים עבור ספק התוכן מבצעות את העבודה באופן אוטומטי בשלבים הקודמים, כך שאין הרבה קוד לכתוב.

יצירת ספק תוכן

ספק התוכן שנדרש להצעות לשאילתות האחרונות הוא הטמעה של SearchRecentSuggestionsProvider. הכיתה הזו עושה הכול בשבילכם. צריך רק לכתוב בנאי של מחלקה שמבצע שורה אחת של קוד.

לדוגמה, הנה הטמעה מלאה של ספק תוכן להצעות של שאילתות אחרונות:

Kotlin

class MySuggestionProvider : SearchRecentSuggestionsProvider() {
    init {
        setupSuggestions(AUTHORITY, MODE)
    }

    companion object {
        const val AUTHORITY = "com.example.MySuggestionProvider"
        const val MODE: Int = SearchRecentSuggestionsProvider.DATABASE_MODE_QUERIES
    }
}

Java

public class MySuggestionProvider extends SearchRecentSuggestionsProvider {
    public final static String AUTHORITY = "com.example.MySuggestionProvider";
    public final static int MODE = DATABASE_MODE_QUERIES;

    public MySuggestionProvider() {
        setupSuggestions(AUTHORITY, MODE);
    }
}

הקריאה אל setupSuggestions() מעבירה את השם של רשות החיפוש ואת מצב מסד הנתונים. רשות החיפוש יכולה להיות כל מחרוזת ייחודית, אבל מומלץ להשתמש בשם שמוגדר במלואו לספק התוכן, כמו שם החבילה ואחריו שם המחלקה של הספק. לדוגמה, "com.example.MySuggestionProvider".

מצב מסד הנתונים חייב לכלול את DATABASE_MODE_QUERIES, ויכול לכלול גם את DATABASE_MODE_2LINES, שמוסיף עמודה לטבלת ההצעות כדי שתוכלו לספק שורה שנייה של טקסט לכל הצעה. אם רוצים לספק שתי שורות בכל הצעה, אפשר לעיין בדוגמה הבאה:

Kotlin

const val MODE: Int = DATABASE_MODE_QUERIES or DATABASE_MODE_2LINES

Java

public final static int MODE = DATABASE_MODE_QUERIES | DATABASE_MODE_2LINES;

מצהירים על ספק התוכן במניפסט של האפליקציה באמצעות אותו מחרוזת הרשאות שבה השתמשתם במחלקה SearchRecentSuggestionsProvider ובאפשרות ההגדרה שאפשר לחפש בה. לדוגמה:

<application>
    <provider android:name=".MySuggestionProvider"
              android:authorities="com.example.MySuggestionProvider" />
    ...
</application>

שינוי ההגדרה של מה שאפשר לחפש

כדי להגדיר את המערכת כך שתשתמש בספק ההצעות שלכם, מוסיפים את המאפיינים android:searchSuggestAuthority ו-android:searchSuggestSelection לרכיב <searchable> בקובץ ההגדרות שניתן לחיפוש. לדוגמה:

<?xml version="1.0" encoding="utf-8"?>
<searchable xmlns:android="http://schemas.android.com/apk/res/android"
    android:label="@string/app_label"
    android:hint="@string/search_hint"
    android:searchSuggestAuthority="com.example.MySuggestionProvider"
    android:searchSuggestSelection=" ?" >
</searchable>

הערך של android:searchSuggestAuthority צריך להיות שם מלא של ספק התוכן, שזהה בדיוק לסמכות שמשמשת את ספק התוכן, כמו "com.example.MySuggestionProvider" בדוגמאות הקודמות.

הערך של android:searchSuggestSelection חייב להיות סימן שאלה יחיד עם רווח לפניו: " ?". זהו placeholder לארגומנט הבחירה של SQLite, והוא מוחלף אוטומטית בטקסט השאילתה שהמשתמש הזין.

שמירת שאילתות

כדי לאכלס את האוסף של השאילתות האחרונות, מוסיפים כל שאילתה שהתקבלה על ידי הפעילות שניתנת לחיפוש אל SearchRecentSuggestionsProvider. כדי לעשות זאת, יוצרים מופע של SearchRecentSuggestions ומבצעים קריאה ל-saveRecentQuery() בכל פעם שמתקבלת שאילתה לגבי פעילות שאפשר לחפש. לדוגמה, כך אפשר לשמור את השאילתה במהלך הפעילות בשיטה onCreate():

Kotlin

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.main)

    if (Intent.ACTION_SEARCH == intent.action) {
        intent.getStringExtra(SearchManager.QUERY)?.also { query ->
            SearchRecentSuggestions(this, MySuggestionProvider.AUTHORITY, MySuggestionProvider.MODE)
                    .saveRecentQuery(query, null)
        }
    }
}

Java

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    Intent intent  = getIntent();

    if (Intent.ACTION_SEARCH.equals(intent.getAction())) {
        String query = intent.getStringExtra(SearchManager.QUERY);
        SearchRecentSuggestions suggestions = new SearchRecentSuggestions(this,
                MySuggestionProvider.AUTHORITY, MySuggestionProvider.MODE);
        suggestions.saveRecentQuery(query, null);
    }
}

הבנאי SearchRecentSuggestionsProvider דורש את אותה הרשאה ואת אותו מצב מסד נתונים שהוגדרו על ידי ספק התוכן.

השיטה saveRecentQuery() מקבלת את מחרוזת שאילתת החיפוש כפרמטר הראשון ובאופן אופציונלי, מחרוזת שנייה שתצורף כשורה השנייה של ההצעה או null. הפרמטר השני משמש רק אם מפעילים את מצב שתי השורות להצעות לחיפוש באמצעות DATABASE_MODE_2LINES. אם מפעילים את מצב שתי השורות, הטקסט של השאילתה מושווה לשורה השנייה כשהמערכת מחפשת הצעות תואמות.

מחיקת נתוני ההצעה

כדי להגן על פרטיות המשתמש, תמיד צריך לספק למשתמש דרך למחוק את הצעות השאילתות האחרונות. כדי לנקות את היסטוריית השאילתות, קוראים ל-clearHistory(). לדוגמה:

Kotlin

SearchRecentSuggestions(this, HelloSuggestionsProvider.AUTHORITY, HelloSuggestionsProvider.MODE)
        .clearHistory()

Java

SearchRecentSuggestions suggestions = new SearchRecentSuggestions(this,
        HelloSuggestionProvider.AUTHORITY, HelloSuggestionProvider.MODE);
suggestions.clearHistory();

מבצעים את הפעולה הזו מתוך פריט בתפריט, פריט בהעדפות או לחצן לבחירתכם שנקרא 'מחיקת היסטוריית החיפושים'. צריך לספק תיבת דו-שיח לאישור כדי לוודא שהמשתמש רוצה למחוק את היסטוריית החיפושים שלו.