អ្នកប្រើប្រាស់ទាំងអស់ទទួលយកការបើកដំណើរការរហ័ស និងឆ្លើយតប UI នៅក្នុងកម្មវិធីទូរស័ព្ទសម្រាប់ការអនុញ្ញាត។ ប្រសិនបើកម្មវិធីចំណាយពេលយូរដើម្បីចាប់ផ្តើម អ្នកប្រើប្រាស់ចាប់ផ្តើមមានអារម្មណ៍សោកសៅ និងខឹង។ អ្នកអាចធ្វើឱ្យខូចបទពិសោធន៍របស់អតិថិជនយ៉ាងងាយស្រួល ឬបាត់បង់អ្នកប្រើប្រាស់ទាំងស្រុង មុនពេលគាត់ចាប់ផ្តើមប្រើប្រាស់កម្មវិធី។
យើងធ្លាប់បានរកឃើញថាកម្មវិធី Dodo Pizza ចំណាយពេល 3 វិនាទីដើម្បីចាប់ផ្តើមជាមធ្យម ហើយសម្រាប់ "អ្នកសំណាង" មួយចំនួនវាចំណាយពេល 15-20 វិនាទី។
ខាងក្រោមការកាត់គឺជារឿងមួយដែលមានការបញ្ចប់ដ៏រីករាយ៖ អំពីការរីកចម្រើននៃមូលដ្ឋានទិន្នន័យ Realm ការលេចធ្លាយអង្គចងចាំ របៀបដែលយើងប្រមូលផ្តុំវត្ថុដែលជាប់គាំង ហើយបន្ទាប់មកទាញខ្លួនយើងរួមគ្នា និងជួសជុលអ្វីៗគ្រប់យ៉ាង។

អ្នកនិពន្ធអត្ថបទ៖ - Android-អ្នកអភិវឌ្ឍន៍នៅ Dodo Pizza។
បីវិនាទីពីការចុចលើរូបតំណាងកម្មវិធីទៅ onResume() នៃសកម្មភាពដំបូងគឺគ្មានកំណត់។ ហើយសម្រាប់អ្នកប្រើប្រាស់មួយចំនួន ពេលវេលាចាប់ផ្តើមឡើងដល់ 15-20 វិនាទី។ តើនេះអាចទៅរួចដោយរបៀបណា?
សេចក្តីសង្ខេបខ្លីបំផុតសម្រាប់អ្នកដែលមិនមានពេលអាន
មូលដ្ឋានទិន្នន័យ Realm របស់យើងបានកើនឡើងឥតឈប់ឈរ។ វត្ថុដែលបានលាក់មួយចំនួនមិនត្រូវបានលុបចេញទេ ប៉ុន្តែត្រូវបានបង្គរឥតឈប់ឈរ។ ពេលវេលាចាប់ផ្តើមកម្មវិធីកើនឡើងជាលំដាប់។ បន្ទាប់មកយើងបានជួសជុលវា ហើយពេលវេលាចាប់ផ្តើមបានមកដល់គោលដៅ - វាបានក្លាយជាតិចជាង 1 វិនាទី ហើយមិនកើនឡើងទៀតទេ។ អត្ថបទនេះមានការវិភាគអំពីស្ថានភាព និងដំណោះស្រាយពីរ - មួយរហ័ស និងធម្មតា។
ការស្វែងរកនិងការវិភាគនៃបញ្ហា
សព្វថ្ងៃនេះ កម្មវិធីទូរសព្ទណាមួយត្រូវតែបើកដំណើរការយ៉ាងឆាប់រហ័ស និងមានការឆ្លើយតប។ ប៉ុន្តែវាមិនមែនគ្រាន់តែអំពីកម្មវិធីទូរស័ព្ទប៉ុណ្ណោះទេ។ បទពិសោធន៍អ្នកប្រើប្រាស់នៃអន្តរកម្មជាមួយសេវាកម្ម និងក្រុមហ៊ុនគឺជារឿងស្មុគស្មាញ។ ជាឧទាហរណ៍ ក្នុងករណីរបស់យើង ល្បឿនដឹកជញ្ជូនគឺជាសូចនាករសំខាន់មួយសម្រាប់សេវាកម្មភីហ្សា។ ប្រសិនបើការដឹកជញ្ជូនលឿន ភីហ្សានឹងក្តៅ ហើយអតិថិជនដែលចង់ញ៉ាំឥឡូវនេះមិនបាច់រង់ចាំយូរទេ។ សម្រាប់កម្មវិធីវិញ វាជារឿងសំខាន់ក្នុងការបង្កើតអារម្មណ៍នៃសេវាកម្មលឿន ព្រោះថាប្រសិនបើកម្មវិធីប្រើពេលត្រឹមតែ 20 វិនាទីប៉ុណ្ណោះដើម្បីបើកដំណើរការ តើត្រូវរង់ចាំភីហ្សារយៈពេលប៉ុន្មាន?
ដំបូងឡើយ ខ្លួនយើងផ្ទាល់ត្រូវប្រឈមមុខនឹងការពិតដែលថា ពេលខ្លះកម្មវិធីប្រើពេលពីរបីវិនាទីដើម្បីចាប់ផ្តើម ហើយបន្ទាប់មកយើងចាប់ផ្តើមឮការត្អូញត្អែរពីមិត្តរួមការងារផ្សេងទៀតអំពីរយៈពេលដែលវាប្រើ។ ប៉ុន្តែយើងមិនអាចធ្វើស្ថានភាពនេះឡើងវិញជាប្រចាំ។
តើវាមានរយៈពេលប៉ុន្មាន? យោងទៅតាម ប្រសិនបើការចាប់ផ្តើមត្រជាក់នៃកម្មវិធីចំណាយពេលតិចជាង 5 វិនាទី វាត្រូវបានចាត់ទុកថា "ធម្មតា"។ Android- កម្មវិធី Dodo Pizza ត្រូវបានដាក់ឱ្យដំណើរការ (យោងតាមរង្វាស់ Firebase) ) នៅ ជាមធ្យមក្នុងរយៈពេល 3 វិនាទី - "មិនអស្ចារ្យ មិនគួរឱ្យភ័យខ្លាច" ដូចដែលពួកគេនិយាយ។
ប៉ុន្តែបន្ទាប់មកមានការត្អូញត្អែរបានចាប់ផ្តើមលេចឡើងថាកម្មវិធីនេះចំណាយពេលយូរណាស់ដើម្បីចាប់ផ្តើម! ដើម្បីចាប់ផ្តើម យើងបានសម្រេចចិត្តវាស់វែងថាតើអ្វីជា "ខ្លាំងណាស់ យូរណាស់" ។ ហើយយើងបានប្រើដាន Firebase សម្រាប់រឿងនេះ។ .

