Ang kuwento kung paano nanalo ang cascade deletion sa Realm sa mahabang paglulunsad

Ang lahat ng mga user ay gumagamit ng mabilis na paglulunsad at tumutugon na UI sa mga mobile application para sa ipinagkaloob. Kung ang application ay tumatagal ng mahabang oras upang ilunsad, ang gumagamit ay magsisimulang malungkot at galit. Madali mong masira ang karanasan ng customer o tuluyang mawala ang user kahit na bago pa niya simulan ang paggamit ng application.

Minsan naming natuklasan na ang Dodo Pizza app ay tumatagal ng 3 segundo upang ilunsad sa karaniwan, at para sa ilang "masuwerteng" ito ay tumatagal ng 15-20 segundo.

Sa ibaba ng hiwa ay isang kuwento na may masayang pagtatapos: tungkol sa paglaki ng database ng Realm, isang memory leak, kung paano kami nag-ipon ng mga nested na bagay, at pagkatapos ay pinagsama ang aming mga sarili at inayos ang lahat.

Ang kuwento kung paano nanalo ang cascade deletion sa Realm sa mahabang paglulunsad

Ang kuwento kung paano nanalo ang cascade deletion sa Realm sa mahabang paglulunsad
may-akda ng artikulo: Maxim Kachinkin β€” Android developer sa Dodo Pizza.

Tatlong segundo mula sa pag-click sa icon ng application hanggang sa onResume() ng unang aktibidad ay infinity. At para sa ilang mga gumagamit, ang oras ng pagsisimula ay umabot sa 15-20 segundo. Paano ito posible?

Isang napakaikling buod para sa mga walang oras na magbasa
Ang aming database ng Realm ay lumago nang walang katapusang. Ang ilang mga nested na bagay ay hindi tinanggal, ngunit patuloy na naipon. Ang oras ng pagsisimula ng application ay unti-unting tumaas. Pagkatapos ay inayos namin ito, at ang oras ng pagsisimula ay dumating sa target - ito ay naging mas mababa sa 1 segundo at hindi na tumaas. Ang artikulo ay naglalaman ng isang pagsusuri ng sitwasyon at dalawang solusyon - isang mabilis at isang normal.

Paghahanap at pagsusuri ng problema

Ngayon, ang anumang mobile application ay dapat na mabilis na ilunsad at maging tumutugon. Ngunit ito ay hindi lamang tungkol sa mobile app. Ang karanasan ng user sa pakikipag-ugnayan sa isang serbisyo at isang kumpanya ay isang kumplikadong bagay. Halimbawa, sa aming kaso, ang bilis ng paghahatid ay isa sa mga pangunahing tagapagpahiwatig para sa serbisyo ng pizza. Kung mabilis ang paghahatid, ang pizza ay magiging mainit, at ang customer na gustong kumain ngayon ay hindi na kailangang maghintay ng matagal. Para sa application, sa turn, ito ay mahalaga upang lumikha ng pakiramdam ng mabilis na serbisyo, dahil kung ang application ay tumatagal lamang ng 20 segundo upang ilunsad, kung gayon gaano katagal ka maghihintay para sa pizza?

Sa una, kami mismo ay nahaharap sa katotohanan na kung minsan ang application ay tumagal ng ilang segundo upang ilunsad, at pagkatapos ay nagsimula kaming makarinig ng mga reklamo mula sa iba pang mga kasamahan tungkol sa kung gaano katagal. Ngunit hindi namin nagawang paulit-ulit ang sitwasyong ito.

Gaano katagal ito? Ayon kay Dokumentasyon ng Google, kung ang isang malamig na pagsisimula ng isang aplikasyon ay tumatagal ng mas mababa sa 5 segundo, kung gayon ito ay itinuturing na "parang normal". Inilunsad ang Dodo Pizza Android app (ayon sa mga sukatan ng Firebase _app_start) sa malamig na simula sa karaniwan sa loob ng 3 segundo - "Hindi mahusay, hindi kakila-kilabot," gaya ng sinasabi nila.

Ngunit pagkatapos ay nagsimulang lumitaw ang mga reklamo na ang application ay tumagal ng napaka, napaka, napakatagal na oras upang ilunsad! Upang magsimula, nagpasya kaming sukatin kung ano ang "napaka, napaka, napakahaba". At ginamit namin ang Firebase trace para dito Trace ng pagsisimula ng app.

