การแจ้งเตือนและการเตือนภัยใน Flutter
การทำงานกับปลั๊กอิน Flutter, Android_Alarm_Manager
รู้อย่างนี้! ปลั๊กอินนี้ใช้งานได้กับแพลตฟอร์มAndroidเท่านั้น! โดยส่วนตัวฉันไม่ทราบว่ามี iOS เทียบเท่า หรือหนึ่งเดือนหลังจากเผยแพร่บทความนี้ฉันได้พบกับปลั๊กอินที่ให้การแจ้งเตือนทั้งบนแพลตฟอร์ม Android และ iOS แน่นอนฉันเขียนบทความและสิ่งนั้นเช่นกัน ดูด้านล่าง
ทราบว่าหากคุณต้องการใช้ปลั๊กอินที่อธิบายไว้ที่นี่คุณต้องปฏิบัติตามไฟล์ readmeอย่างชัดเจนเพื่อตั้งค่าสิ่งต่างๆให้ถูกต้อง คุณเป็น AndroidManfest.xml อย่างน้อยควรมีลักษณะดังนี้:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="NAME OF YOUR APPLICATION STARTING WITH COM.">
<!-- The INTERNET permission access.-->
<uses-permission android:name="android.permission.INTERNET"/>
<!-- android_alarm_manager -->
<!-- Start an Alarm When the Device Boots if past due -->
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
<!-- application needs to have the device stay on -->
<uses-permission android:name="android.permission.WAKE_LOCK"/>
<application
android:name="io.flutter.app.FlutterApplication"
android:label="code_samples"
android:icon="@mipmap/ic_launcher">
<activity
android:name=".MainActivity"
android:launchMode="singleTop"
android:theme="@style/LaunchTheme"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:hardwareAccelerated="true"
android:windowSoftInputMode="adjustResize">
<meta-data android:name="io.flutter.embedding.android.NormalTheme"
android:resource="@style/NormalTheme"
/>
<meta-data
android:name="io.flutter.embedding.android.SplashScreenDrawable"
android:resource="@drawable/launch_background"
/>
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<!-- android_alarm_manager -->
<service
android:name="io.flutter.plugins.androidalarmmanager.AlarmService"
android:permission="android.permission.BIND_JOB_SERVICE"
android:exported="false"/>
<receiver
android:name="io.flutter.plugins.androidalarmmanager.AlarmBroadcastReceiver"
android:exported="false"/>
<receiver
android:name="io.flutter.plugins.androidalarmmanager.RebootBroadcastReceiver"
android:enabled="false">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
</application>
</manifest>
# https://pub.dev/packages/android_alarm_manager
android_alarm_manager: ^0.4.0
ในกรณีนี้เป็นการปิดการเตือนในแอปของคุณ! ในกรณีของฉันฉันพบว่าปลั๊กอิน Flutter ซึ่งเป็นandroid_alarm_managerตรงตามความต้องการของแอปล่าสุดที่ฉันกำลังทำงานอยู่ดังนั้น ... ฉันจึงทำกิจวัตรประจำวันเพื่อให้ทำงานกับมันได้อย่างง่ายดาย หากคุณต้องการให้ถ่ายสำเนาทำเองและแบ่งปันการปรับปรุงที่คุณทำ เย็น?
ตอนนี้ถ้าคุณมีเวลาโปรดอ่านสิ่งที่ฉันพบว่าฉันต้องทำต่อไปเพื่อให้ปลั๊กอินนี้ทำงานได้เกือบจะ 'เข้าใจผิดได้' เพื่อตั้งปลุกหรือการดำเนินการอื่น ๆ ที่จะดำเนินการ 'ในพื้นหลัง' ได้อย่างง่ายดายและรวดเร็ว ทันเวลาในอนาคตขณะที่แอปกำลังทำงาน มันทำให้ชีวิตง่ายขึ้นเล็กน้อยและนั่นเป็นสิ่งที่ดี ขวา?
ภาพหน้าจอเท่านั้น คลิกสำหรับ Gists
เช่นเคยฉันชอบใช้ภาพหน้าจอมากกว่าส่วนสำคัญเพื่อแสดงโค้ดในบทความของฉัน ฉันพบว่าพวกเขาทำงานได้ง่ายขึ้นและอ่านง่ายขึ้น อย่างไรก็ตามคุณสามารถคลิก / แตะเพื่อดูรหัสในส่วนสำคัญหรือใน Github น่าแปลกที่การอ่านบทความเกี่ยวกับการพัฒนาอุปกรณ์เคลื่อนที่บนคอมพิวเตอร์ของคุณจะดีกว่าในโทรศัพท์ของคุณ นอกจากนี้เรายังตั้งโปรแกรมบนคอมพิวเตอร์ของเราเป็นส่วนใหญ่ ไม่ได้อยู่ในโทรศัพท์ของเรา สำหรับตอนนี้.
เอาล่ะ.
วิธีการของฉันที่นี่คือการปัจจุบันชั้นแรกยูทิลิตี้นี้ในตัวอย่างและแสดงให้เห็นถึงวิธีการใช้งาน - ทำให้การใช้ประโยชน์จากปลั๊กอินกระพือ, android_alarm_manager ในความเป็นจริงผมจะใช้ตัวอย่างเช่นเดียวกันมากที่ระบุไว้ในปลั๊กอินของตัวเองหน้าตัวอย่าง อย่างไรก็ตามตัวอย่างนี้ได้รับการแก้ไขเพื่อใช้ไฟล์ไลบรารีที่นำเสนอที่นี่แทน สำเนาตัวอย่างนี้มีให้คุณเป็นส่วนสำคัญ, android_alarm_manager หลังจากตัวอย่างฉันจะเดินผ่านบางส่วนของคลาสยูทิลิตี้ที่อธิบายในบางครั้งสิ่งที่ต้องทำเพื่อให้กลุ่มคนที่ไม่ยอมใครใช้ชั้นเรียนนั้นเป็นคนทั่วไป
ให้มันคงที่
ในตัวอย่างง่ายๆนี้คุณจะต้องกดปุ่มที่ปรากฏขึ้นและ 5 วินาทีต่อมาศูนย์ทั้งสองดังภาพในภาพหน้าจอด้านล่างจะกลายเป็นเลขศูนย์ วี๊ด! แน่นอนว่าสิ่งที่น่าสนใจจริงๆคือสิ่งที่อยู่ภายใต้ประทุนในรหัส
หมายเหตุฉันเปลี่ยนรหัสจากเดิมเพื่อรองรับการดำเนินการแบบอะซิงโครนัสที่ต้องดำเนินการก่อนที่แอปจะเริ่มทำงานได้จริง ฉันใช้วิดเจ็ต FutureBuilder เพื่อทำสิ่งนี้ให้สำเร็จ ในการทำเช่นนั้นฉันได้กำหนดฟังก์ชันใหม่ที่เรียกว่าinitSettings ()เพื่อเริ่มต้นรูทีน 'Shared Preferences' ที่ใช้ในการ 'จำ' จำนวนการเตือนทั้งหมดที่เริ่มทำงานดังที่เห็นในภาพหน้าจอด้านบน
นอกจากนี้คุณยังสามารถเห็นในฟังก์ชัน initSettings () ที่แสดงด้านล่างซึ่งจะตั้งค่า 'จำนวนรวม' เป็นศูนย์หากนี่เป็นครั้งแรกที่แอปทำงาน อย่างไรก็ตามในตอนเริ่มต้นกิจวัตรของไลบรารีAlarmManagerได้รับการเริ่มต้นเพื่อตั้งค่า 'Alarm Service' เฉพาะที่จำเป็นสำหรับการแจ้งเตือนบนโทรศัพท์ Android
มาดูโค้ดตัวอย่างเพิ่มเติมและดูว่าปุ่มเล็ก ๆ นั้นมีอะไรบ้าง หมายเหตุประจำห้องสมุดใช้ชื่อเดียวกันมากสำหรับพารามิเตอร์และฟังก์ชั่นที่ทำขึ้นขีดเส้นใต้ Flutter ปลั๊กอินAndroid_Alarm_Manager ดีกว่าที่จะสอดคล้องกับสิ่งเหล่านี้ นอกจากนี้เช่นเดียวกับฟังก์ชัน oneShot ()ของปลั๊กอินเวอร์ชันของไลบรารีนี้เมื่อเรียกใช้แล้วจะ 'รอ' ตามระยะเวลาที่กำหนดก่อนที่จะเริ่มใช้งานรูทีนการเรียกกลับที่ระบุ ในกรณีของตัวอย่างที่แก้ไขนี้รูทีนการเรียกกลับเป็นฟังก์ชันที่ไม่ระบุชื่อซึ่งจะทำงานหลังจากผ่านไป 5 วินาที ในภาพหน้าจอด้านล่างแอปเริ่มต้นขึ้นอีกครั้งโดยกดปุ่มอีกครั้งเพื่อแสดงว่าต้องขอบคุณการตั้งค่าที่ใช้ร่วมกันซึ่งปุ่มนี้ถูกกดสองครั้งนับตั้งแต่มีการเรียกใช้เป็นครั้งแรก Wheeee.
ดูอย่างละเอียดเกี่ยวกับฟังก์ชันที่ไม่ระบุตัวตนด้านล่างนี้และเราจะเห็นว่ามันถูกส่งผ่านพารามิเตอร์ประเภทเดียวคือจำนวนเต็ม คุณสามารถเดาว่าเป็นค่า ID เดียวกันมากส่งผ่านไปยังพารามิเตอร์ที่สองเป็นจำนวนสุ่มโดยใช้ฟังก์ชั่นปาเป้า, สุ่ม (). nextInt (ธาร (2,31)) ทำไมต้องกังวลกับการส่งผ่านค่านั้นเมื่อมันถูกส่งไปยังพารามิเตอร์ที่อยู่ข้างๆแล้ว? เราจะไปถึงจุดนั้น
สำหรับตอนนี้คุณสามารถดูเพิ่มเติมได้ด้านล่างว่าฟังก์ชันการโทรกลับในทางกลับกันจะเรียกใช้ฟังก์ชัน_incrementCounter () ที่นั่น 'จำนวนรวม' ของการกดปุ่มในปัจจุบันจะถูกดึงมาจากรูทีน 'Shared Preferences' จากนั้นอัปเดตทีละรายการเพื่อรองรับการกดปุ่มปัจจุบันนี้และบันทึกกลับไปยัง Shared Preferences จากนั้นหน้าจอของแอปจะอัปเดตด้วยตัวแปรที่เพิ่มขึ้น_counterโดยใช้ ฟังก์ชันsetState () คุณทำตามทุกอย่างจนถึงตอนนี้หรือไม่?
ทำให้มันคงที่
ไม่เหมือนกับตัวอย่างเดิม (ดูด้านล่าง) ตัวอย่างนี้ได้รับอนุญาตให้ใช้ฟังก์ชันที่ไม่ระบุตัวตนและไม่จำเป็นต้องใช้ฟังก์ชันคงที่โดยเฉพาะ แน่นอนคุณได้รับอนุญาตให้ใช้ฟังก์ชันคงที่ในตัวอย่างนี้เช่นกัน - ตราบใดที่ยังยอมรับค่าจำนวนเต็มเดี่ยวนั้น อย่างไรก็ตามในตัวอย่างเดิมก็จะต้องเป็นฟังก์ชั่นแบบคงที่หรือฟังก์ชั่นระดับสูงที่กำหนดไว้นอกชั้นเรียนใด ๆ ในแฟ้มโผที่ห้องสมุด - คนใดคนหนึ่งคุณจะเห็นเป็นความต้องการเมื่อทำงานโดยตรงกับปลั๊กอินกระพือ, Android_Alarm_Manager
อย่างไรก็ตามหากคุณติดตามบทความของฉันคุณก็รู้ว่าฉันชอบตัวเลือกต่างๆ ทุกอย่างเกี่ยวกับการมีตัวเลือกกับฉัน ฉันได้เขียนคลาสยูทิลิตี้นี้เพื่อให้รองรับได้มากขึ้น - เพื่ออนุญาตให้ใช้ฟังก์ชันที่ไม่ระบุตัวตนเช่น ด้วยการจัดเรียงดังกล่าวดังนั้นการส่งค่าเลขจำนวนเต็มไอดีนั้นเป็นพารามิเตอร์จึงทำให้ฟังก์ชันนั้นเป็นฟังก์ชันคงที่ฟังก์ชันระดับสูงหรือฟังก์ชันที่ไม่ระบุชื่อ ตัวเลือก! อีกครั้งภาพหน้าจอของตัวอย่างดั้งเดิมมีดังต่อไปนี้:
ลองหันไปใช้คลาสยูทิลิตี้AlarmManagerเอง อีกครั้งออกแบบมาเพื่อทำงานกับปลั๊กอิน และอีกครั้งพารามิเตอร์หลายตัวเป็นพารามิเตอร์เดียวกันกับที่ปลั๊กอินใช้และจะถูกส่งต่อไปยังปลั๊กอินนั้น แต่ไม่ใช่ก่อนการทดสอบพารามิเตอร์ที่ครอบคลุมสำหรับค่าที่ถูกต้อง ลักษณะที่จำเป็นอีกประการหนึ่งของคลาสยูทิลิตี้ดังกล่าว มันทำงานทั้งหมดโดยที่คุณไม่ต้องทำ ขวา?
ในภาพหน้าจอด้านล่างนี้เป็นส่วนแรกของคลาสยูทิลิตี้นี้ ในฟังก์ชั่นคงที่init () เราเห็นว่าปลั๊กอินถูกเริ่มต้นอย่างแน่นอน หมายเหตุข้อผิดพลาดที่ไม่ดีที่อาจเกิดขึ้นในความพยายามที่จะเริ่มต้นจะถูกจับได้ในคำสั่งtry-catch ชั้นเรียนยูทิลิตี้ก็ต้องทำเช่นนั้นเช่นกัน ถัดไปในการinit () ฟังก์ชันมีชั้น 'ผู้ช่วย' _Callbackซึ่งเรียกว่าการเริ่มต้นวิธีการที่จำเป็นสำหรับ app ที่จะสื่อสารกับแยกไอโซเลตที่ใช้โดยบริการปลุกในพื้นหลัง
สุดท้ายคุณสามารถดูด้านล่างที่ใด ๆ และค่าพารามิเตอร์ที่ไม่เป็นโมฆะได้รับมอบหมายให้เฉพาะเจาะจงและยังคงคุณสมบัติที่ทำขึ้นในระดับยูทิลิตี้AlarmManager ไม่มีไฟฟ้าสถิตเกิดขึ้นมากมายที่นี่
คุณจะพบว่าคุณสมบัติและฟังก์ชันมากมายที่ประกอบกันเป็นคลาสนี้เป็นแบบคงที่ อย่างไรก็ตามการเลือกใช้สมาชิกคงที่ในชั้นเรียนควรมีอารมณ์ดี ตัวอย่างเช่นเนื่องจากฟังก์ชันinit () เป็นแบบคงที่ซึ่งหมายความว่าสามารถเรียกใช้งานได้ทุกที่ทุกเวลาและกี่ครั้งก็ได้ ข้อเท็จจริงนั้นจำเป็นต้องมีการพิจารณาเพิ่มเติม ในกรณีนี้คำสั่งบรรทัดเดียวแรกสุดในภาพหน้าจอด้านบนคือคำสั่ง if: 'i f (_init) return _init;' จำเป็นเมื่อเขียนฟังก์ชันinit () นี้ ด้วยวิธีนี้คุณสามารถเรียกใช้ฟังก์ชันนั้นได้หลายครั้งเท่าที่คุณต้องการ ไม่ว่าบริการและปลั๊กอินที่จำเป็นจะเริ่มต้นด้วยการโทรครั้งแรกเท่านั้น ดังนั้นในทีมนักพัฒนาตัวอย่างเช่นหากการเรียกใช้ฟังก์ชันinit () ผิดพลาดมากกว่าหนึ่งครั้งจะไม่มีอันตรายใด ๆ เกิดขึ้น ลักษณะที่พึงประสงค์อีกประการหนึ่งของคลาสยูทิลิตี้ ดูสิ่งที่ฉันกำลังทำอยู่ที่นี่? ทำให้มัน 'เข้าใจผิดได้' ขวา?
เริ่มการตั้งค่าของคุณ
อย่างไรก็ตามเมื่อพารามิเตอร์เหล่านั้นถูกส่งต่อไปยังตัวแปรคงที่นั่นหมายความว่าคุณมีตัวเลือกเพิ่มเติมในตัวอย่างของเรา เมื่อเรียกใช้ฟังก์ชันinit () การตั้งค่าอาจได้รับการระบุจากนั้นและที่นั่นแทน การทำเช่นนั้นจะอนุญาตให้มีการเรียกใช้ฟังก์ชันoneShot (), oneShotAt () และperiodic () ในภายหลังเพื่อใช้การตั้งค่าเหล่านั้นหากไม่ได้ระบุไว้อย่างชัดเจน ฉันได้แสดงให้เห็นด้านล่างนี้ คุณสามารถดูความแตกต่างที่เกิดขึ้นในโค้ดตัวอย่างได้หากใช้พารามิเตอร์เพิ่มเติมในฟังก์ชันinit () แทน เพียงแค่ออกจากการเรียกใช้ฟังก์ชัน 'oneShot' พร้อมกับระยะเวลา id และฟังก์ชันเรียกกลับที่จำเป็น ทำให้โค้ดสะอาดขึ้นเล็กน้อย ตัวเลือก!
D อย่าวาง init () ไว้ในฟังก์ชัน build () ! มันจะปรากฏฟังก์ชันinit () ของปลั๊กอินของ Flutter ที่เรียกว่าAndroidAlarmManager initialize (); มีแนวโน้มที่จะก่อให้เกิดผลข้างเคียงหรือปัญหา ในบางกรณีระบบจะเริ่มการสร้างใหม่ (เหมือนกับการเรียกใช้ฟังก์ชัน setState ()) นั่นเป็นเหตุผลที่คลาสยูทิลิตี้ของฉันมีฟังก์ชันinit () แยกต่างหาก ควรเรียกว่าใกล้จุดเริ่มต้นของแอพของคุณ - ในวิดเจ็ต FutureBuilder ที่มี MaterialApp เป็นต้น ดูตัวเองและในตัวอย่างการแก้ไขของคุณลองแสดงความคิดเห็นออกAlarmManger.init () ฟังก์ชันจากinitSettings () และวางไว้แทนขวาก่อนที่จะOneshotฟังก์ชั่น () (ดูด้านล่าง.) ตัวอย่างของคุณจะเริ่มต้นในการข้อผิดพลาดของการเผชิญหน้า
ถ่าย oneShot ของคุณ
โอเคกลับไปที่คลาสยูทิลิตี้ ในฟังก์ชัน oneShot () ค่าพารามิเตอร์ 'จำเป็น' สามตัวแรกกำลังทดสอบความถูกต้องและส่งต่อไปยังฟังก์ชันoneShot () ของปลั๊กอิน ทั้งหมดยกเว้น 'ฟังก์ชั่น' พารามิเตอร์โทรกลับ แต่ที่จะถูกเพิ่มไปยังคงแผนที่วัตถุระบุเอกลักษณ์โดย ID จำนวนเต็มมีให้ใช้คำสั่งต่อไป_Callback.oneShots [ID] = การเรียกกลับ เราจะกลับไปที่นั่นเร็วพอ สุดท้ายคุณสังเกตเห็นมีการเรียกฟังก์ชันคงOneshot () นอกจากนี้ยังพบในชั้นเรียนผู้ช่วยที่_Callback มันย่อมาจาก 'ฟังก์ชันคงที่' ที่จำเป็นที่ปลั๊กอินจะใช้ สิ่งนี้ทำให้ค่าพารามิเตอร์ที่เหลืออยู่ในตัวแปรคงที่จำนวนมากเหล่านั้นโดยใช้ตัวดำเนินการการรวมกันเป็นโมฆะ?? . ตัวดำเนินการถูกใช้ดังนั้นเมื่อไม่มีการส่งผ่านพารามิเตอร์ที่ชัดเจนระบบจะใช้ค่าในตัวแปรคงที่เหล่านั้นแทน รับหรือไม่ ตัวแปรแบบคงที่เหล่านี้จะถูกกำหนดค่าเริ่มต้นด้วยค่าเริ่มต้นดังนั้นจึงไม่มีค่า null ที่ส่งผ่านไปยังปลั๊กอินในที่สุด ดี.
ไม่มีโอกาส
โปรดทราบว่าการเรียกปลั๊กอินเองจะอยู่ในคำสั่งtry-catchด้วย นั่นเป็นเพราะเป็นโปรแกรมของบุคคลที่สาม เราไม่รู้ว่าจะเกิดอะไรขึ้นและเนื่องจากนี่เป็นคลาสยูทิลิตี้เราจึงไม่ต้องการทำให้แอปของคุณขัดข้อง แต่จะพบข้อยกเว้นที่อาจเกิดขึ้นแทน
นอกจากนี้เช่นเดียวกับคลาสยูทิลิตี้ที่ดีคลาสนี้มีวิธีให้นักพัฒนา 'ทดสอบ' ว่าการดำเนินการสำเร็จหรือไม่ หากไม่เป็นเช่นนั้นข้อยกเว้นใด ๆ ที่อาจเกิดขึ้นจะถูกบันทึกไว้เพื่อให้นักพัฒนาสามารถจัดการได้ นี่แสดงให้เห็นด้านล่างในตัวอย่างที่แก้ไขด้วยคำสั่งif ที่เพิ่งแทรก
คงที่มากขึ้น
ไกลออกไปตามในระดับยูทิลิตี้AlarmManager เราเห็นฟังก์ชัน oneShotAt () อีกครั้งเนื่องจากฟังก์ชันเหล่านี้ทั้งหมดเป็นฟังก์ชันแบบคงที่การป้องกันบางอย่างจึงจำเป็นต้องรวมไว้ในโค้ด ภายใต้สถานการณ์ที่โชคร้ายตัวอย่างเช่นปลั๊กอินอาจไม่ได้รับการเตรียมใช้งานก่อนเมื่อเรียกใช้ฟังก์ชันonShotAt () กล่าวอีกนัยหนึ่งก็คือฟังก์ชันinit () ไม่ได้ถูกเรียกก่อน อาจเกิดขึ้นได้เมื่อใช้โดยบุคคลทั่วไป คุณสามารถดูในภาพหน้าจอด้านล่างสถานการณ์ดังกล่าวได้รับการทดสอบด้วยฟังก์ชันassert () นี่เป็นความหวังว่านักพัฒนาจะจับข้อผิดพลาดดังกล่าวได้ในขณะที่พวกเขากำลังพัฒนา ในการผลิตมันถูกจับโดยคำสั่งifที่ตามหลังฟังก์ชันassert ()
หมายเหตุนี้oneShotAt () ฟังก์ชันมีวัตถุแผนที่ของตัวเองในการจัดเก็บที่ผ่านมาในการเรียกกลับ 'ฟังก์ชั่นและมีฟังก์ชั่นแบบคงที่ของตัวเอง_Callback.onShatAt () จะถูกส่งผ่านไปยังตัวเองปลั๊กอินoneShotAt () ฟังก์ชัน ทั้งหมดนี้มีความหมายโดยนัยว่าคุณสามารถเรียกใช้ฟังก์ชันเหล่านี้กี่ครั้งก็ได้ในแอปของคุณที่กำหนดเวลาการดำเนินการจำนวนเท่าใดก็ได้ที่จะเกิดขึ้นในอนาคต แน่นอนว่าแต่ละคนจะต้องได้รับการกำหนดค่า id เฉพาะของตัวเองจำไว้ มิฉะนั้นการดำเนินการใด ๆ ที่กำหนดเวลาไว้แล้วจะถูกเขียนทับด้วยการดำเนินการใหม่หากเกิดขึ้นโดยใช้ค่ารหัสเดียวกัน นั่นคือประเด็นเมื่อใช้รหัสเฉพาะ ขวา?
อย่างไรก็ตามทั้งหมดนี้ยังบอกเป็นนัยว่าคุณสามารถใช้ id เดียวกันได้ แต่ระหว่างสามฟังก์ชันที่แตกต่างกันคือoneShot (), oneShotAt () และperiodic () แยกกัน โปรดจำไว้ว่าพวกเขามีวัตถุแผนที่แยกต่างหากและฟังก์ชันคงที่ ข้อเท็จจริงนี้ให้บริการฉันเป็นอย่างดีในโครงการล่าสุดของฉันซึ่ง ID ที่ใช้เป็นค่าที่พบในฟิลด์หลักของฐานข้อมูลที่อยู่อาศัย ทางเลือกที่รัก! รักเลย!
Plugin Peek
ดูอย่างรวดเร็วที่ฟังก์ชั่นoneShot () และoneShotAt () ของปลั๊กอิน Flutter และคุณจะเห็นว่าในความเป็นจริงฟังก์ชันoneShot () เป็นเพียงการส่งผ่านพารามิเตอร์ไปยังคู่ของoneShotAt () หมายเหตุ 'ที่ CallbackHandle' วัตถุที่คุณเห็นในภาพด้านล่างมาจากฟังก์ชั่น_getCallbackHandle () ซึ่งในการเปิดฟังก์ชั่นที่เรียกว่ากรอบการกระพือของPluginUtilities.getCallbackHandle (โทรกลับ) การดำเนินการนี้ 'ฉีกขาด' สำเนาของฟังก์ชันการโทรกลับเพื่อให้สามารถเข้าถึงและเรียกใช้ฟังก์ชันดังกล่าวใน Isolate ที่ทำงานอยู่เบื้องหลัง ฉันจะกลับไปเช่นกัน
การดำเนินการโทรกลับ
Let 's ดำเนินต่อไปในขณะนี้และใช้เวลาดูที่ 'ระดับผู้ช่วย' _Callback ในไฟล์ไลบรารี คุณสามารถดูด้านล่างวัตถุแผนที่ที่เพิ่มในฟังก์ชันการเรียกกลับวัตถุถูกกำหนดในคลาสนี้เป็นคุณสมบัติคงที่ คลาสนี้ยังมีฟังก์ชันinit () และถูกเรียกใช้ในฟังก์ชันinit () ของ AlarmManger ในฟังก์ชันinit () นี้ซึ่งมีการลงทะเบียน 'พอร์ตการสื่อสาร' ด้วยตัวระบุชื่อเฉพาะสามตัว พอร์ตถูกใช้โดยพื้นหลัง Isolate เพื่อสื่อสารกับฉากหน้า Isolate โดยการส่งข้อความไปยังพอร์ตนั้น เดาว่าค่าของตัวระบุชื่อเหล่านั้นคืออะไร? ปรากฏอยู่ในภาพด้านล่างเก็บไว้ในตัวแปร_oneShot , _oneShotAt ,และ_periodic
ตามที่ชื่อมีความหมายว่าแยกเป็นส่วนของหน่วยความจำ
ที่แยกจากกันซึ่งเป็นไปตามการออกแบบ ... ไม่มีการแบ่งปันหน่วยความจำ มีเพียงการส่งผ่านข้อความระหว่าง Isolates เท่านั้น เนื้อหาของข้อความดังกล่าวอาจเป็นค่าดั้งเดิม (null, num, bool, double, String) อินสแตนซ์ของอ็อบเจ็กต์SendPortอ็อบเจ็กต์ List หรืออ็อบเจ็กต์แผนที่ที่มีค่าดั้งเดิมที่กล่าวถึงก่อน
ฟังอยู่เบื้องหลัง
พอร์ตจะถูกกำหนดให้ 'ผู้ฟัง' เพิ่มเติมเพื่อตอบสนองหากและเมื่อได้รับข้อความในกรณีนี้โดยพื้นหลังแยกที่เรียกใช้บริการสัญญาณเตือน Listener อยู่ในรูปแบบของฟังก์ชันที่ไม่ระบุตัวตนโดยใช้วัตถุแผนที่เป็นพารามิเตอร์ คุณสามารถดูด้านล่างวัตถุแผนที่มีค่าจำนวนเต็ม (ซึ่งเป็น id) และสตริงที่เก็บหนึ่งใน 'ตัวระบุชื่อ' กรณีคำสั่งกำหนดแล้วซึ่ง 'ชนิดของฟังก์ชั่นคือการดับเพลิง ดูวิธีการทำงาน? แน่นอนว่าเป็นคลาสยูทิลิตี้ทุกอย่างอยู่ในคำสั่งtry-catch ตัวอย่างเช่นเราไม่รู้ว่าจะเกิดอะไรขึ้นเมื่อเรียกใช้ฟังก์ชันที่เลือก เราต้องการตรวจจับข้อยกเว้นใด ๆ ที่อาจเกิดขึ้น ขวา?
ส่งข้อความ
แล้วข้อความนั้นส่งไปยังแอปที่ทำงานอยู่เบื้องหน้าได้อย่างไร? ดีเมื่อตัวระบุชื่อลงทะเบียนข้างต้นแล้ว (ดูด้านล่าง) ใด ๆ ในสามฟังก์ชั่นระดับยูทิลิตี้AlarmManager Oneshot () AlarmManager oneShotAt () ,และAlarmManager ระยะ () จะผ่านสามฟังก์ชั่นที่สอดคล้องกันคง_Callback onShot () _Callback onShotAt () และ_Callback periodic () โดยตรงไปยังปลั๊กอิน Flutter เพื่อให้พื้นหลัง Isolate ส่งข้อความกลับไปที่แอพที่ทำงานอยู่เบื้องหน้า Isolate การโทรทั้งสามประเภทมีดังต่อไปนี้
คุณจะเห็นมันเป็นที่สามเหล่านี้สอดคล้องกับฟังก์ชั่นแบบคงที่_Callback onShot () _Callback onShotAt () และ_Callback คาบ () นั่นคือ 'สะพาน' จากพื้นหลังแยกไปยังส่วนหน้าแยก เมื่อถึงเวลาปิดการเตือนตัวอย่างเช่น Alarm Service จะเรียกใช้ฟังก์ชันคงที่หนึ่งในสามฟังก์ชันนี้ โปรดทราบว่ามันไม่ใช่ฟังก์ชั่นจริงที่กำหนดไว้ในโฟร์กราวด์ Isolate แต่เป็นการ 'ฉีกสำเนา' ของมัน คุณจะเห็นพฤติกรรมต่อต้านที่เข้าใจง่ายเนื่องจากข้อเท็จจริงนี้ ตัวอย่างเช่นตัวแปร Static ใด ๆ ในฟังก์ชันนั้นที่กำหนดไว้ในโฟร์กราวด์ Isolate จะเป็น null ในพื้นหลัง Isolate คุณสามารถทดสอบปรากฏการณ์นี้ได้ด้วยตนเอง
ตัวอย่างเช่นในตัวอย่างที่แก้ไขของเราถ้าฉันกดปุ่มครั้งที่สามเราจะรู้ว่าวัตถุแผนที่คือoneShotsมีวัตถุฟังก์ชันนั้นเพื่อเรียกใช้และอัปเดตหน้าจอหลังจากผ่านไปห้าวินาทีและจะทำเช่นนั้นในภาพหน้าจอ ของกิจวัตร 'ผู้ฟัง' ด้านล่าง อย่างไรก็ตามในกระบวนการนี้วัตถุแผนที่นั้นว่างเปล่าหากเข้าถึงในพื้นหลัง Isolate ?! เป็นไปได้อย่างไร? เป็นไปได้เพราะเป็นสำเนาของวัตถุแผนที่ไม่ใช่วัตถุที่อยู่เบื้องหน้า Isolate อีกครั้ง Isolates สามารถส่งผ่าน 'ข้อความ' ถึงกันเท่านั้น พวกเขาไม่แบ่งปันหน่วยความจำ
อีกครั้งฟังก์ชั่นคงที่ทั้งสามนี้อยู่ในคลาสตัวช่วย_Callbackซึ่งแสดงรายการหนึ่งตามลำดับ จะปรากฏในภาพหน้าจอด้านล่าง ในแต่ละรายการคุณจะเห็น Isolate เบื้องหน้าถูกอ้างอิงโดยใช้ 'ตัวระบุชื่อ' และส่งผ่านวัตถุแผนที่จากพื้นหลัง Isolate หมายเหตุตัวดำเนินการเข้าถึงสมาชิกแบบมีเงื่อนไข?. ใช้ในกรณีที่การดำเนินการค้นหาส่งคืนค่าว่าง จะทำเช่นนั้นถ้าไม่มีชื่อเช่น ไม่น่าจะเกิดขึ้นเนื่องจากนี่เป็นโค้ดภายในทั้งหมด แต่เนื่องจากเป็นคลาสยูทิลิตี้เราไม่ได้ใช้โอกาสใด ๆ ขวา?
ทั้งหมดนี้เป็นที่สิ้นสุดของแฟ้มห้องสมุดและมันนี่ที่ในที่สุดเราก็เห็นคุณค่าของผู้ที่ชื่อตัวระบุ 'ในตัวแปร_oneShot , _oneShotAt ,และ_periodic แต่ละตัวตั้งชื่อตามประเภทฟังก์ชันที่เกี่ยวข้อง ไม่จินตนาการมาก แต่ก็เข้าท่า นอกจากนี้เรายังเห็นว่าเป็นตัวแปรระดับสูงที่กำหนดไว้นอกคลาสหรือฟังก์ชันระดับสูง ในความเป็นจริงพวกเขากำลังตัวแปรอย่างต่อเนื่องกับคำหลักconst เช่นเดียวกับตัวแปรสุดท้ายตัวแปร const จะเริ่มต้นเพียงครั้งเดียวและไม่สามารถเปลี่ยนแปลงได้ ต่างจากตัวแปรสุดท้ายคือกำหนดเมื่อแอปรวบรวม ดังนั้นสำหรับความต้องการของเราที่นี่พวกเขาพร้อมใช้งานแม้กระทั่งพื้นหลัง Isolates ดี.
หากคุณไม่สามารถจัดการกับสิ่งที่แยกได้ทั้งหมดนี้ อย่าเพิ่งกังวลไปในตอนนี้ นั่นคือสิ่งที่คลาสยูทิลิตี้มีไว้สำหรับ ซึ่งแตกต่างจากโค้ดตัวอย่างปลั๊กอินเดิมคุณไม่ต้องกังวลเกี่ยวกับการตั้งค่า "พอร์ตการสื่อสาร" หรือเมื่อใดที่จะใช้ฟังก์ชันหรือตัวแปรคงที่หรือระดับสูง นั่นเป็นเหตุผลที่ฉันเขียนคลาสนี้ตั้งแต่แรก - ดังนั้นฉันจึงไม่ต้องกังวลเกี่ยวกับสิ่งนั้นทั้งหมด นั่นเป็นเหตุผลว่าทำไมคลาสยูทิลิตี้ดังกล่าวจึงถูกเขียนขึ้นทั้งหมดดังนั้นจึงสามารถใช้ซ้ำได้โดยแอพมากมายของเราที่เราทุกคนจะเขียนในอนาคต ขวา?
ไชโย