ដានស្តង់ដារនេះវាស់ពេលវេលារវាងពេលដែលអ្នកប្រើប្រាស់បើកកម្មវិធី និងពេលដែល onResume() នៃសកម្មភាពដំបូងត្រូវបានប្រតិបត្តិ។ នៅក្នុង Firebase Console ម៉ែត្រនេះត្រូវបានគេហៅថា _app_start។ វាបានប្រែក្លាយថា:
- ពេលវេលាចាប់ផ្តើមសម្រាប់អ្នកប្រើប្រាស់លើសពីភាគរយទី 95 គឺជិត 20 វិនាទី (ខ្លះក៏យូរជាងនេះ) ទោះបីជាពេលវេលាចាប់ផ្តើមត្រជាក់ជាមធ្យមតិចជាង 5 វិនាទីក៏ដោយ។
- ពេលវេលាចាប់ផ្តើមមិនមែនជាតម្លៃថេរទេ ប៉ុន្តែកើនឡើងតាមពេលវេលា។ ប៉ុន្តែពេលខ្លះមានដំណក់។ យើងបានរកឃើញគំរូនេះនៅពេលដែលយើងបង្កើនទំហំនៃការវិភាគដល់ 90 ថ្ងៃ។

គំនិតពីរបានកើតឡើង៖
- អ្វីមួយកំពុងលេចធ្លាយ។
- "អ្វីមួយ" នេះត្រូវបានកំណត់ឡើងវិញបន្ទាប់ពីការចេញផ្សាយហើយបន្ទាប់មកលេចធ្លាយម្តងទៀត។
"ប្រហែលជាអ្វីមួយជាមួយនឹងមូលដ្ឋានទិន្នន័យ" យើងបានគិត ហើយយើងនិយាយត្រូវ។ ទីមួយ យើងប្រើមូលដ្ឋានទិន្នន័យជាឃ្លាំងសម្ងាត់ កំឡុងពេលធ្វើចំណាកស្រុក យើងសម្អាតវា។ ទីពីរ មូលដ្ឋានទិន្នន័យត្រូវបានផ្ទុកនៅពេលកម្មវិធីចាប់ផ្តើម។ អ្វីគ្រប់យ៉ាងត្រូវគ្នា។
តើមានអ្វីខុសជាមួយមូលដ្ឋានទិន្នន័យ Realm
យើងបានចាប់ផ្តើមពិនិត្យមើលថាតើមាតិកានៃមូលដ្ឋានទិន្នន័យផ្លាស់ប្តូរលើជីវិតរបស់កម្មវិធី ចាប់ពីការដំឡើងដំបូង និងបន្ថែមទៀតក្នុងអំឡុងពេលប្រើប្រាស់សកម្ម។ អ្នកអាចមើលមាតិកានៃមូលដ្ឋានទិន្នន័យ Realm តាមរយៈ ឬលម្អិតបន្ថែមទៀត និងច្បាស់លាស់ដោយបើកឯកសារតាមរយៈ . ដើម្បីមើលមាតិកានៃមូលដ្ឋានទិន្នន័យតាមរយៈ ADB សូមចម្លងឯកសារមូលដ្ឋានទិន្នន័យ Realm៖
adb exec-out run-as ${PACKAGE_NAME} cat files/${DB_NAME}ដោយបានមើលមាតិកានៃមូលដ្ឋានទិន្នន័យនៅពេលវេលាផ្សេងៗគ្នា យើងបានរកឃើញថាចំនួនវត្ថុនៃប្រភេទជាក់លាក់មួយកំពុងកើនឡើងឥតឈប់ឈរ។