Ang kuwento kung paano nanalo ang cascade deletion sa Realm sa mahabang paglulunsad

Sinusukat ng karaniwang trace na ito ang oras sa pagitan ng sandaling binuksan ng user ang application at ang sandali na ang onResume() ng unang aktibidad ay naisakatuparan. Sa Firebase Console ang sukatang ito ay tinatawag na _app_start. Ito pala ay:

  • Ang mga oras ng startup para sa mga user na nasa itaas ng 95th percentile ay halos 20 segundo (mas mahaba pa ang ilan), sa kabila ng median cold startup time na mas mababa sa 5 segundo.
  • Ang oras ng pagsisimula ay hindi isang pare-parehong halaga, ngunit lumalaki sa paglipas ng panahon. Ngunit kung minsan ay may mga patak. Natagpuan namin ang pattern na ito noong tinaasan namin ang sukat ng pagsusuri sa 90 araw.

Ang kuwento kung paano nanalo ang cascade deletion sa Realm sa mahabang paglulunsad

Dalawang kaisipan ang pumasok sa isipan:

  1. May tumutulo.
  2. Ang "isang bagay" na ito ay ni-reset pagkatapos ng paglabas at pagkatapos ay muling tumutulo.

"Malamang na may database," naisip namin, at tama kami. Una, ginagamit namin ang database bilang isang cache; sa panahon ng paglilipat, nililinis namin ito. Pangalawa, ang database ay na-load kapag nagsimula ang application. Ang lahat ay magkatugma.

Ano ang mali sa database ng Realm

Sinimulan naming suriin kung paano nagbabago ang mga nilalaman ng database sa buhay ng application, mula sa unang pag-install at higit pa sa panahon ng aktibong paggamit. Maaari mong tingnan ang mga nilalaman ng database ng Realm sa pamamagitan ng stetho o nang mas detalyado at malinaw sa pamamagitan ng pagbubukas ng file sa pamamagitan ng Realm Studio. Upang tingnan ang mga nilalaman ng database sa pamamagitan ng ADB, kopyahin ang Realm database file:

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

Ang pagkakaroon ng pagtingin sa mga nilalaman ng database sa iba't ibang oras, nalaman namin na ang bilang ng mga bagay ng isang tiyak na uri ay patuloy na tumataas.

Ang kuwento kung paano nanalo ang cascade deletion sa Realm sa mahabang paglulunsad
Ang larawan ay nagpapakita ng isang fragment ng Realm Studio para sa dalawang file: sa kaliwa - ang application base ilang oras pagkatapos ng pag-install, sa kanan - pagkatapos ng aktibong paggamit. Ito ay makikita na ang bilang ng mga bagay ImageEntity ΠΈ MoneyType ay lumago nang malaki (ang screenshot ay nagpapakita ng bilang ng mga bagay ng bawat uri).

Relasyon sa pagitan ng paglago ng database at oras ng pagsisimula

Ang hindi nakokontrol na paglago ng database ay napakasama. Ngunit paano ito makakaapekto sa oras ng pagsisimula ng application? Napakadaling sukatin ito sa pamamagitan ng ActivityManager. Dahil Android 4.4, ipinapakita ng logcat ang log na may string na Ipinapakita at ang oras. Ang oras na ito ay katumbas ng agwat mula sa sandaling inilunsad ang application hanggang sa katapusan ng pag-render ng aktibidad. Sa panahong ito, nangyayari ang mga sumusunod na kaganapan:

  • Simulan ang proseso.
  • Pagsisimula ng mga bagay.
  • Paglikha at pagsisimula ng mga aktibidad.
  • Paggawa ng layout.
  • Pag-render ng application.

Nababagay sa amin. Kung nagpapatakbo ka ng ADB gamit ang -S at -W na mga flag, maaari kang makakuha ng pinahabang output sa oras ng pagsisimula:

adb shell am start -S -W ru.dodopizza.app/.MainActivity -c android.intent.category.LAUNCHER -a android.intent.action.MAIN

Kung kukunin mo ito mula doon grep -i WaitTime oras, maaari mong i-automate ang koleksyon ng sukatang ito at biswal na tingnan ang mga resulta. Ipinapakita ng graph sa ibaba ang pag-asa ng oras ng pagsisimula ng application sa bilang ng malamig na pagsisimula ng application.

