เริ่มต้นใช้งาน

หน้านี้จะแสดงวิธีตั้งค่าสภาพแวดล้อมและบิลด์ ส่วนแบ่งในแอป

หมายเหตุ: Android Studio 3.2 ขึ้นไปมี เครื่องมือและฟังก์ชันที่จะช่วยคุณพัฒนา Slice ได้

  • เครื่องมือเปลี่ยนโครงสร้างภายในโค้ด AndroidX: จำเป็นหากคุณกำลังทำงานในโปรเจ็กต์ที่ ใช้ไลบรารี AndroidX
  • Slices Lint Check: พบแนวทางปฏิบัติทั่วไปในการต่อต้านเมื่อสร้าง แบ่งเป็นช่องๆ
  • เทมเพลต SliceProvider: จัดการต้นแบบเมื่อ การสร้าง SliceProvider

ดาวน์โหลดและติดตั้ง Slice Viewer

ดาวน์โหลดตัวอย่างล่าสุด รุ่น APK ของ Slice Viewer ที่คุณสามารถใช้เพื่อทดสอบ Slice โดยไม่ต้องติดตั้ง SliceView API

หาก ADB ไม่ได้รับการตั้งค่าอย่างถูกต้องในสภาพแวดล้อมของคุณ โปรดดู ดูข้อมูลเพิ่มเติมได้ที่คู่มือ AADB

ติดตั้ง Slice Viewer บนอุปกรณ์ของคุณโดยเรียกใช้คำสั่งต่อไปนี้ใน ไดเรกทอรีเดียวกันกับ slice-viewer.apk ที่ดาวน์โหลดไว้:

adb install -r -t slice-viewer.apk

เรียกใช้โปรแกรมดู Slice

คุณเปิดใช้ Slice Viewer จากโปรเจ็กต์ Android Studio หรือจาก บรรทัดคำสั่งดังนี้

เปิด Slice Viewer จากโปรเจ็กต์ Android Studio ของคุณ

  1. เลือก Run > (เรียกใช้) ในโปรเจ็กต์ แก้ไขการกำหนดค่า...
  2. คลิกเครื่องหมายบวกสีเขียวที่มุมซ้ายบน
  3. เลือกแอป Android

  4. ป้อนส่วนแบ่งในช่องชื่อ

  5. เลือกโมดูลแอปในเมนูแบบเลื่อนลงโมดูล

  6. ในส่วนตัวเลือกการเปิดตัว ให้เลือก URL จากเมนูแบบเลื่อนลงการเปิดตัว

  7. ป้อน slice-<your slice URI> ในช่อง URL

    ตัวอย่าง: slice-content://com.example.your.sliceuri

  8. คลิกตกลง

เปิดเครื่องมือ Slice Viewer ผ่าน ADB (บรรทัดคำสั่ง)

เรียกใช้แอปจาก Android Studio โดยทำดังนี้

adb install -t -r <yourapp>.apk

ดู Slice โดยเรียกใช้คำสั่งต่อไปนี้

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

Slice Viewer ที่แสดงเครือข่าย Wi-Fi เดี่ยว

ดูส่วนแบ่งทั้งหมดของคุณในที่เดียว