រូបភាពបង្ហាញពីបំណែកនៃ Realm Studio សម្រាប់ឯកសារពីរ៖ នៅខាងឆ្វេង - មូលដ្ឋានកម្មវិធីបន្ទាប់ពីដំឡើងរួច នៅខាងស្តាំ - បន្ទាប់ពីការប្រើប្រាស់សកម្ម។ វាអាចត្រូវបានគេមើលឃើញថាចំនួននៃវត្ថុ ImageEntity и MoneyType បានរីកចម្រើនយ៉ាងខ្លាំង (រូបថតអេក្រង់បង្ហាញពីចំនួនវត្ថុនៃប្រភេទនីមួយៗ) ។
ទំនាក់ទំនងរវាងកំណើនមូលដ្ឋានទិន្នន័យ និងពេលវេលាចាប់ផ្តើម
កំណើនមូលដ្ឋានទិន្នន័យដែលមិនមានការគ្រប់គ្រងគឺជារឿងអាក្រក់ណាស់។ ប៉ុន្តែតើវាប៉ះពាល់ដល់ពេលវេលាចាប់ផ្តើមកម្មវិធីយ៉ាងដូចម្តេច? ការវាស់វែងនេះគឺងាយស្រួលណាស់ដោយប្រើ ActivityManager។ ចាប់ផ្តើមជាមួយ Android ៤.៤, logcat បង្ហាញកំណត់ហេតុដែលមានបន្ទាត់ "បង្ហាញ" និងពេលវេលា។ ពេលវេលានេះគឺជាចន្លោះពេលចាប់ពីការចាប់ផ្តើមកម្មវិធីរហូតដល់ចុងបញ្ចប់នៃការបង្ហាញសកម្មភាព។ ក្នុងអំឡុងពេលនេះ ព្រឹត្តិការណ៍ដូចខាងក្រោមកើតឡើង៖
- ចាប់ផ្តើមដំណើរការ។
- ការចាប់ផ្តើមនៃវត្ថុ។
- ការបង្កើតនិងការចាប់ផ្តើមនៃសកម្មភាព។
- ការបង្កើតប្លង់។
- ការបង្ហាញកម្មវិធី។
សាកសមនឹងយើង។ ប្រសិនបើអ្នកដំណើរការ ADB ជាមួយនឹងទង់ -S និង -W អ្នកអាចទទួលបានលទ្ធផលបន្ថែមជាមួយនឹងពេលវេលាចាប់ផ្តើម៖
adb shell am start -S -W ru.dodopizza.app/.MainActivity -c android.intent.category.LAUNCHER -a android.intent.action.MAIN ប្រសិនបើអ្នកចាប់យកវាពីទីនោះ grep -i WaitTime ពេលវេលា អ្នកអាចធ្វើស្វ័យប្រវត្តិកម្មការប្រមូលម៉ែត្រនេះ ហើយមើលលទ្ធផលដោយភ្នែក។ ក្រាហ្វខាងក្រោមបង្ហាញពីភាពអាស្រ័យនៃពេលវេលាចាប់ផ្តើមកម្មវិធីលើចំនួននៃការចាប់ផ្តើមត្រជាក់នៃកម្មវិធី។