Ang kuwento kung paano nanalo ang cascade deletion sa Realm sa mahabang paglulunsad

Kasabay nito, mayroong parehong likas na katangian ng ugnayan sa pagitan ng laki at paglago ng database, na lumago mula 4 MB hanggang 15 MB. Sa kabuuan, lumalabas na sa paglipas ng panahon (kasama ang paglago ng malamig na pagsisimula), ang parehong oras ng paglulunsad ng application at ang laki ng database ay tumaas. Mayroon kaming hypothesis sa aming mga kamay. Ngayon ang lahat na natitira ay upang kumpirmahin ang pagtitiwala. Samakatuwid, nagpasya kaming alisin ang mga "paglabas" at tingnan kung ito ay magpapabilis sa paglulunsad.

Mga dahilan para sa walang katapusang paglago ng database

Bago alisin ang "mga pagtagas", ito ay nagkakahalaga ng pag-unawa kung bakit sila lumitaw sa unang lugar. Para magawa ito, tandaan natin kung ano ang Realm.

Ang Realm ay isang non-relational na database. Binibigyang-daan ka nitong ilarawan ang mga ugnayan sa pagitan ng mga bagay sa katulad na paraan sa kung gaano karaming ORM relational database sa Android ang inilalarawan. Kasabay nito, ang Realm ay nag-iimbak ng mga bagay nang direkta sa memorya na may pinakamaliit na dami ng mga pagbabago at pagmamapa. Nagbibigay-daan ito sa iyo na magbasa ng data mula sa disk nang napakabilis, na siyang lakas ng Realm at kung bakit ito minamahal.

(Para sa mga layunin ng artikulong ito, ang paglalarawang ito ay magiging sapat para sa amin. Maaari kang magbasa nang higit pa tungkol sa Realm sa cool dokumentasyon o sa kanilang akademya).

Maraming mga developer ang nakasanayan na magtrabaho nang higit pa sa mga relational database (halimbawa, mga database ng ORM na may SQL sa ilalim ng hood). At ang mga bagay tulad ng cascading data deletion ay kadalasang tila isang ibinigay. Pero hindi sa Realm.

Sa pamamagitan ng paraan, ang tampok na pagtanggal ng kaskad ay tinanong nang mahabang panahon. Ito rebisyon ΠΈ isa pa, na nauugnay dito, ay aktibong tinalakay. May pakiramdam na malapit na itong matapos. Ngunit pagkatapos ang lahat ay isinalin sa pagpapakilala ng malakas at mahina na mga link, na awtomatikong malulutas din ang problemang ito. Medyo masigla at aktibo sa gawaing ito hiling ng hilahin, na na-pause sa ngayon dahil sa mga panloob na paghihirap.

Pag-leak ng data nang walang cascading na pagtanggal

Paano eksaktong tumagas ang data kung umaasa ka sa isang hindi umiiral na pagtanggal ng cascading? Kung mayroon kang nested na mga object ng Realm, dapat na tanggalin ang mga ito.
Tingnan natin ang isang (halos) tunay na halimbawa. Mayroon kaming isang bagay 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()

Ang produkto sa cart ay may iba't ibang field, kabilang ang isang larawan ImageEntity, mga naka-customize na sangkap CustomizationEntity. Gayundin, ang produkto sa cart ay maaaring isang combo na may sarili nitong hanay ng mga produkto RealmList (CartProductEntity). Ang lahat ng nakalistang field ay Realm object. Kung maglalagay kami ng bagong object (copyToRealm() / copyToRealmOrUpdate()) na may parehong id, ang object na ito ay ganap na ma-overwrite. Ngunit lahat ng panloob na bagay (larawan, customizationEntity at cartComboProducts) ay mawawalan ng koneksyon sa magulang at mananatili sa database.

Dahil nawala ang koneksyon sa kanila, hindi na namin sila binabasa o tinatanggal (maliban kung tahasan naming i-access ang mga ito o i-clear ang buong "talahanayan"). Tinawag namin itong "memory leaks".

Kapag nagtatrabaho tayo sa Realm, dapat nating tahasan ang lahat ng elemento at tahasang tanggalin ang lahat bago ang mga naturang operasyon. Magagawa ito, halimbawa, tulad nito:

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()
}
// ΠΈ ΠΏΠΎΡ‚ΠΎΠΌ ΡƒΠΆΠ΅ сохраняСм