นอกจากการเปิดตัวเพียงส่วนเดียวแล้ว คุณยังสามารถดูรายการถาวรของ แบ่งช่อง

  • ใช้แถบค้นหาเพื่อค้นหาสไลซ์ของคุณผ่าน URI ด้วยตนเอง (เช่น content://com.example.android.app/hello) ทุกครั้งที่คุณค้นหา Slice เพิ่มลงในรายการแล้ว
  • เมื่อใดก็ตามที่คุณเปิดเครื่องมือดูส่วนแบ่งด้วย URI ส่วนแบ่ง ระบบจะเพิ่มส่วนแบ่งดังกล่าว ลงในรายการ
  • คุณสามารถปัดสไลซ์เพื่อนำออกจากรายการ
  • แตะ URI ของส่วนเพื่อดูหน้าเว็บที่มีเฉพาะสไลซ์ดังกล่าว มี ซึ่งจะส่งผลเหมือนกับการเปิด Slice Viewer ด้วย URI Slice

Slice Viewer ที่แสดงรายการสไลซ์

ดูสไลซ์ในโหมดต่างๆ

แอปที่นำเสนอสไลซ์สามารถแก้ไข SliceView#mode ขณะรันไทม์ ดังนั้นคุณควรตรวจสอบว่า Slice มีลักษณะตามที่คาดไว้ในแต่ละโหมด เลือกไอคอนเมนูที่บริเวณด้านขวาบนของหน้าเพื่อเปลี่ยนโหมด

โปรแกรมดูส่วนแบ่งเดี่ยวที่ตั้งค่าโหมดเป็น "เล็ก"

สร้าง Slice แรกของคุณ

หากต้องการสร้าง Slice ให้เปิดโปรเจ็กต์ Android Studio แล้วคลิกขวาที่ src แพ็กเกจ แล้วเลือก ใหม่... อื่นๆ > Slice Provider การดำเนินการนี้จะสร้างชั้นเรียน ที่ขยาย SliceProvider ให้เพิ่ม ป้อนข้อมูลผู้ให้บริการที่จำเป็นลงใน AndroidManifest.xml ของคุณและแก้ไข build.gradle เพื่อเพิ่มทรัพยากร Dependency ของ 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>

เพิ่มทรัพยากร Dependency ต่อไปนี้ไปยัง build.gradle แล้ว

Kotlin

dependencies {
// ...
    implementation "androidx.slice:slice-builders-ktx:(latest version)"
// ...
}

Java

dependencies {
// ...
    implementation "androidx.slice:slice-builders:(latest version)"
// ...
}

แต่ละส่วนมี URI ที่เชื่อมโยงอยู่ เมื่อพื้นผิวต้องการแสดงสไลซ์ ส่งคำขอการเชื่อมโยงไปยังแอปของคุณด้วย URI นี้ จากนั้นแอปของคุณจะจัดการเรื่องนี้ และสร้าง Slice แบบไดนามิกผ่าน 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();
}

ใช้การกำหนดค่าการเรียกใช้ Slice ซึ่งคุณสร้างไว้ในส่วน Slice Viewer ข้างต้น การส่งผ่านใน URI ของ Slice (เช่น slice-content://com.android.example.slicesample/hello) ของ Hello World Slice เพื่อดูใน Slice Viewer

สไลซ์แบบอินเทอร์แอกทีฟ

เช่นเดียวกับการแจ้งเตือน คุณสามารถจัดการการคลิกใน Slice ได้โดยแนบ PendingIntent ออบเจ็กต์ที่ เมื่อมีการโต้ตอบของผู้ใช้ ตัวอย่างด้านล่างเริ่ม Activity ที่รับและจัดการไฟล์เหล่านั้นได้ Intent:

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

Slice ยังรองรับอินพุตประเภทอื่นๆ ด้วย เช่น ปุ่มสลับ ซึ่งมีสถานะใน Intent ที่ส่งไปยังแอป

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

ส่วนแบ่งแบบไดนามิก

สไลซ์อาจมีเนื้อหาแบบไดนามิกได้เช่นกัน ในตัวอย่างต่อไปนี้ Slice ในตอนนี้ รวมจำนวนการออกอากาศที่ได้รับในเนื้อหา ได้แก่

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

ในตัวอย่างนี้ ขณะที่จำนวนแสดงอยู่ จำนวนจะไม่อัปเดตเอง คุณสามารถ แก้ไข Broadcast Receiver ของคุณเพื่อแจ้งระบบว่ามีการเปลี่ยนแปลง โดยใช้ 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);
        }
    }
}

เทมเพลต

Slices รองรับเทมเพลตที่หลากหลาย สำหรับรายละเอียดเพิ่มเติมเกี่ยวกับตัวเลือกเทมเพลตและ ลักษณะการทำงาน โปรดดูที่เทมเพลต