الخطوات الأولى

توضّح لك هذه الصفحة كيفية إعداد بيئتك وإنشاء شرائح في تطبيقك.

ملاحظة: يتضمّن الإصدار 3.2 من "استوديو Android" أو إصدار أحدث أدوات ووظائف إضافية يمكن أن تساعدك في تطوير شريحة:

  • أداة إعادة الهيكلة من AndroidX: مطلوبة إذا كنت تعمل في مشروع يستخدم مكتبات AndroidX.
  • عمليات التحقّق من الوبر في الشرائح: رصد الممارسات المضادة الشائعة عند إنشاء الشرائح
  • نموذج SliceProvider: يعالج النص النموذجي عند إنشاء SliceProvider.

تنزيل عارض الشرائح وتثبيته

نزِّل أحدث نموذج من إصدار APK Slice Viewer الذي يمكنك استخدامه لاختبار الشرائح بدون تنفيذ واجهة برمجة التطبيقات SliceView.

في حال عدم إعداد ADB بشكل صحيح في بيئتك، راجِع دليل ADB للحصول على مزيد من المعلومات.

ثبِّت Slice Viewer على جهازك من خلال تنفيذ الأمر التالي في الدليل نفسه مثل slice-viewer.apk الذي تم تنزيله:

adb install -r -t slice-viewer.apk

تشغيل عارض الشرائح

يمكنك تشغيل Slice Viewer إما من مشروع استوديو Android أو من سطر الأوامر:

تشغيل Slice Viewer من مشروع "استوديو Android"

  1. في مشروعك، اختَر تشغيل > تعديل الإعدادات...
  2. في أعلى اليمين، انقر على علامة الجمع الخضراء
  3. اختَر تطبيق Android.

  4. أدخِل شريحة في حقل الاسم.

  5. اختَر وحدة التطبيق في القائمة المنسدلة الوحدة.

  6. ضِمن خيارات التشغيل، اختَر عنوان URL من القائمة المنسدلة تشغيل.

  7. أدخِل slice-<your slice URI> في حقل عنوان URL.

    مثال: slice-content://com.example.your.sliceuri

  8. انقر على حسنًا.

تشغيل أداة Slice Viewer من خلال ADB (سطر الأوامر)

تشغيل تطبيقك من "استوديو Android":

adb install -t -r <yourapp>.apk

اعرض الشريحة عن طريق تشغيل الأمر التالي:

adb shell am start -a android.intent.action.VIEW -d slice-<your slice URI>

عارض شرائح يعرض شريحة Wi-Fi واحدة

عرض كل الشرائح في مكان واحد

بالإضافة إلى تشغيل شريحة واحدة، يمكنك عرض قائمة دائمة تشمل الشرائح.

  • استخدِم شريط البحث للبحث يدويًا عن الشرائح من خلال معرّف الموارد المنتظم (URI) (مثلاً content://com.example.android.app/hello). وفي كل مرة تبحث فيها، تتم إضافة الشريحة إلى القائمة.
  • في أي وقت يتم فيه تشغيل أداة "عارض الشرائح" باستخدام معرّف موارد منتظم (URI) لشريحة، تتم إضافة الشريحة إلى القائمة.
  • يمكنك تمرير شريحة بسرعة لإزالتها من القائمة.
  • انقر على معرّف الموارد المنتظم (URI) للشريحة لعرض صفحة تحتوي على تلك الشريحة فقط. له نفس تأثير تشغيل عارض الشريحة باستخدام معرف موارد منتظم (URI) لشريحة.

عارض شرائح يعرض قائمة بالشرائح

عرض الشريحة في أوضاع مختلفة

يمكن للتطبيق الذي يعرض شريحة تعديل SliceView#mode في وقت التشغيل، لذا يجب التأكّد من أنّ الشريحة تبدو كما هو متوقع في كل وضع. انقر على رمز القائمة في أعلى يسار الصفحة لتغيير الوضع.

عارض شرائح واحد مع ضبط الوضع على "صغير"

إنشاء أوّل شريحة

لإنشاء شريحة، افتح مشروع استوديو Android، وانقر بزر الماوس الأيمن على حزمة src، واختر جديد... > غير ذلك > موفِّر الشرائح. يؤدي ذلك إلى إنشاء فئة تمتد SliceProvider، وتضيف إدخال مقدّم الخدمة المطلوب إلى AndroidManifest.xml، وتعدّل build.gradle لإضافة تبعيات Slice المطلوبة.

يظهر أدناه تعديل 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 هذا. بعد ذلك، يعالج تطبيقك هذا الطلب وينشئ شريحة SIM ديناميكيًا من خلال طريقة onBindSlice. يمكن بعد ذلك عرض الشريحة على السطح عندما يكون ذلك مناسبًا.

في ما يلي مثال لطريقة 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 التي يمكنها تلقّي هذه الأهداف ومعالجتها:

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);
        }
    }
}

النماذج

تتوافق الشرائح مع مجموعة متنوعة من النماذج. للحصول على مزيد من التفاصيل حول خيارات النماذج والسلوكيات، اطّلع على النماذج.