ក្នុងពេលជាមួយគ្នានេះមានលក្ខណៈដូចគ្នានៃទំនាក់ទំនងរវាងទំហំនិងការលូតលាស់នៃមូលដ្ឋានទិន្នន័យដែលបានកើនឡើងពី 4 MB ទៅ 15 MB ។ សរុបមក វាបង្ហាញថាយូរ ៗ ទៅ (ជាមួយនឹងការកើនឡើងនៃការចាប់ផ្តើមត្រជាក់) ទាំងពេលវេលាចាប់ផ្តើមកម្មវិធីនិងទំហំនៃមូលដ្ឋានទិន្នន័យបានកើនឡើង។ យើងមានសម្មតិកម្មមួយនៅលើដៃរបស់យើង។ ឥឡូវនេះអ្វីៗដែលនៅសល់គឺដើម្បីបញ្ជាក់ពីការពឹងផ្អែក។ ដូច្នេះហើយ យើងបានសម្រេចចិត្តលុប "ការលេចធ្លាយ" ហើយមើលថាតើវានឹងបង្កើនល្បឿននៃការបើកដំណើរការដែរឬទេ។
ហេតុផលសម្រាប់កំណើនមូលដ្ឋានទិន្នន័យគ្មានទីបញ្ចប់
មុនពេលដកចេញ "ការលេចធ្លាយ" វាគឺមានតំលៃយល់ពីមូលហេតុដែលពួកគេបង្ហាញខ្លួនជាលើកដំបូង។ ដើម្បីធ្វើដូច្នេះ ចូរយើងចាំថា Realm គឺជាអ្វី។
Realm គឺជាមូលដ្ឋានទិន្នន័យមិនមែនទំនាក់ទំនង។ វាអនុញ្ញាតឱ្យអ្នកពិពណ៌នាអំពីទំនាក់ទំនងរវាងវត្ថុតាមរបៀបស្រដៀងគ្នាទៅនឹងចំនួនមូលដ្ឋានទិន្នន័យទំនាក់ទំនង ORM ដែលពិពណ៌នាអំពីពួកវា។ AndroidRealm រក្សាទុកវត្ថុដោយផ្ទាល់នៅក្នុងអង្គចងចាំជាមួយនឹងការបំលែង និងការគូសផែនទីតិចតួចបំផុត។ នេះអនុញ្ញាតឱ្យមានការអានទិន្នន័យលឿនបំផុតពីថាស ដែលជាចំណុចខ្លាំងរបស់ Realm និងជាលក្ខណៈពិសេសដ៏ពេញនិយមបំផុតមួយរបស់វា។
(សម្រាប់គោលបំណងនៃអត្ថបទនេះ ការពិពណ៌នានេះនឹងគ្រប់គ្រាន់សម្រាប់ពួកយើង។ អ្នកអាចអានបន្ថែមអំពី Realm in the cool ឬនៅក្នុងពួកគេ។ ).
អ្នកអភិវឌ្ឍន៍ជាច្រើនមានទម្លាប់ធ្វើការច្រើនជាមួយមូលដ្ឋានទិន្នន័យទំនាក់ទំនង (ឧទាហរណ៍ មូលដ្ឋានទិន្នន័យ ORM ជាមួយ SQL នៅក្រោមក្រណាត់)។ ហើយអ្វីៗដូចជាការលុបទិន្នន័យជាបណ្ដើរៗ ហាក់បីដូចជាត្រូវបានផ្តល់ឱ្យ។ ប៉ុន្តែមិនមែននៅក្នុង Realm ទេ។
ដោយវិធីនេះលក្ខណៈពិសេសនៃការលុបល្បាក់ត្រូវបានសួរជាយូរមកហើយ។ នេះ។ и ដែលភ្ជាប់ជាមួយវាត្រូវបានពិភាក្សាយ៉ាងសកម្ម។ មានអារម្មណ៍ថាវានឹងត្រូវបានធ្វើក្នុងពេលឆាប់ៗនេះ។ ប៉ុន្តែបន្ទាប់មកអ្វីគ្រប់យ៉ាងដែលត្រូវបានបកប្រែទៅជាការណែនាំនៃតំណភ្ជាប់ខ្លាំងនិងខ្សោយដែលនឹងដោះស្រាយបញ្ហានេះដោយស្វ័យប្រវត្តិផងដែរ។ មានភាពរស់រវើក និងសកម្មក្នុងកិច្ចការនេះ។ ដែលត្រូវបានផ្អាកសម្រាប់ពេលនេះ ដោយសារបញ្ហាផ្ទៃក្នុង។
ការលេចធ្លាយទិន្នន័យដោយមិនមានការលុបចោល
តើទិន្នន័យលេចធ្លាយយ៉ាងណាបើអ្នកពឹងផ្អែកលើការលុបល្បាក់ដែលមិនមាន? ប្រសិនបើអ្នកបានដាក់វត្ថុ Realm រួចហើយ នោះពួកវាត្រូវតែត្រូវបានលុបចេញ។
សូមក្រឡេកមើលឧទាហរណ៍ជាក់ស្តែង (ស្ទើរតែ)។ យើងមានវត្ថុមួយ។ CartItemEntity:
@RealmClass
class CartItemEntity(
@PrimaryKey
override var id: String? = null,
...
var name: String = "",
var description: String = "",
var image: ImageEntity? = null,
var category: String = MENU_CATEGORY_UNKNOWN_ID,
var customizationEntity: CustomizationEntity? = null,
var cartComboProducts: RealmList<CartProductEntity> = RealmList(),
...
) : RealmObject() ផលិតផលនៅក្នុងរទេះមានវាលផ្សេងៗគ្នា រួមទាំងរូបភាពផងដែរ។ ImageEntity, គ្រឿងផ្សំតាមតម្រូវការ CustomizationEntity. ដូចគ្នានេះផងដែរ ផលិតផលនៅក្នុងរទេះអាចជាបន្សំជាមួយនឹងផលិតផលផ្ទាល់ខ្លួនរបស់វា។ RealmList (CartProductEntity). វាលដែលបានរាយបញ្ជីទាំងអស់គឺជាវត្ថុ Realm ។ ប្រសិនបើយើងបញ្ចូលវត្ថុថ្មី (copyToRealm() / copyToRealmOrUpdate()) ដែលមានលេខសម្គាល់ដូចគ្នា នោះវត្ថុនេះនឹងត្រូវបានសរសេរជាន់ពីលើទាំងស្រុង។ ប៉ុន្តែវត្ថុខាងក្នុងទាំងអស់ (រូបភាព ការប្ដូរតាមបំណងEntity និង cartComboProducts) នឹងបាត់បង់ការតភ្ជាប់ជាមួយមេ ហើយនៅតែមាននៅក្នុងមូលដ្ឋានទិន្នន័យ។
ដោយសារការភ្ជាប់ជាមួយពួកវាត្រូវបានបាត់បង់ យើងលែងអាន ឬលុបវាទៀតហើយ (លុះត្រាតែយើងចូលប្រើពួកវាយ៉ាងច្បាស់ ឬលុប "តារាង" ទាំងមូល)។ យើងបានហៅវាថា "ការលេចធ្លាយការចងចាំ" ។
នៅពេលយើងធ្វើការជាមួយ Realm យើងត្រូវឆ្លងកាត់ធាតុទាំងអស់យ៉ាងច្បាស់ ហើយលុបអ្វីៗទាំងអស់ឱ្យបានច្បាស់លាស់មុនពេលប្រតិបត្តិការបែបនេះ។ នេះអាចត្រូវបានធ្វើឧទាហរណ៍ដូចនេះ៖
val entity = realm.where(CartItemEntity::class.java).equalTo("id", id).findFirst()
if (first != null) {
deleteFromRealm(first.image)
deleteFromRealm(first.customizationEntity)
for(cartProductEntity in first.cartComboProducts) {
deleteFromRealm(cartProductEntity)
}
first.deleteFromRealm()
}
// и потом уже сохраняемប្រសិនបើអ្នកធ្វើបែបនេះ អ្វីៗនឹងដំណើរការដូចដែលវាគួរតែ។ ក្នុងឧទាហរណ៍នេះ យើងសន្មត់ថាមិនមានវត្ថុ Realm ផ្សេងទៀតដែលដាក់ក្នុងរូបភាព CustomizationEntity និង cartComboProducts ដូច្នេះមិនមានរង្វិលជុំ និងលុបផ្សេងទៀតទេ។
ដំណោះស្រាយរហ័ស
រឿងដំបូងដែលយើងសម្រេចចិត្តធ្វើគឺសម្អាតវត្ថុដែលលូតលាស់លឿនបំផុត ហើយពិនិត្យមើលលទ្ធផលដើម្បីមើលថាតើវានឹងដោះស្រាយបញ្ហាដើមរបស់យើង។ ទីមួយ ដំណោះស្រាយដ៏សាមញ្ញបំផុត និងវិចារណញាណបំផុតត្រូវបានធ្វើឡើង ពោលគឺ៖ វត្ថុនីមួយៗគួរតែទទួលខុសត្រូវចំពោះការដកកូនរបស់វា។ ដើម្បីធ្វើដូច្នេះ យើងបានណែនាំចំណុចប្រទាក់ដែលត្រឡប់បញ្ជីវត្ថុអាណាចក្រដែលដាក់ជាប់របស់វាវិញ៖
interface NestedEntityAware {
fun getNestedEntities(): Collection<RealmObject?>
}ហើយយើងបានអនុវត្តវានៅក្នុងវត្ថុអាណាចក្ររបស់យើង៖
@RealmClass
class DataPizzeriaEntity(
@PrimaryKey
var id: String? = null,
var name: String? = null,
var coordinates: CoordinatesEntity? = null,
var deliverySchedule: ScheduleEntity? = null,
var restaurantSchedule: ScheduleEntity? = null,
...
) : RealmObject(), NestedEntityAware {
override fun getNestedEntities(): Collection<RealmObject?> {
return listOf(
coordinates,
deliverySchedule,
restaurantSchedule
)
}
} В getNestedEntities យើងប្រគល់កុមារទាំងអស់ជាបញ្ជីរាបស្មើ។ ហើយវត្ថុកូននីមួយៗក៏អាចអនុវត្តចំណុចប្រទាក់ NestedEntityAware ដោយបង្ហាញថាវាមានវត្ថុ Realm ខាងក្នុងដែលត្រូវលុប ឧទាហរណ៍ ScheduleEntity:
@RealmClass
class ScheduleEntity(
var monday: DayOfWeekEntity? = null,
var tuesday: DayOfWeekEntity? = null,
var wednesday: DayOfWeekEntity? = null,
var thursday: DayOfWeekEntity? = null,
var friday: DayOfWeekEntity? = null,
var saturday: DayOfWeekEntity? = null,
var sunday: DayOfWeekEntity? = null
) : RealmObject(), NestedEntityAware {
override fun getNestedEntities(): Collection<RealmObject?> {
return listOf(
monday, tuesday, wednesday, thursday, friday, saturday, sunday
)
}
}ហើយដូច្នេះនៅលើសំបុកនៃវត្ថុអាចត្រូវបានធ្វើម្តងទៀត។
បន្ទាប់មកយើងសរសេរវិធីសាស្ត្រដែលលុបវត្ថុដែលបានដាក់ជាថ្មីម្តងទៀត។ វិធីសាស្រ្ត (បង្កើតជាផ្នែកបន្ថែម) deleteAllNestedEntities ទទួលបានវត្ថុ និងវិធីសាស្ត្រកម្រិតកំពូលទាំងអស់។ deleteNestedRecursively ដកវត្ថុដែលបានដាក់ជាប់គ្នាទាំងអស់ចេញឡើងវិញដោយប្រើចំណុចប្រទាក់ NestedEntityAware៖
fun <T> Realm.deleteAllNestedEntities(entities: Collection<T>,
entityClass: Class<out RealmObject>,
idMapper: (T) -> String,
idFieldName : String = "id"
) {
val existedObjects = where(entityClass)
.`in`(idFieldName, entities.map(idMapper).toTypedArray())
.findAll()
deleteNestedRecursively(existedObjects)
}
private fun Realm.deleteNestedRecursively(entities: Collection<RealmObject?>) {
for(entity in entities) {
entity?.let { realmObject ->
if (realmObject is NestedEntityAware) {
deleteNestedRecursively((realmObject as NestedEntityAware).getNestedEntities())
}
realmObject.deleteFromRealm()
}
}
}យើងបានធ្វើបែបនេះជាមួយនឹងវត្ថុដែលលូតលាស់លឿនបំផុត ហើយពិនិត្យមើលអ្វីដែលបានកើតឡើង។

