בדף הזה נסביר איך להגדיר את הסביבה ולפתח פרוסות באפליקציה.
הערה: מערכת Android Studio 3.2 ואילך כוללת תכונות נוספות כלים ופונקציונליות שיכולים לעזור לכם בפיתוח Slices:
- כלי לארגון הקוד מחדש של AndroidX: נדרש אם עובדים בפרויקט משתמש בספריות AndroidX.
- בדיקות לאיתור שגיאות בקוד: זיהוי שיטות נגד שיטות נפוצות במהלך הבנייה פרוסות
- התבנית
SliceProvider
: מטפלת בתבנית הסטנדרטית כאשר בנייתSliceProvider
הורדה והתקנה של מציג הפרוסות
הורדת הדוגמה האחרונה
גרסת ה-APK של Slice Viewer
שאפשר להשתמש בה כדי לבדוק את הפרוסות בלי ליישם את
SliceView
API.
אם ADB לא מוגדר כראוי בסביבה שלך, קראו את מידע נוסף זמין במדריך ADB.
מתקינים את Slice Viewer במכשיר על ידי הרצת הפקודה הבאה ב
אותה ספרייה כמו הקובץ slice-viewer.apk
שהורדתם:
adb install -r -t slice-viewer.apk
הפעלה של מציג הפרוסות
אפשר להפעיל את 'צפייה בפרוסות' (Slice) מפרויקט Android Studio או דרך שורת הפקודה:
הפעלה של Slice Viewer מפרויקט Android Studio
- בפרויקט, בוחרים באפשרות Run > לעריכת ההגדרות האישיות...
- בפינה הימנית העליונה, לוחצים על סימן הפלוס הירוק
בוחרים באפשרות אפליקציה ל-Android.
מזינים slice בשדה השם
בוחרים את מודול האפליקציה בתפריט הנפתח מודול
בקטע Launch options (אפשרויות הפעלה), בוחרים באפשרות URL בתפריט הנפתח Launch (הפעלה).
מזינים את
slice-<your slice URI>
בשדה כתובת ה-URLדוגמה:
slice-content://com.example.your.sliceuri
לוחצים על אישור.
הפעלת הכלי Slice Viewer באמצעות ADB (שורת פקודה)
מפעילים את האפליקציה מ-Android Studio:
adb install -t -r <yourapp>.apk
כדי להציג את הפלח, מריצים את הפקודה הבאה:
adb shell am start -a android.intent.action.VIEW -d slice-<your slice URI>
מציג Wi-Fi מציג פלח אחד של Wi-Fi
הצגת כל הפרוסות במקום אחד
בנוסף להשקה של פרוסה אחת, אפשר להציג רשימה של כל פרוסות.
- אפשר להשתמש בסרגל החיפוש כדי לחפש באופן ידני את הפרוסות באמצעות URI (לדוגמה,
content://com.example.android.app/hello
). בכל פעם שמחפשים, הפלח נוספו לרשימה. - בכל פעם שמפעילים את הכלי 'צפייה בפרוסות' עם URI של פרוסה, הפרוסה תתווסף לרשימה.
- אפשר להחליק פרוסה כדי להסיר אותה מהרשימה.
- מקישים על ה-URI של הפלח כדי לראות דף שמכיל רק את הפלח הזה. זה כולל אותו אפקט כמו הפעלת Slice Viewer עם Slice URI.
מציג הפילוחים מציג רשימה של פרוסות
הצגת הפלח במצבים שונים
אפליקציה שמציגה פרוסה יכולה לשנות את
SliceView#mode
בזמן הריצה, לכן עליך לוודא שהפרוסה שלך נראית כצפוי בכל מצב.
כדי לשנות את המצב, לוחצים על סמל התפריט באזור השמאלי העליון של הדף.
צפייה בפורמט פרוסה יחיד במצב מוגדר כ'קטן'
בניית הפלח הראשון
כדי ליצור פרוסה, פותחים את פרויקט Android Studio ולוחצים לחיצה ימנית על src
חבילה, ובחר חדש... > אחר > ספק הפלחים. הפעולה הזו יוצרת כיתה
שאורכו SliceProvider
, מוסיף
רשומת הספק הנדרשת ב-AndroidManifest.xml
, ומשנה את
build.gradle
כדי להוסיף את יחסי התלות הנדרשים של פרוסות.
השינוי ב-AndroidManifest.xml
מוצג למטה:
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.android.app"> ... <application> ... <provider android:name="MySliceProvider" android:authorities="com.example.android.app" android:exported="true" > <intent-filter> <action android:name="android.intent.action.VIEW" /> <category android:name="android.app.slice.category.SLICE" /> </intent-filter> </provider> ... </application> </manifest>
יחסי התלות הבאים מתווספים ל-build.gradle
:
Kotlin
dependencies { // ... implementation "androidx.slice:slice-builders-ktx:(latest version)" // ... }
Java
dependencies { // ... implementation "androidx.slice:slice-builders:(latest version)" // ... }
לכל פרוסה יש URI משויך. כשמשטחים רוצים להציג פרוסה,
שולחת בקשת קישור לאפליקציה עם ה-URI הזה. לאחר מכן האפליקציה תטפל בבעיה
ותבנה את הפלח באופן דינמי דרך
onBindSlice
. לאחר מכן, המשטח יוכל להציג את הפלח במקרים הרלוונטיים.
בהמשך מוצגת דוגמה ל-method onBindSlice
שבודקת את ה-URI /hello
ומחזירה פלח של Hello World:
Kotlin
override fun onBindSlice(sliceUri: Uri): Slice? { val activityAction = createActivityAction() return if (sliceUri.path == "/hello") { list(context, sliceUri, ListBuilder.INFINITY) { row { primaryAction = activityAction title = "Hello World." } } } else { list(context, sliceUri, ListBuilder.INFINITY) { row { primaryAction = activityAction title = "URI not recognized." } } } }
Java
@Override public Slice onBindSlice(Uri sliceUri) { if (getContext() == null) { return null; } SliceAction activityAction = createActivityAction(); ListBuilder listBuilder = new ListBuilder(getContext(), sliceUri, ListBuilder.INFINITY); // Create parent ListBuilder. if ("/hello".equals(sliceUri.getPath())) { listBuilder.addRow(new ListBuilder.RowBuilder() .setTitle("Hello World") .setPrimaryAction(activityAction) ); } else { listBuilder.addRow(new ListBuilder.RowBuilder() .setTitle("URI not recognized") .setPrimaryAction(activityAction) ); } return listBuilder.build(); }
משתמשים בתצורת הרצת הפרוסות שיצרתם בקטע 'צפייה בפרוסות'
שלמעלה, העברת ה-URI של הפלח (לדוגמה,
slice-content://com.android.example.slicesample/hello
) של Hello World
פרוסות כדי להציג אותו במציג הפרוסות.
פרוסות אינטראקטיביות
בדומה להתראות, אפשר לטפל בקליקים בתוך הפלח על ידי צירוף
PendingIntent
אובייקטים שהם
מופעל בעקבות אינטראקציה של המשתמש. הדוגמה הבאה מפעילה
Activity
שיכול לקבל את האימיילים האלה ולטפל בהם
Intents:
Kotlin
fun createSlice(sliceUri: Uri): Slice { val activityAction = createActivityAction() return list(context, sliceUri, INFINITY) { row { title = "Perform action in app" primaryAction = activityAction } } } fun createActivityAction(): SliceAction { val intent = Intent(context, MainActivity::class.java) return SliceAction.create( PendingIntent.getActivity(context, 0, Intent(context, MainActivity::class.java), 0), IconCompat.createWithResource(context, R.drawable.ic_home), ListBuilder.ICON_IMAGE, "Enter app" ) }
Java
public Slice createSlice(Uri sliceUri) { if (getContext() == null) { return null; } SliceAction activityAction = createActivityAction(); return new ListBuilder(getContext(), sliceUri, ListBuilder.INFINITY) .addRow(new ListBuilder.RowBuilder() .setTitle("Perform action in app.") .setPrimaryAction(activityAction) ).build(); } public SliceAction createActivityAction() { if (getContext() == null) { return null; } return SliceAction.create( PendingIntent.getActivity( getContext(), 0, new Intent(getContext(), MainActivity.class), 0 ), IconCompat.createWithResource(getContext(), R.drawable.ic_home), ListBuilder.ICON_IMAGE, "Enter app" ); }
פרוסות תומכות גם בסוגי קלט אחרים, כמו מתגים, שכוללים של הכוונה שנשלחת לאפליקציה.
Kotlin
fun createBrightnessSlice(sliceUri: Uri): Slice { val toggleAction = SliceAction.createToggle( createToggleIntent(), "Toggle adaptive brightness", true ) return list(context, sliceUri, ListBuilder.INFINITY) { row { title = "Adaptive brightness" subtitle = "Optimizes brightness for available light" primaryAction = toggleAction } inputRange { inputAction = (brightnessPendingIntent) max = 100 value = 45 } } } fun createToggleIntent(): PendingIntent { val intent = Intent(context, MyBroadcastReceiver::class.java) return PendingIntent.getBroadcast(context, 0, intent, 0) }
Java
public Slice createBrightnessSlice(Uri sliceUri) { if (getContext() == null) { return null; } SliceAction toggleAction = SliceAction.createToggle( createToggleIntent(), "Toggle adaptive brightness", true ); ListBuilder listBuilder = new ListBuilder(getContext(), sliceUri, ListBuilder.INFINITY) .addRow(new ListBuilder.RowBuilder() .setTitle("Adaptive brightness") .setSubtitle("Optimizes brightness for available light.") .setPrimaryAction(toggleAction) ).addInputRange(new ListBuilder.InputRangeBuilder() .setInputAction(brightnessPendingIntent) .setMax(100) .setValue(45) ); return listBuilder.build(); } public PendingIntent createToggleIntent() { Intent intent = new Intent(getContext(), MyBroadcastReceiver.class); return PendingIntent.getBroadcast(getContext(), 0, intent, 0); }
המקבל יכול לבדוק את המצב שהוא מקבל:
Kotlin
class MyBroadcastReceiver : BroadcastReceiver() { override fun onReceive(context: Context, intent: Intent) { if (intent.hasExtra(Slice.EXTRA_TOGGLE_STATE)) { Toast.makeText(context, "Toggled: " + intent.getBooleanExtra( Slice.EXTRA_TOGGLE_STATE, false), Toast.LENGTH_LONG).show() } } companion object { const val EXTRA_MESSAGE = "message" } }
Java
public class MyBroadcastReceiver extends BroadcastReceiver { public static String EXTRA_MESSAGE = "message"; @Override public void onReceive(Context context, Intent intent) { if (intent.hasExtra(EXTRA_TOGGLE_STATE)) { Toast.makeText(context, "Toggled: " + intent.getBooleanExtra( EXTRA_TOGGLE_STATE, false), Toast.LENGTH_LONG).show(); } } }
פרוסות דינמיות
פרוסות יכולות גם להכיל תוכן דינמי. בדוגמה הבאה, עכשיו הפלח כולל את מספר השידורים שהתקבלו בתוכן שלו:
Kotlin
fun createDynamicSlice(sliceUri: Uri): Slice { return when (sliceUri.path) { "/count" -> { val toastAndIncrementAction = SliceAction.create( createToastAndIncrementIntent("Item clicked."), actionIcon, ListBuilder.ICON_IMAGE, "Increment." ) list(context, sliceUri, ListBuilder.INFINITY) { row { primaryAction = toastAndIncrementAction title = "Count: ${MyBroadcastReceiver.receivedCount}" subtitle = "Click me" } } } else -> { list(context, sliceUri, ListBuilder.INFINITY) { row { primaryAction = createActivityAction() title = "URI not found." } } } } }
Java
public Slice createDynamicSlice(Uri sliceUri) { if (getContext() == null || sliceUri.getPath() == null) { return null; } ListBuilder listBuilder = new ListBuilder(getContext(), sliceUri, ListBuilder.INFINITY); switch (sliceUri.getPath()) { case "/count": SliceAction toastAndIncrementAction = SliceAction.create( createToastAndIncrementIntent("Item clicked."), actionIcon, ListBuilder.ICON_IMAGE, "Increment." ); listBuilder.addRow( new ListBuilder.RowBuilder() .setPrimaryAction(toastAndIncrementAction) .setTitle("Count: " + MyBroadcastReceiver.sReceivedCount) .setSubtitle("Click me") ); break; default: listBuilder.addRow( new ListBuilder.RowBuilder() .setPrimaryAction(createActivityAction()) .setTitle("URI not found.") ); break; } return listBuilder.build(); } public PendingIntent createToastAndIncrementIntent(String s) { Intent intent = new Intent(getContext(), MyBroadcastReceiver.class) .putExtra(MyBroadcastReceiver.EXTRA_MESSAGE, s); return PendingIntent.getBroadcast(getContext(), 0, intent, 0); }
בדוגמה הזאת, כשהספירה מוצגת, היא לא מתעדכנת מעצמו. אפשר
לשנות את מקלט השידורים כדי להודיע למערכת על כך שבוצע שינוי
באמצעות
ContentResolver#notifyChange
Kotlin
class MyBroadcastReceiver : BroadcastReceiver() { override fun onReceive(context: Context, intent: Intent) { if (intent.hasExtra(Slice.EXTRA_TOGGLE_STATE)) { Toast.makeText( context, "Toggled: " + intent.getBooleanExtra( Slice.EXTRA_TOGGLE_STATE, false ), Toast.LENGTH_LONG ).show() receivedCount++; context.contentResolver.notifyChange(sliceUri, null) } } companion object { var receivedCount = 0 val sliceUri = Uri.parse("content://com.android.example.slicesample/count") const val EXTRA_MESSAGE = "message" } }
Java
public class MyBroadcastReceiver extends BroadcastReceiver { public static int sReceivedCount = 0; public static String EXTRA_MESSAGE = "message"; private static Uri sliceUri = Uri.parse("content://com.android.example.slicesample/count"); @Override public void onReceive(Context context, Intent intent) { if (intent.hasExtra(EXTRA_TOGGLE_STATE)) { Toast.makeText(context, "Toggled: " + intent.getBooleanExtra( EXTRA_TOGGLE_STATE, false), Toast.LENGTH_LONG).show(); sReceivedCount++; context.getContentResolver().notifyChange(sliceUri, null); } } }
תבניות
הפרוסות תומכות במגוון תבניות. לפרטים נוספים על האפשרויות של תבניות בתבניות.