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

אפשר לנסות את הדרך של כתיבת הודעה
‫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();

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