ជាលទ្ធផល វត្ថុទាំងនោះដែលយើងគ្របដណ្តប់ជាមួយនឹងដំណោះស្រាយនេះឈប់លូតលាស់។ ហើយកំណើនទាំងមូលនៃមូលដ្ឋានបានថយចុះ ប៉ុន្តែមិនបញ្ឈប់ឡើយ។
ដំណោះស្រាយ "ធម្មតា"
ទោះបីជាមូលដ្ឋានចាប់ផ្តើមលូតលាស់យឺតក៏ដោយ ក៏វានៅតែកើនឡើង។ ដូច្នេះ យើងចាប់ផ្តើមមើលបន្ថែមទៀត។ គម្រោងរបស់យើងធ្វើឱ្យការប្រើប្រាស់សកម្មនៃការរក្សាទុកទិន្នន័យនៅក្នុង Realm ។ ដូច្នេះហើយ ការសរសេរវត្ថុដែលជាប់គាំងទាំងអស់សម្រាប់វត្ថុនីមួយៗគឺពឹងផ្អែកលើកម្លាំងពលកម្ម បូកនឹងហានិភ័យនៃកំហុសកើនឡើង ព្រោះអ្នកអាចភ្លេចបញ្ជាក់វត្ថុនៅពេលផ្លាស់ប្តូរកូដ។
ខ្ញុំចង់ធ្វើឱ្យប្រាកដថាខ្ញុំមិនបានប្រើចំណុចប្រទាក់, ប៉ុន្តែថាអ្វីគ្រប់យ៉ាងធ្វើការដោយខ្លួនឯង។
នៅពេលដែលយើងចង់ឱ្យអ្វីមួយដំណើរការដោយខ្លួនឯង យើងត្រូវប្រើការឆ្លុះបញ្ចាំង។ ដើម្បីធ្វើដូច្នេះ យើងអាចឆ្លងកាត់ថ្នាក់នីមួយៗ ហើយពិនិត្យមើលថាតើវាជាវត្ថុ Realm ឬបញ្ជីវត្ថុ៖
RealmModel::class.java.isAssignableFrom(field.type)
RealmList::class.java.isAssignableFrom(field.type)ប្រសិនបើវាលគឺជា RealmModel ឬ RealmList បន្ទាប់មកបន្ថែមវត្ថុនៃវាលនេះទៅក្នុងបញ្ជីវត្ថុដែលបានដាក់។ អ្វីគ្រប់យ៉ាងគឺដូចគ្នាទៅនឹងអ្វីដែលយើងបានធ្វើខាងលើដែរ មានតែនៅទីនេះប៉ុណ្ណោះដែលវានឹងធ្វើដោយខ្លួនឯង។ វិធីសាស្ត្រលុបល្បាក់ដោយខ្លួនវាគឺសាមញ្ញណាស់ ហើយមើលទៅដូចនេះ៖
fun <T : Any> Realm.cascadeDelete(entities: Collection<T?>) {
if(entities.isEmpty()) {
return
}
entities.filterNotNull().let { notNullEntities ->
notNullEntities
.filterRealmObject()
.flatMap { realmObject -> getNestedRealmObjects(realmObject) }
.also { realmObjects -> cascadeDelete(realmObjects) }
notNullEntities
.forEach { entity ->
if((entity is RealmObject) && entity.isValid) {
entity.deleteFromRealm()
}
}
}
}
ផ្នែកបន្ថែម filterRealmObject ច្រោះចេញ ហើយឆ្លងកាត់តែវត្ថុ Realm ប៉ុណ្ណោះ។ វិធីសាស្រ្ត getNestedRealmObjects តាមរយៈការឆ្លុះបញ្ជាំង វារកឃើញវត្ថុ Realm ទាំងអស់ដែលដាក់ក្នុងសំបុក ហើយដាក់វាចូលទៅក្នុងបញ្ជីលីនេអ៊ែរ។ បន្ទាប់មកយើងធ្វើដូចគ្នាដដែលៗ។ នៅពេលលុប អ្នកត្រូវពិនិត្យមើលវត្ថុសម្រាប់សុពលភាព isValidពីព្រោះវាអាចថាវត្ថុមេផ្សេងៗគ្នាអាចមានវត្ថុដូចគ្នាបេះបិទ។ វាជាការល្អប្រសើរជាងមុនដើម្បីជៀសវាងបញ្ហានេះ ហើយគ្រាន់តែប្រើការបង្កើតលេខសម្គាល់ដោយស្វ័យប្រវត្តិនៅពេលបង្កើតវត្ថុថ្មី។

ការអនុវត្តពេញលេញនៃវិធីសាស្ត្រ getNestedRealmObjects
private fun getNestedRealmObjects(realmObject: RealmObject) : List<RealmObject> {
val nestedObjects = mutableListOf<RealmObject>()
val fields = realmObject.javaClass.superclass.declaredFields
// Проверяем каждое поле, не является ли оно RealmModel или списком RealmList
fields.forEach { field ->
when {
RealmModel::class.java.isAssignableFrom(field.type) -> {
try {
val child = getChildObjectByField(realmObject, field)
child?.let {
if (isInstanceOfRealmObject(it)) {
nestedObjects.add(child as RealmObject)
}
}
} catch (e: Exception) { ... }
}
RealmList::class.java.isAssignableFrom(field.type) -> {
try {
val childList = getChildObjectByField(realmObject, field)
childList?.let { list ->
(list as RealmList<*>).forEach {
if (isInstanceOfRealmObject(it)) {
nestedObjects.add(it as RealmObject)
}
}
}
} catch (e: Exception) { ... }
}
}
}
return nestedObjects
}
private fun getChildObjectByField(realmObject: RealmObject, field: Field): Any? {
val methodName = "get${field.name.capitalize()}"
val method = realmObject.javaClass.getMethod(methodName)
return method.invoke(realmObject)
}
ជាលទ្ធផល នៅក្នុងកូដអតិថិជនរបស់យើង យើងប្រើ “cascading delete” សម្រាប់ប្រតិបត្តិការកែប្រែទិន្នន័យនីមួយៗ។ ឧទាហរណ៍ សម្រាប់ប្រតិបត្តិការបញ្ចូលវាមើលទៅដូចនេះ៖
override fun <T : Entity> insert(
entityInformation: EntityInformation,
entities: Collection<T>): Collection<T> = entities.apply {
realmInstance.cascadeDelete(getManagedEntities(entityInformation, this))
realmInstance.copyFromRealm(
realmInstance
.copyToRealmOrUpdate(this.map { entity -> entity as RealmModel }
))
} វិធីសាស្រ្តដំបូង getManagedEntities ទទួលវត្ថុបន្ថែមទាំងអស់ ហើយបន្ទាប់មកវិធីសាស្ត្រ cascadeDelete លុបវត្ថុដែលបានប្រមូលទាំងអស់ឡើងវិញម្តងហើយម្តងទៀត មុនពេលសរសេរថ្មី។ យើងបញ្ចប់ដោយប្រើវិធីសាស្រ្តនេះពេញមួយកម្មវិធី។ ការលេចធ្លាយអង្គចងចាំនៅក្នុង Realm ត្រូវបានបាត់បង់ទាំងស្រុង។ ដោយបានអនុវត្តការវាស់វែងដូចគ្នានៃការពឹងផ្អែកនៃពេលវេលាចាប់ផ្តើមនៅលើចំនួននៃការចាប់ផ្តើមត្រជាក់នៃកម្មវិធីយើងឃើញលទ្ធផល។

បន្ទាត់ពណ៌បៃតងបង្ហាញពីភាពអាស្រ័យនៃពេលវេលាចាប់ផ្តើមកម្មវិធីលើចំនួននៃការចាប់ផ្តើមត្រជាក់កំឡុងពេលការលុបដោយស្វ័យប្រវត្តិនៃវត្ថុដែលបានដាក់ជាប់គ្នា។
លទ្ធផលនិងការសន្និដ្ឋាន
មូលដ្ឋានទិន្នន័យ Realm ដែលកំពុងរីកចម្រើនឥតឈប់ឈរបានធ្វើឱ្យកម្មវិធីចាប់ផ្តើមដំណើរការយឺតណាស់។ យើងបានចេញផ្សាយការអាប់ដេតជាមួយនឹង "cascading delete" របស់យើងផ្ទាល់នៃវត្ថុដែលបានដាក់។ ហើយឥឡូវនេះ យើងតាមដាន និងវាយតម្លៃពីរបៀបដែលការសម្រេចចិត្តរបស់យើងប៉ះពាល់ដល់ពេលវេលាចាប់ផ្តើមកម្មវិធីតាមរយៈម៉ែត្រ _app_start ។

សម្រាប់ការវិភាគ យើងចំណាយពេល 90 ថ្ងៃ ហើយឃើញ៖ ពេលវេលាចាប់ផ្តើមកម្មវិធី ទាំងមធ្យមភាគ និងដែលធ្លាក់លើភាគរយនៃអ្នកប្រើប្រាស់ទី 95 បានចាប់ផ្តើមថយចុះ និងលែងកើនឡើងទៀតហើយ។

ប្រសិនបើអ្នកក្រឡេកមើលតារាងរយៈពេលប្រាំពីរថ្ងៃ នោះម៉ែត្រ _app_start មើលទៅគ្រប់គ្រាន់ទាំងស្រុង ហើយតិចជាង 1 វិនាទី។
វាក៏មានតម្លៃបន្ថែមថា តាមលំនាំដើម Firebase ផ្ញើការជូនដំណឹង ប្រសិនបើតម្លៃមធ្យមនៃ _app_start លើសពី 5 វិនាទី។ ទោះជាយ៉ាងណាក៏ដោយ ដូចដែលយើងឃើញហើយ អ្នកមិនគួរពឹងផ្អែកលើរឿងនេះទេ ប៉ុន្តែត្រូវចូលទៅពិនិត្យឱ្យបានច្បាស់លាស់។
អ្វីដែលពិសេសអំពីមូលដ្ឋានទិន្នន័យ Realm គឺថាវាជាមូលដ្ឋានទិន្នន័យដែលមិនទាក់ទង។ ទោះបីជាមានភាពងាយស្រួលក្នុងការប្រើប្រាស់ ភាពស្រដៀងគ្នាទៅនឹងដំណោះស្រាយ ORM និងការភ្ជាប់វត្ថុក៏ដោយ វាមិនមានការលុបល្បាក់ទេ។
ប្រសិនបើវាមិនត្រូវបានគេយកមកពិចារណាទេ នោះវត្ថុដែលដាក់នៅក្នុងសំបុកនឹងកកកុញ ហើយ "លេចធ្លាយ" ។ មូលដ្ឋានទិន្នន័យនឹងកើនឡើងឥតឈប់ឈរ ដែលនឹងប៉ះពាល់ដល់ការយឺតយ៉ាវ ឬការចាប់ផ្តើមកម្មវិធី។
ខ្ញុំបានចែករំលែកបទពិសោធន៍របស់យើងអំពីរបៀបលុបវត្ថុក្នុង Realm យ៉ាងរហ័ស ដែលមិនទាន់ចេញពីប្រអប់ ប៉ុន្តែត្រូវបាននិយាយជាយូរមកហើយ и . ក្នុងករណីរបស់យើង វាបង្កើនល្បឿនពេលវេលាចាប់ផ្តើមកម្មវិធីយ៉ាងខ្លាំង។
ទោះបីជាមានការពិភាក្សាអំពីរូបរាងដែលជិតមកដល់នៃលក្ខណៈពិសេសនេះក៏ដោយ ក៏អវត្តមាននៃការលុបល្បាក់នៅក្នុង Realm គឺធ្វើឡើងដោយការរចនា។ ប្រសិនបើអ្នកកំពុងរចនាកម្មវិធីថ្មី សូមយកវាទៅក្នុងគណនី។ ហើយប្រសិនបើអ្នកកំពុងប្រើ Realm រួចហើយ សូមពិនិត្យមើលថាតើអ្នកមានបញ្ហាបែបនេះដែរឬទេ។
ប្រភព: www.habr.com

