การส่งผู้ใช้ไปยังแอปอื่น

ฟีเจอร์ที่สำคัญที่สุดอย่างหนึ่งของ Android คือความสามารถของแอปในการส่งผู้ใช้ไปยังแอปอื่น อิงตาม "การกระทำ" ที่อยากจะทำ ตัวอย่างเช่น หาก แอปของคุณมีที่อยู่ของธุรกิจที่คุณต้องการให้แสดงบนแผนที่ คุณไม่จำเป็นต้องสร้าง กิจกรรมที่แสดงแผนที่ในแอป แต่คุณสามารถสร้างคำขอเพื่อดูที่อยู่แทนได้ โดยใช้ Intent จากนั้น ระบบ Android จะเริ่มต้นแอปที่สามารถแสดง ที่อยู่บนแผนที่

ตามที่ได้อธิบายไว้ในชั้นเรียนแรก อาคาร แอปแรกของคุณ คุณต้องใช้ Intent เพื่อสลับไปมาระหว่างกิจกรรมต่างๆ ในแอปของคุณเอง คุณ มักจะทำเช่นนั้นด้วยIntent แบบเจาะจงปลายทาง ซึ่งจะระบุชื่อคลาสที่แน่นอนของ คอมโพเนนต์ที่คุณจะเริ่มต้น แต่เมื่อคุณต้องการมีแอปอีกแอปหนึ่ง ให้ดำเนินการบางอย่าง เช่น เช่น "ดูแผนที่" คุณต้องใช้Intent แบบไม่เจาะจงปลายทาง

บทเรียนนี้แสดงวิธีการสร้างความตั้งใจโดยปริยายสำหรับการกระทำบางอย่างและวิธีใช้งาน เพื่อเริ่มกิจกรรมที่เป็นการดำเนินการในแอปอื่น ดูวิดีโอที่ฝังที่นี่ด้วย เพื่อให้เข้าใจเหตุผลที่คุณต้องรวมการตรวจสอบรันไทม์สำหรับ Intent แบบไม่เจาะจงปลายทางด้วย

สร้าง Intent แบบไม่เจาะจงปลายทาง

Intent แบบไม่เจาะจงปลายทางจะไม่ประกาศชื่อคลาสของคอมโพเนนต์เพื่อเริ่มต้น แต่จะประกาศแทน ในการทำงาน การดำเนินการจะระบุสิ่งที่คุณต้องการทำ เช่น view แก้ไข ส่ง หรือรับเนื้อหา

เชื่อมโยงการดำเนินการผ่าน Intent กับข้อมูล

Intent มักมีข้อมูลที่เกี่ยวข้องด้วย เช่น ที่อยู่ที่ต้องการดู หรือข้อความอีเมลที่ต้องการส่ง ข้อมูลอาจเป็น Uri ทั้งนี้ขึ้นอยู่กับ Intent ที่คุณต้องการสร้าง ประเภทข้อมูลอีกประเภทหนึ่ง หรือเจตนาอาจไม่จำเป็นต้องใช้ข้อมูลเลย

ถ้าข้อมูลของคุณเป็น Uri คุณสามารถใช้ตัวสร้าง Intent() ง่ายๆ เพื่อตั้งการทำงานและ

ตัวอย่างเช่น วิธีสร้างความตั้งใจเพื่อเริ่มต้นการโทรโดยใช้ข้อมูล Uri เพื่อระบุหมายเลขโทรศัพท์มีดังนี้

Kotlin

val callIntent: Intent = Uri.parse("tel:5551234").let { number ->
    Intent(Intent.ACTION_DIAL, number)
}

Java

Uri number = Uri.parse("tel:5551234");
Intent callIntent = new Intent(Intent.ACTION_DIAL, number);

เมื่อแอปเรียกใช้ Intent นี้ด้วยการโทร startActivity() แอป "โทรศัพท์" จะเริ่มโทรหาหมายเลขโทรศัพท์ที่ระบุไว้

นี่คือ Intent อีก 2 รายการ รวมถึงการดำเนินการและข้อมูล Uri คู่:

ดูแผนที่

Kotlin

