Утечка загружаемого шрифта Android от FontsContractCompat в Android Pie (9)

В моем приложении произошла утечка памяти из-за использования функции DownloadableFont. Утечка происходит только в эмуляторе, работающем на Android 9. Похоже, это происходит, когда эмулятору не удается кэшировать шрифт и FontsContractCompatдолжен перейти на сервер Google (или что-то еще), чтобы загрузить шрифт.

Воспроизвести шаги:

  • Сотрите данные эмулятора.
  • Откройте мое приложение.
  • Путешествуйте через приложение. (Я использую инструмент обезьяны для запуска ~9000 событий, чтобы получить утечку).

Утечка случайным образом происходит везде, где используются шрифты.

Вот трассировка утечки из LeakCanary:

      Analysis in progress, working on: REPORTING_HEAP_ANALYSIS
2021-03-02 14:26:28.321 4800-6564/my.app.package D/LeakCanary: ====================================
2021-03-02 14:26:28.321 4800-6564/my.app.package D/LeakCanary: HEAP ANALYSIS RESULT
2021-03-02 14:26:28.321 4800-6564/my.app.package D/LeakCanary: ====================================
2021-03-02 14:26:28.321 4800-6564/my.app.package D/LeakCanary: 1 APPLICATION LEAKS
2021-03-02 14:26:28.321 4800-6564/my.app.package D/LeakCanary: References underlined with "~~~" are likely causes.
2021-03-02 14:26:28.321 4800-6564/my.app.package D/LeakCanary: Learn more at https://squ.re/leaks.
2021-03-02 14:26:28.322 4800-6564/my.app.package D/LeakCanary: 500077 bytes retained by leaking objects
2021-03-02 14:26:28.322 4800-6564/my.app.package D/LeakCanary: Signature: a57defa6cf388ebf6313be9d96410abfc599a45
2021-03-02 14:26:28.322 4800-6564/my.app.package D/LeakCanary: ┬───
2021-03-02 14:26:28.322 4800-6564/my.app.package D/LeakCanary: │ GC Root: Input or output parameters in native code
2021-03-02 14:26:28.322 4800-6564/my.app.package D/LeakCanary: │
2021-03-02 14:26:28.322 4800-6564/my.app.package D/LeakCanary: ├─ okio.AsyncTimeout class
2021-03-02 14:26:28.322 4800-6564/my.app.package D/LeakCanary: │    Leaking: NO (PathClassLoader↓ is not leaking and a class is never leaking)
2021-03-02 14:26:28.322 4800-6564/my.app.package D/LeakCanary: │    ↓ static AsyncTimeout.$class$classLoader
2021-03-02 14:26:28.322 4800-6564/my.app.package D/LeakCanary: ├─ dalvik.system.PathClassLoader instance
2021-03-02 14:26:28.322 4800-6564/my.app.package D/LeakCanary: │    Leaking: NO (FontsContractCompat↓ is not leaking and A ClassLoader is never leaking)
2021-03-02 14:26:28.322 4800-6564/my.app.package D/LeakCanary: │    ↓ PathClassLoader.runtimeInternalObjects
2021-03-02 14:26:28.322 4800-6564/my.app.package D/LeakCanary: ├─ java.lang.Object[] array
2021-03-02 14:26:28.322 4800-6564/my.app.package D/LeakCanary: │    Leaking: NO (FontsContractCompat↓ is not leaking)
2021-03-02 14:26:28.322 4800-6564/my.app.package D/LeakCanary: │    ↓ Object[].[21]
2021-03-02 14:26:28.322 4800-6564/my.app.package D/LeakCanary: ├─ androidx.core.provider.FontsContractCompat class
2021-03-02 14:26:28.322 4800-6564/my.app.package D/LeakCanary: │    Leaking: NO (a class is never leaking)
2021-03-02 14:26:28.322 4800-6564/my.app.package D/LeakCanary: │    ↓ static FontsContractCompat.sPendingReplies
2021-03-02 14:26:28.322 4800-6564/my.app.package D/LeakCanary: │                                 ~~~~~~~~~~~~~~~
2021-03-02 14:26:28.322 4800-6564/my.app.package D/LeakCanary: ├─ androidx.collection.SimpleArrayMap instance
2021-03-02 14:26:28.322 4800-6564/my.app.package D/LeakCanary: │    Leaking: UNKNOWN
2021-03-02 14:26:28.322 4800-6564/my.app.package D/LeakCanary: │    ↓ SimpleArrayMap.mArray
2021-03-02 14:26:28.322 4800-6564/my.app.package D/LeakCanary: │                     ~~~~~~
2021-03-02 14:26:28.322 4800-6564/my.app.package D/LeakCanary: ├─ java.lang.Object[] array
2021-03-02 14:26:28.322 4800-6564/my.app.package D/LeakCanary: │    Leaking: UNKNOWN
2021-03-02 14:26:28.322 4800-6564/my.app.package D/LeakCanary: │    ↓ Object[].[3]
2021-03-02 14:26:28.322 4800-6564/my.app.package D/LeakCanary: │               ~~~
2021-03-02 14:26:28.322 4800-6564/my.app.package D/LeakCanary: ├─ java.util.ArrayList instance
2021-03-02 14:26:28.322 4800-6564/my.app.package D/LeakCanary: │    Leaking: UNKNOWN
2021-03-02 14:26:28.322 4800-6564/my.app.package D/LeakCanary: │    ↓ ArrayList.elementData
2021-03-02 14:26:28.322 4800-6564/my.app.package D/LeakCanary: │                ~~~~~~~~~~~
2021-03-02 14:26:28.322 4800-6564/my.app.package D/LeakCanary: ├─ java.lang.Object[] array
2021-03-02 14:26:28.322 4800-6564/my.app.package D/LeakCanary: │    Leaking: UNKNOWN
2021-03-02 14:26:28.322 4800-6564/my.app.package D/LeakCanary: │    ↓ Object[].[0]
2021-03-02 14:26:28.322 4800-6564/my.app.package D/LeakCanary: │               ~~~
2021-03-02 14:26:28.322 4800-6564/my.app.package D/LeakCanary: ├─ androidx.core.provider.FontsContractCompat$2 instance
2021-03-02 14:26:28.322 4800-6564/my.app.package D/LeakCanary: │    Leaking: UNKNOWN
2021-03-02 14:26:28.322 4800-6564/my.app.package D/LeakCanary: │    Anonymous class implementing androidx.core.provider.SelfDestructiveThread$ReplyCallback
2021-03-02 14:26:28.322 4800-6564/my.app.package D/LeakCanary: │    ↓ FontsContractCompat$2.val$fontCallback
2021-03-02 14:26:28.322 4800-6564/my.app.package D/LeakCanary: │                            ~~~~~~~~~~~~~~~~
2021-03-02 14:26:28.322 4800-6564/my.app.package D/LeakCanary: ├─ androidx.appcompat.widget.AppCompatTextHelper$1 instance
2021-03-02 14:26:28.322 4800-6564/my.app.package D/LeakCanary: │    Leaking: UNKNOWN
2021-03-02 14:26:28.322 4800-6564/my.app.package D/LeakCanary: │    Anonymous subclass of androidx.core.content.res.ResourcesCompat$FontCallback
2021-03-02 14:26:28.322 4800-6564/my.app.package D/LeakCanary: │    ↓ AppCompatTextHelper$1.this$0
2021-03-02 14:26:28.322 4800-6564/my.app.package D/LeakCanary: │                            ~~~~~~
2021-03-02 14:26:28.322 4800-6564/my.app.package D/LeakCanary: ├─ androidx.appcompat.widget.AppCompatTextHelper instance
2021-03-02 14:26:28.322 4800-6564/my.app.package D/LeakCanary: │    Leaking: UNKNOWN
2021-03-02 14:26:28.322 4800-6564/my.app.package D/LeakCanary: │    ↓ AppCompatTextHelper.mView
2021-03-02 14:26:28.322 4800-6564/my.app.package D/LeakCanary: │                          ~~~~~
2021-03-02 14:26:28.322 4800-6564/my.app.package D/LeakCanary: ├─ com.google.android.material.button.MaterialButton instance
2021-03-02 14:26:28.322 4800-6564/my.app.package D/LeakCanary: │    Leaking: YES (View detached and has parent)
2021-03-02 14:26:28.322 4800-6564/my.app.package D/LeakCanary: │    mContext instance of android.view.ContextThemeWrapper, wrapping activity my.app.package.MyActivity with mDestroyed = false
2021-03-02 14:26:28.322 4800-6564/my.app.package D/LeakCanary: │    View#mParent is set
2021-03-02 14:26:28.322 4800-6564/my.app.package D/LeakCanary: │    View#mAttachInfo is null (view detached)
2021-03-02 14:26:28.322 4800-6564/my.app.package D/LeakCanary: │    View.mID = R.id.signInButton
2021-03-02 14:26:28.322 4800-6564/my.app.package D/LeakCanary: │    View.mWindowAttachCount = 1
2021-03-02 14:26:28.322 4800-6564/my.app.package D/LeakCanary: │    ↓ MaterialButton.mParent
2021-03-02 14:26:28.322 4800-6564/my.app.package D/LeakCanary: ├─ androidx.constraintlayout.widget.ConstraintLayout instance
2021-03-02 14:26:28.322 4800-6564/my.app.package D/LeakCanary: │    Leaking: YES (MaterialButton↑ is leaking and View detached and has parent)
2021-03-02 14:26:28.322 4800-6564/my.app.package D/LeakCanary: │    mContext instance of android.view.ContextThemeWrapper, wrapping activity my.app.package.MyActivity with mDestroyed = false
2021-03-02 14:26:28.322 4800-6564/my.app.package D/LeakCanary: │    View#mParent is set
2021-03-02 14:26:28.322 4800-6564/my.app.package D/LeakCanary: │    View#mAttachInfo is null (view detached)
2021-03-02 14:26:28.322 4800-6564/my.app.package D/LeakCanary: │    View.mID = R.id.signInLayout
2021-03-02 14:26:28.322 4800-6564/my.app.package D/LeakCanary: │    View.mWindowAttachCount = 1
2021-03-02 14:26:28.322 4800-6564/my.app.package D/LeakCanary: │    ↓ ConstraintLayout.mParent
2021-03-02 14:26:28.322 4800-6564/my.app.package D/LeakCanary: ├─ androidx.constraintlayout.widget.ConstraintLayout instance
2021-03-02 14:26:28.322 4800-6564/my.app.package D/LeakCanary: │    Leaking: YES (ConstraintLayout↑ is leaking and View detached and has parent)
2021-03-02 14:26:28.322 4800-6564/my.app.package D/LeakCanary: │    mContext instance of android.view.ContextThemeWrapper, wrapping activity my.app.package.MyActivity with mDestroyed = false
2021-03-02 14:26:28.322 4800-6564/my.app.package D/LeakCanary: │    View#mParent is set
2021-03-02 14:26:28.322 4800-6564/my.app.package D/LeakCanary: │    View#mAttachInfo is null (view detached)
2021-03-02 14:26:28.322 4800-6564/my.app.package D/LeakCanary: │    View.mID = R.id.ll_portfolio_auth_content
2021-03-02 14:26:28.322 4800-6564/my.app.package D/LeakCanary: │    View.mWindowAttachCount = 1
2021-03-02 14:26:28.322 4800-6564/my.app.package D/LeakCanary: │    ↓ ConstraintLayout.mParent
2021-03-02 14:26:28.322 4800-6564/my.app.package D/LeakCanary: ├─ androidx.core.widget.NestedScrollView instance
2021-03-02 14:26:28.322 4800-6564/my.app.package D/LeakCanary: │    Leaking: YES (ConstraintLayout↑ is leaking and View detached and has parent)
2021-03-02 14:26:28.322 4800-6564/my.app.package D/LeakCanary: │    mContext instance of android.view.ContextThemeWrapper, wrapping activity my.app.package.MyActivity with mDestroyed = false
2021-03-02 14:26:28.322 4800-6564/my.app.package D/LeakCanary: │    View#mParent is set
2021-03-02 14:26:28.322 4800-6564/my.app.package D/LeakCanary: │    View#mAttachInfo is null (view detached)
2021-03-02 14:26:28.322 4800-6564/my.app.package D/LeakCanary: │    View.mWindowAttachCount = 1
2021-03-02 14:26:28.322 4800-6564/my.app.package D/LeakCanary: │    ↓ NestedScrollView.mParent
2021-03-02 14:26:28.322 4800-6564/my.app.package D/LeakCanary: ╰→ my.app.package.MyCustomizedCoordinatorLayout instance
2021-03-02 14:26:28.322 4800-6564/my.app.package D/LeakCanary: ​     Leaking: YES (ObjectWatcher was watching this because my.app.package.MyFragment received Fragment#onDestroyView() callback (references to its views should be cleared to prevent leaks))
2021-03-02 14:26:28.322 4800-6564/my.app.package D/LeakCanary: ​     key = f5e3a6d2-3f04-40ed-9e67-2788011fe63b
2021-03-02 14:26:28.322 4800-6564/my.app.package D/LeakCanary: ​     watchDurationMillis = 13097
2021-03-02 14:26:28.322 4800-6564/my.app.package D/LeakCanary: ​     retainedDurationMillis = 8096
2021-03-02 14:26:28.322 4800-6564/my.app.package D/LeakCanary: ​     mContext instance of android.view.ContextThemeWrapper, wrapping activity my.app.package.MyActivity with mDestroyed = false
2021-03-02 14:26:28.322 4800-6564/my.app.package D/LeakCanary: ​     View#mParent is null
2021-03-02 14:26:28.322 4800-6564/my.app.package D/LeakCanary: ​     View#mAttachInfo is null (view detached)
2021-03-02 14:26:28.322 4800-6564/my.app.package D/LeakCanary: ​     View.mID = R.id.portfolio_fragment
2021-03-02 14:26:28.322 4800-6564/my.app.package D/LeakCanary: ​     View.mWindowAttachCount = 1
2021-03-02 14:26:28.322 4800-6564/my.app.package D/LeakCanary: ====================================
2021-03-02 14:26:28.322 4800-6564/my.app.package D/LeakCanary: 0 LIBRARY LEAKS
2021-03-02 14:26:28.322 4800-6564/my.app.package D/LeakCanary: A Library Leak is a leak caused by a known bug in 3rd party code that you do not have control over.
2021-03-02 14:26:28.322 4800-6564/my.app.package D/LeakCanary: See https://square.github.io/leakcanary/fundamentals-how-leakcanary-works/#4-categorizing-leaks
2021-03-02 14:26:28.322 4800-6564/my.app.package D/LeakCanary: ====================================
2021-03-02 14:26:28.322 4800-6564/my.app.package D/LeakCanary: METADATA
2021-03-02 14:26:28.322 4800-6564/my.app.package D/LeakCanary: Please include this in bug reports and Stack Overflow questions.
2021-03-02 14:26:28.322 4800-6564/my.app.package D/LeakCanary: Build.VERSION.SDK_INT: 28
2021-03-02 14:26:28.322 4800-6564/my.app.package D/LeakCanary: Build.MANUFACTURER: Google
2021-03-02 14:26:28.322 4800-6564/my.app.package D/LeakCanary: LeakCanary version: 2.4
2021-03-02 14:26:28.322 4800-6564/my.app.package D/LeakCanary: App process name: my.app.package
2021-03-02 14:26:28.322 4800-6564/my.app.package D/LeakCanary: Analysis duration: 7435 ms
2021-03-02 14:26:28.322 4800-6564/my.app.package D/LeakCanary: Heap dump file path: /data/user/0/my.app.package/files/leakcanary/2021-03-02_14-26-18_332.hprof
2021-03-02 14:26:28.322 4800-6564/my.app.package D/LeakCanary: Heap dump timestamp: 1614713188314

Вот детали эмулятора:

      

Name: Nexus_One_API_28

CPU/ABI: Google APIs Intel Atom (x86)

Path: /Users/mycomputer/.android/avd/Nexus_One_API_28.avd

Target: google_apis [Google APIs] (API level 28)

Skin: nexus_one

SD Card: 512 MB

fastboot.chosenSnapshotFile: 

runtime.network.speed: full

hw.accelerometer: yes

hw.device.name: Nexus One

hw.lcd.width: 480

hw.initialOrientation: Portrait

image.androidVersion.api: 28

tag.id: google_apis

hw.mainKeys: yes

hw.camera.front: None

avd.ini.displayname: Nexus One API 28

hw.gpu.mode: auto

hw.ramSize: 512

PlayStore.enabled: false

fastboot.forceColdBoot: no

hw.cpu.ncore: 4

hw.keyboard: yes

hw.sensors.proximity: yes

hw.dPad: no

hw.lcd.height: 800

vm.heapSize: 48

skin.dynamic: yes

hw.device.manufacturer: Google

hw.gps: yes

hw.audioInput: yes

image.sysdir.1: system-images/android-28/google_apis/x86/

showDeviceFrame: yes

hw.camera.back: virtualscene

AvdId: Nexus_One_API_28

hw.lcd.density: 240

hw.arc: false

hw.device.hash2: MD5:ef39e456bf2cab397201c2ac251f35fc

fastboot.forceChosenSnapshotBoot: no

fastboot.forceFastBoot: yes

hw.trackBall: yes

hw.battery: yes

hw.sdCard: yes

tag.display: Google APIs

runtime.network.latency: none

disk.dataPartition.size: 800M

hw.sensors.orientation: no

avd.ini.encoding: UTF-8

hw.gpu.enabled: yes

Я использовал эту команду для запуска теста на обезьяну:

      adb shell monkey -p my.app.package -s 12345 --throttle 1000 -v --pct-syskeys 0 9999

my.app.package — это мое приложение.

Вот код, который я использую для настройки DownloadableFont.

AndroidManifest.xml

       <meta-data
            android:name="preloaded_fonts"
            android:resource="@array/preloaded_fonts" />

preloaded_fonts.xml

      <?xml version="1.0" encoding="utf-8"?>
<resources>
    <array name="preloaded_fonts" translatable="false">
        <item>@font/droid_sans_mono</item>
        <item>@font/roboto_bold</item>
        <item>@font/roboto_medium</item>
        <item>@font/roboto_mono_medium</item>
        <item>@font/roboto_regular</item>
        <item>@font/roboto_thin</item>
    </array>
</resources>

один из пользовательских шрифтов (я могу добавить больше, если вы думаете, что это поможет вам помочь мне), другой выглядит очень похоже.

roboto_bold.xml

      <?xml version="1.0" encoding="utf-8"?>
<font-family xmlns:app="http://schemas.android.com/apk/res-auto"
        app:fontProviderAuthority="com.google.android.gms.fonts"
        app:fontProviderPackage="com.google.android.gms"
        app:fontProviderQuery="name=Roboto&amp;weight=700"
        app:fontProviderCerts="@array/com_google_android_gms_fonts_certs">
</font-family>

и использовать их так

тип.xml

      <style name="TextAppearance.MyApp.Headline1" parent="TextAppearance.MaterialComponents.Headline1">
        <item name="fontFamily">@font/roboto_bold</item>
        <item name="android:textStyle">bold</item>
    </style>

в любом текстовом представлении, кнопке или EditText

      ...
android:textAppearance="?attr/textAppearanceHeadline1"

Я добавил эти шрифты в свое приложение с помощью Android Studio.

0 ответов

Другие вопросы по тегам