Kung gagawin mo ito, ang lahat ay gagana ayon sa nararapat. Sa halimbawang ito, ipinapalagay namin na walang ibang nested Realm object sa loob ng image, customizationEntity, at cartComboProducts, kaya walang iba pang mga nested na loop at pagtanggal.

"Mabilis" na solusyon

Ang unang bagay na napagpasyahan naming gawin ay linisin ang pinakamabilis na lumalagong mga bagay at suriin ang mga resulta upang makita kung malulutas nito ang aming orihinal na problema. Una, ang pinakasimpleng at pinaka-intuitive na solusyon ay ginawa, ibig sabihin: ang bawat bagay ay dapat na responsable para sa pag-alis ng mga anak nito. Upang gawin ito, ipinakilala namin ang isang interface na nagbalik ng isang listahan ng mga nested Realm object nito:

interface NestedEntityAware {
 fun getNestedEntities(): Collection<RealmObject?>
}

At ipinatupad namin ito sa aming mga bagay sa Realm:

@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 ibinabalik namin ang lahat ng mga bata bilang isang patag na listahan. At ang bawat child object ay maaari ding magpatupad ng NestedEntityAware interface, na nagsasaad na mayroon itong mga panloob na Realm object na tatanggalin, halimbawa 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
   )
 }
}

At iba pa, ang pagpupugad ng mga bagay ay maaaring paulit-ulit.

Pagkatapos ay sumulat kami ng isang paraan na muling tinatanggal ang lahat ng mga nested na bagay. Paraan (ginawa bilang extension) deleteAllNestedEntities nakakakuha ng lahat ng top-level na bagay at pamamaraan deleteNestedRecursively Paulit-ulit na inaalis ang lahat ng nested object gamit ang NestedEntityAware interface:

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

Ginawa namin ito sa pinakamabilis na lumalagong mga bagay at sinuri kung ano ang nangyari.

Ang kuwento kung paano nanalo ang cascade deletion sa Realm sa mahabang paglulunsad

Bilang resulta, ang mga bagay na tinakpan namin ng solusyon na ito ay tumigil sa paglaki. At ang pangkalahatang paglago ng base ay bumagal, ngunit hindi huminto.

Ang "normal" na solusyon

Kahit na ang base ay nagsimulang lumaki nang mas mabagal, lumago pa rin ito. Kaya nagsimula kaming maghanap pa. Ang aming proyekto ay gumagawa ng napakaaktibong paggamit ng data caching sa Realm. Samakatuwid, ang pagsusulat ng lahat ng mga nested na bagay para sa bawat bagay ay labor-intensive, at ang panganib ng mga error ay tumataas, dahil maaari mong kalimutan na tukuyin ang mga bagay kapag binabago ang code.

Nais kong tiyakin na hindi ako gumamit ng mga interface, ngunit ang lahat ay gumagana sa sarili nitong.

Kapag gusto natin ang isang bagay na gumana nang mag-isa, kailangan nating gumamit ng pagmuni-muni. Upang gawin ito, maaari tayong dumaan sa bawat field ng klase at suriin kung ito ay isang Realm object o isang listahan ng mga object:

RealmModel::class.java.isAssignableFrom(field.type)

RealmList::class.java.isAssignableFrom(field.type)

Kung ang field ay isang RealmModel o RealmList, pagkatapos ay idagdag ang object ng field na ito sa isang listahan ng mga nested object. Ang lahat ay eksaktong kapareho ng ginawa natin sa itaas, dito lamang ito gagawin nang mag-isa. Ang mismong paraan ng pagtanggal ng kaskad ay napakasimple at ganito ang hitsura:

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

Extension filterRealmObject nagsasala at nagpapasa lamang ng mga bagay sa Realm. Pamamaraan getNestedRealmObjects sa pamamagitan ng pagmuni-muni, nahahanap nito ang lahat ng mga nested na bagay sa Realm at inilalagay ang mga ito sa isang linear na listahan. Pagkatapos ay ginagawa namin ang parehong bagay nang paulit-ulit. Kapag nagtatanggal, kailangan mong suriin ang bagay para sa bisa isValid, dahil maaaring ang iba't ibang parent object ay maaaring magkaroon ng nested na magkapareho. Mas mainam na iwasan ito at gumamit na lang ng auto-generation ng id kapag gumagawa ng mga bagong bagay.

Ang kuwento kung paano nanalo ang cascade deletion sa Realm sa mahabang paglulunsad

Buong pagpapatupad ng getNestedRealmObjects method

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

Π’ ΠΈΡ‚ΠΎΠ³Π΅ Π² нашСм клиСнтском ΠΊΠΎΠ΄Π΅ ΠΌΡ‹ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅ΠΌ «каскадноС ΡƒΠ΄Π°Π»Π΅Π½ΠΈΠ΅Β» ΠΏΡ€ΠΈ ΠΊΠ°ΠΆΠ΄ΠΎΠΉ ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΈ измСнСния Π΄Π°Π½Π½Ρ‹Ρ…. НапримСр, для ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΈ вставки это выглядит Π²ΠΎΡ‚ Ρ‚Π°ΠΊ:

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

Pamamaraan muna getManagedEntities tumatanggap ng lahat ng idinagdag na bagay, at pagkatapos ay ang pamamaraan cascadeDelete Paulit-ulit na tinatanggal ang lahat ng nakolektang bagay bago magsulat ng mga bago. Natapos namin ang paggamit ng diskarteng ito sa buong application. Ang mga memory leak sa Realm ay ganap na nawala. Ang pagkakaroon ng isinasagawa ang parehong pagsukat ng pagtitiwala ng oras ng pagsisimula sa bilang ng malamig na pagsisimula ng aplikasyon, nakikita namin ang resulta.

Ang kuwento kung paano nanalo ang cascade deletion sa Realm sa mahabang paglulunsad

Ipinapakita ng berdeng linya ang pag-asa ng oras ng pagsisimula ng application sa bilang ng mga malamig na pagsisimula sa panahon ng awtomatikong cascade na pagtanggal ng mga nested na bagay.

Mga resulta at konklusyon

Ang patuloy na lumalagong database ng Realm ay naging sanhi ng paglunsad ng application nang napakabagal. Naglabas kami ng update gamit ang sarili naming "cascading delete" ng mga nested object. At ngayon, sinusubaybayan at sinusuri namin kung paano naapektuhan ng aming desisyon ang oras ng pagsisimula ng application sa pamamagitan ng sukatan ng _app_start.

Ang kuwento kung paano nanalo ang cascade deletion sa Realm sa mahabang paglulunsad

Para sa pagsusuri, tumagal kami ng 90 araw at tingnan: ang oras ng paglulunsad ng application, parehong median at yaong nasa ika-95 percentile ng mga user, ay nagsimulang bumaba at hindi na tumaas.

Ang kuwento kung paano nanalo ang cascade deletion sa Realm sa mahabang paglulunsad

Kung titingnan mo ang pitong araw na chart, ang sukatan ng _app_start ay mukhang ganap na sapat at wala pang 1 segundo.

Nararapat ding idagdag na bilang default, nagpapadala ang Firebase ng mga notification kung ang median na halaga ng _app_start ay lumampas sa 5 segundo. Gayunpaman, tulad ng nakikita natin, hindi ka dapat umasa dito, sa halip ay pumasok at suriin ito nang tahasan.

Ang espesyal na bagay tungkol sa database ng Realm ay ito ay isang hindi relasyonal na database. Sa kabila ng kadalian ng paggamit nito, pagkakatulad sa mga solusyon sa ORM at pag-link ng object, wala itong cascade deletion.

Kung hindi ito isasaalang-alang, ang mga nested na bagay ay maiipon at "tumagas." Patuloy na lalago ang database, na makakaapekto sa paghina o pagsisimula ng application.

Ibinahagi ko ang aming karanasan sa kung paano mabilis na gumawa ng isang kaskad na pagtanggal ng mga bagay sa Realm, na hindi pa out of the box, ngunit napag-usapan sa mahabang panahon sabi nila ΠΈ sabi nila. Sa aming kaso, lubos nitong pinabilis ang oras ng pagsisimula ng application.

Sa kabila ng talakayan tungkol sa nalalapit na hitsura ng feature na ito, ang kawalan ng cascade deletion sa Realm ay ginagawa ayon sa disenyo. Kung ikaw ay nagdidisenyo ng isang bagong application, pagkatapos ay isaalang-alang ito. At kung gumagamit ka na ng Realm, tingnan kung mayroon kang mga ganitong problema.

Pinagmulan: www.habr.com

Magdagdag ng komento