// Map point based on address
val mapIntent: Intent = Uri.parse(
        "geo:0,0?q=1600+Amphitheatre+Parkway,+Mountain+View,+California"
).let { location ->
    // Or map point based on latitude/longitude
    // val location: Uri = Uri.parse("geo:37.422219,-122.08364?z=14") // z param is zoom level
    Intent(Intent.ACTION_VIEW, location)
}

Java

// Map point based on address
Uri location = Uri.parse("geo:0,0?q=1600+Amphitheatre+Parkway,+Mountain+View,+California");
// Or map point based on latitude/longitude
// Uri location = Uri.parse("geo:37.422219,-122.08364?z=14"); // z param is zoom level
Intent mapIntent = new Intent(Intent.ACTION_VIEW, location);

ดูหน้าเว็บ

Kotlin

val webIntent: Intent = Uri.parse("https://www.android.com").let { webpage ->
    Intent(Intent.ACTION_VIEW, webpage)
}

Java

Uri webpage = Uri.parse("https://www.android.com");
Intent webIntent = new Intent(Intent.ACTION_VIEW, webpage);

เพิ่มส่วนเสริมไปยัง Intent

Intent แบบไม่เจาะจงปลายทางประเภทอื่นๆ ต้องใช้ "เพิ่มเติม" ที่ให้ข้อมูลประเภทต่างๆ เช่น สตริง คุณเพิ่มข้อมูลเพิ่มเติมอย่างน้อย 1 รายการได้โดยใช้เมธอด putExtra() ต่างๆ

โดยค่าเริ่มต้น ระบบจะระบุประเภท MIME ที่เหมาะสมที่ Intent ต้องการโดยอิงจาก ข้อมูล Uri ที่รวมอยู่ หากคุณไม่ใส่ Uri ในช่อง โดยทั่วไป คุณควรใช้ setType() เพื่อระบุประเภท ที่เกี่ยวข้องกับ Intent การตั้งค่าประเภท MIME จะระบุเพิ่มเติมถึงประเภทของ กิจกรรมควรได้รับความตั้งใจ

ต่อไปนี้เป็น Intent บางส่วนที่เพิ่มข้อมูลเพิ่มเติมเพื่อระบุการดำเนินการที่ต้องการ

ส่งอีเมลพร้อมไฟล์แนบ

Kotlin

Intent(Intent.ACTION_SEND).apply {
    // The intent does not have a URI, so declare the "text/plain" MIME type
    type = "text/plain"
    putExtra(Intent.EXTRA_EMAIL, arrayOf("jan@example.com")) // recipients
    putExtra(Intent.EXTRA_SUBJECT, "Email subject")
    putExtra(Intent.EXTRA_TEXT, "Email message text")
    putExtra(Intent.EXTRA_STREAM, Uri.parse("content://path/to/email/attachment"))
    // You can also attach multiple items by passing an ArrayList of Uris
}

Java

Intent emailIntent = new Intent(Intent.ACTION_SEND);
// The intent does not have a URI, so declare the "text/plain" MIME type
emailIntent.setType(HTTP.PLAIN_TEXT_TYPE);
emailIntent.putExtra(Intent.EXTRA_EMAIL, new String[] {"jan@example.com"}); // recipients
emailIntent.putExtra(Intent.EXTRA_SUBJECT, "Email subject");
emailIntent.putExtra(Intent.EXTRA_TEXT, "Email message text");
emailIntent.putExtra(Intent.EXTRA_STREAM, Uri.parse("content://path/to/email/attachment"));
// You can also attach multiple items by passing an ArrayList of Uris

สร้างกิจกรรมในปฏิทิน

หมายเหตุ: Intent นี้สำหรับกิจกรรมในปฏิทินรองรับเฉพาะ API ระดับ 14 ขึ้นไป

Kotlin

// Event is on January 23, 2021 -- from 7:30 AM to 10:30 AM.
Intent(Intent.ACTION_INSERT, Events.CONTENT_URI).apply {
    val beginTime: Calendar = Calendar.getInstance().apply {
        set(2021, 0, 23, 7, 30)
    }
    val endTime = Calendar.getInstance().apply {
        set(2021, 0, 23, 10, 30)
    }
    putExtra(CalendarContract.EXTRA_EVENT_BEGIN_TIME, beginTime.timeInMillis)
    putExtra(CalendarContract.EXTRA_EVENT_END_TIME, endTime.timeInMillis)
    putExtra(Events.TITLE, "Ninja class")
    putExtra(Events.EVENT_LOCATION, "Secret dojo")
}

