Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Проблема с жизненным циклом MvpDelegate #272

Open
ermac95 opened this issue Mar 14, 2022 · 4 comments
Open

Проблема с жизненным циклом MvpDelegate #272

ermac95 opened this issue Mar 14, 2022 · 4 comments

Comments

@ermac95
Copy link

ermac95 commented Mar 14, 2022

Добрый день. На большом количестве устройств - от 9 до 12 версии андроид происходит вылет со следующей ошибкой

Fatal Exception: java.util.ConcurrentModificationException
at java.util.ArrayList$Itr.next(ArrayList.java:860)
at moxy.MvpDelegate.onAttach(MvpDelegate.java:166)
at moxy.MvpAppCompatFragment.onStart(MvpAppCompatFragment.java:38)
at androidx.fragment.app.Fragment.performStart(Fragment.java:2731)
at androidx.fragment.app.FragmentStateManager.start(FragmentStateManager.java:365)
at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1206)
at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1368)
at androidx.fragment.app.FragmentManager.moveFragmentToExpectedState(FragmentManager.java:1446)
at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1509)
at androidx.fragment.app.FragmentManager.dispatchStateChange(FragmentManager.java:2637)
at androidx.fragment.app.FragmentManager.dispatchStart(FragmentManager.java:2595)
at androidx.fragment.app.Fragment.performStart(Fragment.java:2740)
at androidx.fragment.app.FragmentStateManager.start(FragmentStateManager.java:365)
at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1206)
at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1368)
at androidx.fragment.app.FragmentManager.moveFragmentToExpectedState(FragmentManager.java:1446)
at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1509)
at androidx.fragment.app.FragmentManager.dispatchStateChange(FragmentManager.java:2637)
at androidx.fragment.app.FragmentManager.dispatchStart(FragmentManager.java:2595)
at androidx.fragment.app.FragmentController.dispatchStart(FragmentController.java:258)
at androidx.fragment.app.FragmentActivity.onStart(FragmentActivity.java:550)
at androidx.appcompat.app.AppCompatActivity.onStart(AppCompatActivity.java:210)
at moxy.MvpAppCompatActivity.onStart(MvpAppCompatActivity.java:32)
at modulbank.ru.commonapp.ui.main.MainActivity.onStart(MainActivity.kt:274)
at android.app.Instrumentation.callActivityOnStart(Instrumentation.java:1456)
at android.app.Activity.performStart(Activity.java:8076)
at android.app.ActivityThread.handleStartActivity(ActivityThread.java:3665)
at android.app.servertransaction.TransactionExecutor.performLifecycleSequence(TransactionExecutor.java:221)
at android.app.servertransaction.TransactionExecutor.cycleToPath(TransactionExecutor.java:201)
at android.app.servertransaction.TransactionExecutor.executeLifecycleState(TransactionExecutor.java:173)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:97)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2215)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loopOnce(Looper.java:346)
at android.os.Looper.loop(Looper.java:475)
at android.app.ActivityThread.main(ActivityThread.java:7889)
at java.lang.reflect.Method.invoke(Method.java)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1009)

   Экран приложения, где происходит вылет не определен, крашлитика firebase выдает ошибку в вышеприведенном виде. Я так понимаю происходит рассинхронизация методов, в ходе чего происходит одновременная запись и чтение из листа, в связи с чем случается падение. 
@senneco
Copy link
Collaborator

senneco commented Mar 14, 2022

Привет! Скорей всего причина в следующем:

  1. Во вью стейт летит какая-то команда
  2. Эта команда сохраняется в очереди команд
  3. Эта команда как-то отрабатывает (на этом этапе не важно как)
  4. Затем происходит пересоздание Activity (или что вы используете)
  5. Мокси начинает итерацию команд, последовательно выполняя их
  6. Видимо, в момент вызова какой-то команды на View улетает событие в презентер, чем триггерится новая команда для View
  7. Новая команда добавляется в очередь команд View State
  8. Восстановление стейта продолжается, итератор пытается взять следующую команду, но обнаруживает, что список был изменен
  9. Происходит падение.

Надеюсь, понятно объяснил. Если нет, то спрашивай, что именно не понятно =)

В самой мокси нет никакой многопоточности, и всё вообще работает обычно на одном потоке - на main потоке. Так что проблема именно с модификацией списка команд в процесс итерирования по этому же самому списку.

@ermac95
Copy link
Author

ermac95 commented Mar 14, 2022

Все понятно, хорошая мысль, спасибо за наводку. А есть какой нибудь способ отследить, где именно происходит подобная ситуация? чтобы понимать где искать, приложение коммерческое и масштабное, просто так перекапывать все команды всех вью не вариант конечно )

@senneco
Copy link
Collaborator

senneco commented Mar 14, 2022

Тут обычно сложность в том, что проблема получается глубинная. Потому что выходит так, что View управляет доменом, а должно быть наоборот =(

Чаще всего это конечно какие-нибудь переключения свитчеров или изменение edit text, от которых отрабатывает какой-то listener, который пушит что-то в presenter, а presenter сразу начинает что-то делать. Например, показывать лоадинг.

Тут нет серебряной пули. Поможет только ручной поиск проблемы.

Как вариант - можно попробовать каким-нибудь regexp поменять код так, что перед каждым вызововм какого-нибудь метода viewState, делать проверку:

if (isInRestoreState()) {
    throw RuntimeException("Wrong moxy usages")
}

А затем запустить приложение, заполнить как-нибудь view state и попересоздавать активити. И можно будет понять, кто ломает flow. Но это костыль.

Как мысль, можно это добавить в кодогенерацию, чтобы в будущем было понятно, какой метод ломает код. Потому что ConcurrentModificationException очень уж не информативен. Но это нужно сперва обмозговать.

@ermac95
Copy link
Author

ermac95 commented Mar 15, 2022

Окей, спасибо большое за помощь, буду разбираться )

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants