រឿងរ៉ាវនៃរបៀបដែលការលុបល្បាក់នៅក្នុង Realm បានឈ្នះលើការបើកដំណើរការដ៏យូរ

អ្នកប្រើប្រាស់ទាំងអស់ទទួលយកការបើកដំណើរការរហ័ស និងឆ្លើយតប UI នៅក្នុងកម្មវិធីទូរស័ព្ទសម្រាប់ការអនុញ្ញាត។ ប្រសិនបើកម្មវិធីចំណាយពេលយូរដើម្បីចាប់ផ្តើម អ្នកប្រើប្រាស់ចាប់ផ្តើមមានអារម្មណ៍សោកសៅ និងខឹង។ អ្នកអាចធ្វើឱ្យខូចបទពិសោធន៍របស់អតិថិជនយ៉ាងងាយស្រួល ឬបាត់បង់អ្នកប្រើប្រាស់ទាំងស្រុង មុនពេលគាត់ចាប់ផ្តើមប្រើប្រាស់កម្មវិធី។

យើងធ្លាប់បានរកឃើញថាកម្មវិធី Dodo Pizza ចំណាយពេល 3 វិនាទីដើម្បីចាប់ផ្តើមជាមធ្យម ហើយសម្រាប់ "អ្នកសំណាង" មួយចំនួនវាចំណាយពេល 15-20 វិនាទី។

ខាងក្រោមការកាត់គឺជារឿងមួយដែលមានការបញ្ចប់ដ៏រីករាយ៖ អំពីការរីកចម្រើននៃមូលដ្ឋានទិន្នន័យ Realm ការលេចធ្លាយអង្គចងចាំ របៀបដែលយើងប្រមូលផ្តុំវត្ថុដែលជាប់គាំង ហើយបន្ទាប់មកទាញខ្លួនយើងរួមគ្នា និងជួសជុលអ្វីៗគ្រប់យ៉ាង។

រឿងរ៉ាវនៃរបៀបដែលការលុបល្បាក់នៅក្នុង Realm បានឈ្នះលើការបើកដំណើរការដ៏យូរ

រឿងរ៉ាវនៃរបៀបដែលការលុបល្បាក់នៅក្នុង Realm បានឈ្នះលើការបើកដំណើរការដ៏យូរ
អ្នកនិពន្ធអត្ថបទ៖ Maxim Kachinkin - Android-អ្នកអភិវឌ្ឍន៍នៅ Dodo Pizza។

បីវិនាទីពីការចុចលើរូបតំណាងកម្មវិធីទៅ onResume() នៃសកម្មភាពដំបូងគឺគ្មានកំណត់។ ហើយសម្រាប់អ្នកប្រើប្រាស់មួយចំនួន ពេលវេលាចាប់ផ្តើមឡើងដល់ 15-20 វិនាទី។ តើនេះអាចទៅរួចដោយរបៀបណា?

សេចក្តីសង្ខេបខ្លីបំផុតសម្រាប់អ្នកដែលមិនមានពេលអាន
មូលដ្ឋានទិន្នន័យ Realm របស់យើងបានកើនឡើងឥតឈប់ឈរ។ វត្ថុ​ដែល​បាន​លាក់​មួយ​ចំនួន​មិន​ត្រូវ​បាន​លុប​ចេញ​ទេ ប៉ុន្តែ​ត្រូវ​បាន​បង្គរ​ឥត​ឈប់ឈរ។ ពេលវេលាចាប់ផ្តើមកម្មវិធីកើនឡើងជាលំដាប់។ បន្ទាប់មកយើងបានជួសជុលវា ហើយពេលវេលាចាប់ផ្តើមបានមកដល់គោលដៅ - វាបានក្លាយជាតិចជាង 1 វិនាទី ហើយមិនកើនឡើងទៀតទេ។ អត្ថបទនេះមានការវិភាគអំពីស្ថានភាព និងដំណោះស្រាយពីរ - មួយរហ័ស និងធម្មតា។

ការស្វែងរកនិងការវិភាគនៃបញ្ហា

សព្វ​ថ្ងៃ​នេះ កម្មវិធី​ទូរសព្ទ​ណា​មួយ​ត្រូវ​តែ​បើក​ដំណើរ​ការ​យ៉ាង​ឆាប់​រហ័ស និង​មាន​ការ​ឆ្លើយ​តប។ ប៉ុន្តែវាមិនមែនគ្រាន់តែអំពីកម្មវិធីទូរស័ព្ទប៉ុណ្ណោះទេ។ បទពិសោធន៍អ្នកប្រើប្រាស់នៃអន្តរកម្មជាមួយសេវាកម្ម និងក្រុមហ៊ុនគឺជារឿងស្មុគស្មាញ។ ជាឧទាហរណ៍ ក្នុងករណីរបស់យើង ល្បឿនដឹកជញ្ជូនគឺជាសូចនាករសំខាន់មួយសម្រាប់សេវាកម្មភីហ្សា។ ប្រសិនបើការដឹកជញ្ជូនលឿន ភីហ្សានឹងក្តៅ ហើយអតិថិជនដែលចង់ញ៉ាំឥឡូវនេះមិនបាច់រង់ចាំយូរទេ។ សម្រាប់កម្មវិធីវិញ វាជារឿងសំខាន់ក្នុងការបង្កើតអារម្មណ៍នៃសេវាកម្មលឿន ព្រោះថាប្រសិនបើកម្មវិធីប្រើពេលត្រឹមតែ 20 វិនាទីប៉ុណ្ណោះដើម្បីបើកដំណើរការ តើត្រូវរង់ចាំភីហ្សារយៈពេលប៉ុន្មាន?

ដំបូងឡើយ ខ្លួនយើងផ្ទាល់ត្រូវប្រឈមមុខនឹងការពិតដែលថា ពេលខ្លះកម្មវិធីប្រើពេលពីរបីវិនាទីដើម្បីចាប់ផ្តើម ហើយបន្ទាប់មកយើងចាប់ផ្តើមឮការត្អូញត្អែរពីមិត្តរួមការងារផ្សេងទៀតអំពីរយៈពេលដែលវាប្រើ។ ប៉ុន្តែ​យើង​មិន​អាច​ធ្វើ​ស្ថានភាព​នេះ​ឡើង​វិញ​ជា​ប្រចាំ។

តើវាមានរយៈពេលប៉ុន្មាន? យោង​ទៅ​តាម ឯកសារ Googleប្រសិនបើការចាប់ផ្តើមត្រជាក់នៃកម្មវិធីចំណាយពេលតិចជាង 5 វិនាទី វាត្រូវបានចាត់ទុកថា "ធម្មតា"។ Android- កម្មវិធី Dodo Pizza ត្រូវបានដាក់ឱ្យដំណើរការ (យោងតាមរង្វាស់ Firebase) _app_start) នៅ ការចាប់ផ្តើមត្រជាក់ ជាមធ្យមក្នុងរយៈពេល 3 វិនាទី - "មិនអស្ចារ្យ មិនគួរឱ្យភ័យខ្លាច" ដូចដែលពួកគេនិយាយ។

ប៉ុន្តែ​បន្ទាប់មក​មានការ​ត្អូញត្អែរ​បាន​ចាប់ផ្តើម​លេចឡើង​ថា​កម្មវិធី​នេះ​ចំណាយពេល​យូរ​ណាស់​ដើម្បី​ចាប់ផ្តើម​! ដើម្បីចាប់ផ្តើម យើងបានសម្រេចចិត្តវាស់វែងថាតើអ្វីជា "ខ្លាំងណាស់ យូរណាស់" ។ ហើយ​យើង​បាន​ប្រើ​ដាន Firebase សម្រាប់​រឿង​នេះ។ កម្មវិធីចាប់ផ្តើមតាមដាន.

រឿងរ៉ាវនៃរបៀបដែលការលុបល្បាក់នៅក្នុង Realm បានឈ្នះលើការបើកដំណើរការដ៏យូរ

ដានស្តង់ដារនេះវាស់ពេលវេលារវាងពេលដែលអ្នកប្រើប្រាស់បើកកម្មវិធី និងពេលដែល onResume() នៃសកម្មភាពដំបូងត្រូវបានប្រតិបត្តិ។ នៅក្នុង Firebase Console ម៉ែត្រនេះត្រូវបានគេហៅថា _app_start។ វាបានប្រែក្លាយថា:

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

រឿងរ៉ាវនៃរបៀបដែលការលុបល្បាក់នៅក្នុង Realm បានឈ្នះលើការបើកដំណើរការដ៏យូរ

គំនិតពីរបានកើតឡើង៖

  1. អ្វីមួយកំពុងលេចធ្លាយ។
  2. "អ្វីមួយ" នេះត្រូវបានកំណត់ឡើងវិញបន្ទាប់ពីការចេញផ្សាយហើយបន្ទាប់មកលេចធ្លាយម្តងទៀត។

"ប្រហែលជាអ្វីមួយជាមួយនឹងមូលដ្ឋានទិន្នន័យ" យើងបានគិត ហើយយើងនិយាយត្រូវ។ ទីមួយ យើងប្រើមូលដ្ឋានទិន្នន័យជាឃ្លាំងសម្ងាត់ កំឡុងពេលធ្វើចំណាកស្រុក យើងសម្អាតវា។ ទីពីរ មូលដ្ឋានទិន្នន័យត្រូវបានផ្ទុកនៅពេលកម្មវិធីចាប់ផ្តើម។ អ្វីគ្រប់យ៉ាងត្រូវគ្នា។

តើមានអ្វីខុសជាមួយមូលដ្ឋានទិន្នន័យ Realm

យើងបានចាប់ផ្តើមពិនិត្យមើលថាតើមាតិកានៃមូលដ្ឋានទិន្នន័យផ្លាស់ប្តូរលើជីវិតរបស់កម្មវិធី ចាប់ពីការដំឡើងដំបូង និងបន្ថែមទៀតក្នុងអំឡុងពេលប្រើប្រាស់សកម្ម។ អ្នកអាចមើលមាតិកានៃមូលដ្ឋានទិន្នន័យ Realm តាមរយៈ ស្តូត ឬលម្អិតបន្ថែមទៀត និងច្បាស់លាស់ដោយបើកឯកសារតាមរយៈ Realm Studio. ដើម្បីមើលមាតិកានៃមូលដ្ឋានទិន្នន័យតាមរយៈ ADB សូមចម្លងឯកសារមូលដ្ឋានទិន្នន័យ Realm៖

adb exec-out run-as ${PACKAGE_NAME} cat files/${DB_NAME}

ដោយបានមើលមាតិកានៃមូលដ្ឋានទិន្នន័យនៅពេលវេលាផ្សេងៗគ្នា យើងបានរកឃើញថាចំនួនវត្ថុនៃប្រភេទជាក់លាក់មួយកំពុងកើនឡើងឥតឈប់ឈរ។

រឿងរ៉ាវនៃរបៀបដែលការលុបល្បាក់នៅក្នុង Realm បានឈ្នះលើការបើកដំណើរការដ៏យូរ
រូបភាពបង្ហាញពីបំណែកនៃ 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 ពេល​វេលា អ្នក​អាច​ធ្វើ​ស្វ័យប្រវត្តិកម្ម​ការ​ប្រមូល​ម៉ែត្រ​នេះ ហើយ​មើល​លទ្ធផល​ដោយ​ភ្នែក។ ក្រាហ្វខាងក្រោមបង្ហាញពីភាពអាស្រ័យនៃពេលវេលាចាប់ផ្តើមកម្មវិធីលើចំនួននៃការចាប់ផ្តើមត្រជាក់នៃកម្មវិធី។

រឿងរ៉ាវនៃរបៀបដែលការលុបល្បាក់នៅក្នុង Realm បានឈ្នះលើការបើកដំណើរការដ៏យូរ

ក្នុងពេលជាមួយគ្នានេះមានលក្ខណៈដូចគ្នានៃទំនាក់ទំនងរវាងទំហំនិងការលូតលាស់នៃមូលដ្ឋានទិន្នន័យដែលបានកើនឡើងពី 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 ។ ដូច្នេះហើយ ការសរសេរវត្ថុដែលជាប់គាំងទាំងអស់សម្រាប់វត្ថុនីមួយៗគឺពឹងផ្អែកលើកម្លាំងពលកម្ម បូកនឹងហានិភ័យនៃកំហុសកើនឡើង ព្រោះអ្នកអាចភ្លេចបញ្ជាក់វត្ថុនៅពេលផ្លាស់ប្តូរកូដ។

ខ្ញុំ​ចង់​ធ្វើ​ឱ្យ​ប្រាកដ​ថា​ខ្ញុំ​មិន​បាន​ប្រើ​ចំណុច​ប្រទាក់​, ប៉ុន្តែ​ថា​អ្វី​គ្រប់​យ៉ាង​ធ្វើ​ការ​ដោយ​ខ្លួន​ឯង​។

នៅពេលដែលយើងចង់ឱ្យអ្វីមួយដំណើរការដោយខ្លួនឯង យើងត្រូវប្រើការឆ្លុះបញ្ចាំង។ ដើម្បីធ្វើដូច្នេះ យើងអាចឆ្លងកាត់ថ្នាក់នីមួយៗ ហើយពិនិត្យមើលថាតើវាជាវត្ថុ 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ពីព្រោះវាអាចថាវត្ថុមេផ្សេងៗគ្នាអាចមានវត្ថុដូចគ្នាបេះបិទ។ វាជាការល្អប្រសើរជាងមុនដើម្បីជៀសវាងបញ្ហានេះ ហើយគ្រាន់តែប្រើការបង្កើតលេខសម្គាល់ដោយស្វ័យប្រវត្តិនៅពេលបង្កើតវត្ថុថ្មី។

រឿងរ៉ាវនៃរបៀបដែលការលុបល្បាក់នៅក្នុង Realm បានឈ្នះលើការបើកដំណើរការដ៏យូរ

ការអនុវត្តពេញលេញនៃវិធីសាស្ត្រ 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 បានឈ្នះលើការបើកដំណើរការដ៏យូរ

បន្ទាត់ពណ៌បៃតងបង្ហាញពីភាពអាស្រ័យនៃពេលវេលាចាប់ផ្តើមកម្មវិធីលើចំនួននៃការចាប់ផ្តើមត្រជាក់កំឡុងពេលការលុបដោយស្វ័យប្រវត្តិនៃវត្ថុដែលបានដាក់ជាប់គ្នា។

លទ្ធផលនិងការសន្និដ្ឋាន

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

រឿងរ៉ាវនៃរបៀបដែលការលុបល្បាក់នៅក្នុង Realm បានឈ្នះលើការបើកដំណើរការដ៏យូរ

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

រឿងរ៉ាវនៃរបៀបដែលការលុបល្បាក់នៅក្នុង Realm បានឈ្នះលើការបើកដំណើរការដ៏យូរ

ប្រសិនបើអ្នកក្រឡេកមើលតារាងរយៈពេលប្រាំពីរថ្ងៃ នោះម៉ែត្រ _app_start មើលទៅគ្រប់គ្រាន់ទាំងស្រុង ហើយតិចជាង 1 វិនាទី។

វាក៏មានតម្លៃបន្ថែមថា តាមលំនាំដើម Firebase ផ្ញើការជូនដំណឹង ប្រសិនបើតម្លៃមធ្យមនៃ _app_start លើសពី 5 វិនាទី។ ទោះជាយ៉ាងណាក៏ដោយ ដូចដែលយើងឃើញហើយ អ្នកមិនគួរពឹងផ្អែកលើរឿងនេះទេ ប៉ុន្តែត្រូវចូលទៅពិនិត្យឱ្យបានច្បាស់លាស់។

អ្វីដែលពិសេសអំពីមូលដ្ឋានទិន្នន័យ Realm គឺថាវាជាមូលដ្ឋានទិន្នន័យដែលមិនទាក់ទង។ ទោះបីជាមានភាពងាយស្រួលក្នុងការប្រើប្រាស់ ភាពស្រដៀងគ្នាទៅនឹងដំណោះស្រាយ ORM និងការភ្ជាប់វត្ថុក៏ដោយ វាមិនមានការលុបល្បាក់ទេ។

ប្រសិនបើវាមិនត្រូវបានគេយកមកពិចារណាទេ នោះវត្ថុដែលដាក់នៅក្នុងសំបុកនឹងកកកុញ ហើយ "លេចធ្លាយ" ។ មូលដ្ឋានទិន្នន័យនឹងកើនឡើងឥតឈប់ឈរ ដែលនឹងប៉ះពាល់ដល់ការយឺតយ៉ាវ ឬការចាប់ផ្តើមកម្មវិធី។

ខ្ញុំបានចែករំលែកបទពិសោធន៍របស់យើងអំពីរបៀបលុបវត្ថុក្នុង Realm យ៉ាងរហ័ស ដែលមិនទាន់ចេញពីប្រអប់ ប៉ុន្តែត្រូវបាននិយាយជាយូរមកហើយ និយាយ и និយាយ. ក្នុងករណីរបស់យើង វាបង្កើនល្បឿនពេលវេលាចាប់ផ្តើមកម្មវិធីយ៉ាងខ្លាំង។

ទោះបីជាមានការពិភាក្សាអំពីរូបរាងដែលជិតមកដល់នៃលក្ខណៈពិសេសនេះក៏ដោយ ក៏អវត្តមាននៃការលុបល្បាក់នៅក្នុង Realm គឺធ្វើឡើងដោយការរចនា។ ប្រសិនបើអ្នកកំពុងរចនាកម្មវិធីថ្មី សូមយកវាទៅក្នុងគណនី។ ហើយប្រសិនបើអ្នកកំពុងប្រើ Realm រួចហើយ សូមពិនិត្យមើលថាតើអ្នកមានបញ្ហាបែបនេះដែរឬទេ។

ប្រភព: www.habr.com

ទិញការបង្ហោះដែលអាចទុកចិត្តបានសម្រាប់គេហទំព័រដែលមានការការពារ DDoS, ម៉ាស៊ីនមេ VPS VDS 🔥 ទិញសេវាបង្ហោះគេហទំព័រដែលអាចទុកចិត្តបានជាមួយនឹងការការពារ DDoS និងម៉ាស៊ីនមេ VPS VDS | ProHoster