Java

// Event is on January 23, 2021 -- from 7:30 AM to 10:30 AM.
Intent calendarIntent = new Intent(Intent.ACTION_INSERT, Events.CONTENT_URI);
Calendar beginTime = Calendar.getInstance();
beginTime.set(2021, 0, 23, 7, 30);
Calendar endTime = Calendar.getInstance();
endTime.set(2021, 0, 23, 10, 30);
calendarIntent.putExtra(CalendarContract.EXTRA_EVENT_BEGIN_TIME, beginTime.getTimeInMillis());
calendarIntent.putExtra(CalendarContract.EXTRA_EVENT_END_TIME, endTime.getTimeInMillis());
calendarIntent.putExtra(Events.TITLE, "Ninja class");
calendarIntent.putExtra(Events.EVENT_LOCATION, "Secret dojo");

หมายเหตุ: คุณต้องกำหนด Intent ให้เฉพาะเจาะจงมากที่สุด เช่น ถ้าต้องการแสดงรูปภาพ เมื่อใช้ Intent ACTION_VIEW คุณควรระบุประเภท MIME เป็น image/* วิธีนี้จะช่วยป้องกันไม่ให้แอปที่ "ดู" ได้ ข้อมูลประเภทอื่นๆ (เช่น แอปแผนที่) ที่เกิดจากความตั้งใจ

เริ่มกิจกรรมด้วยความตั้งใจ

เมื่อคุณสร้าง Intent และตั้งค่าข้อมูลเพิ่มเติมแล้ว โปรดโทรหา startActivity() เพื่อส่งไปยังระบบ

Kotlin

startActivity(intent)

Java

startActivity(intent);

รับมือกับสถานการณ์ที่ไม่มีแอปใดได้รับ Intent

แม้ว่าอีกแอปหนึ่งที่ติดตั้งไว้จะจัดการ Intent หลายรายการได้สำเร็จ บนอุปกรณ์ เช่น แอปโทรศัพท์ อีเมล หรือปฏิทิน แอปของคุณควรเตรียมการ สำหรับสถานการณ์ที่ไม่มีกิจกรรมใดที่จะจัดการกับความตั้งใจของแอปของคุณได้ เมื่อใดก็ตามที่คุณ สร้างความตั้งใจ เตรียมพร้อมที่จะจับ ActivityNotFoundException ซึ่งเกิดขึ้นหากไม่มีกิจกรรมอื่นๆ ที่จัดการกับความตั้งใจของแอปได้

Kotlin

try {
    startActivity(intent)
} catch (e: ActivityNotFoundException) {
    // Define what your app should do if no activity can handle the intent.
}

Java

try {
    startActivity(intent);
} catch (ActivityNotFoundException e) {
    // Define what your app should do if no activity can handle the intent.
}

หลังจากตรวจพบข้อยกเว้นนี้แล้ว ให้ตัดสินใจว่าแอปควรทำอย่างไรต่อไป รายการถัดไป จะขึ้นอยู่กับลักษณะเฉพาะของเจตนาที่คุณพยายามจะ เรียกใช้ ตัวอย่างเช่น หากคุณรู้จักแอปที่เจาะจงซึ่งจัดการความตั้งใจได้ ระบุลิงก์ให้ผู้ใช้ดาวน์โหลดแอป ดูข้อมูลเพิ่มเติมเกี่ยวกับวิธี ที่ลิงก์ไปยังผลิตภัณฑ์ของคุณใน Google Play

กล่องโต้ตอบที่มีคำอธิบาย

หากระบบระบุกิจกรรมได้มากกว่า 1 รายการที่สามารถจัดการความตั้งใจ จะแสดงกล่องโต้ตอบ (บางครั้งเรียกว่า "กล่องโต้ตอบที่มีคำอธิบาย") สำหรับ ผู้ใช้จะเลือกแอปที่จะใช้ ดังที่แสดงในรูปที่ 1 หากมีเพียงรายการเดียว ที่จัดการความตั้งใจแล้ว ระบบจะเริ่มการทำงานของสิ่งนั้นทันที

แผงจะปรากฏขึ้น
  บริเวณด้านล่างของหน้าจอ แผงนี้แสดงแอปต่างๆ ที่อาจ
  จัดการความตั้งใจ

รูปที่ 1 ตัวอย่างการเลือก ที่ปรากฏขึ้นเมื่อมีแอปมากกว่า 1 แอปสามารถจัดการ Intent ได้

ตัวอย่างที่สมบูรณ์

ต่อไปนี้เป็นตัวอย่างที่สมบูรณ์ที่แสดงวิธีสร้างความตั้งใจที่จะดูแผนที่ ยืนยันว่า มีไว้เพื่อจัดการ Intent แล้วเริ่มแอป:

Kotlin

// Build the intent.
val location = Uri.parse("geo:0,0?q=1600+Amphitheatre+Parkway,+Mountain+View,+California")
val mapIntent = Intent(Intent.ACTION_VIEW, location)

// Try to invoke the intent.
try {
    startActivity(mapIntent)
} catch (e: ActivityNotFoundException) {
    // Define what your app should do if no activity can handle the intent.
}

Java

// Build the intent.
Uri location = Uri.parse("geo:0,0?q=1600+Amphitheatre+Parkway,+Mountain+View,+California");
Intent mapIntent = new Intent(Intent.ACTION_VIEW, location);

// Try to invoke the intent.
try {
    startActivity(mapIntent);
} catch (ActivityNotFoundException e) {
    // Define what your app should do if no activity can handle the intent.
}

แสดงตัวเลือกแอป

รูปที่ 2 กล่องโต้ตอบตัวเลือก

โปรดสังเกตว่าเมื่อคุณเริ่มกิจกรรมโดยการส่ง Intent ไปยัง startActivity() และมีแอปมากกว่า 1 แอปที่ตอบสนองต่อ ผู้ใช้เลือกได้ว่าจะใช้แอปใดโดยค่าเริ่มต้น (โดยเลือกช่องทำเครื่องหมายด้านล่าง ของกล่องโต้ตอบ ดูรูปที่ 1) ซึ่งมีประโยชน์มากเมื่อดำเนินการที่ผู้ใช้ โดยทั่วไปต้องการใช้แอปเดิมทุกครั้ง เช่น เมื่อเปิดหน้าเว็บ (ผู้ใช้ ใช้เว็บเบราว์เซอร์เพียงตัวเดียว) หรือถ่ายรูป (ผู้ใช้มักชอบกล้อง 1 ตัว)

แต่หากการทำงานที่ต้องทำนั้นหลายแอปสามารถจัดการได้จากหลายแอปและผู้ใช้อาจ เลือกใช้แอปที่แตกต่างกันในแต่ละครั้ง เช่น "แชร์" ซึ่งผู้ใช้อาจมี แอปที่ผู้ใช้อาจแชร์รายการ คุณควรแสดงกล่องโต้ตอบตัวเลือกอย่างชัดเจน ดังที่แสดงในรูปที่ 2 กล่องโต้ตอบตัวเลือก บังคับให้ผู้ใช้เลือกแอปที่จะใช้สำหรับการทำงานทุกครั้ง (ผู้ใช้ไม่สามารถเลือก แอปเริ่มต้นสำหรับการดำเนินการ)

หากต้องการแสดงตัวเลือก ให้สร้าง Intent โดยใช้ createChooser() แล้วส่งไปยัง startActivity() เช่น

Kotlin

val intent = Intent(Intent.ACTION_SEND)

// Create intent to show chooser
val chooser = Intent.createChooser(intent, /* title */ null)

// Try to invoke the intent.
try {
    startActivity(chooser)
} catch (e: ActivityNotFoundException) {
    // Define what your app should do if no activity can handle the intent.
}

Java

Intent intent = new Intent(Intent.ACTION_SEND);

// Create intent to show chooser
Intent chooser = Intent.createChooser(intent, /* title */ null);

// Try to invoke the intent.
try {
    startActivity(chooser);
} catch (ActivityNotFoundException e) {
    // Define what your app should do if no activity can handle the intent.
}

การดำเนินการนี้จะแสดงกล่องโต้ตอบที่มีรายการแอปที่ตอบสนองต่อ Intent ที่ส่งผ่าน ไปยังเมธอด createChooser() พารามิเตอร์ title อาจเป็น ระบุหากการดำเนินการไม่ใช่ ACTION_SEND หรือ ACTION_SEND_MULTIPLE