capacitor-community / photoviewer

⚡ Capacitor plugin to view table images with fullscreen and sharing capabilities.
MIT License
54 stars 27 forks source link

Google Play crash console: java.util.ConcurrentModificationException #15

Closed ivanov84 closed 2 years ago

ivanov84 commented 2 years ago

Describe the bug I have only log

To Reproduce Bug in Google Developer Console

Expected behavior No bug

Smartphone (please complete the following information):

Error java.util.ConcurrentModificationException: at java.util.ArrayList$Itr.next (ArrayList.java:860) at com.getcapacitor.community.media.photoviewer.Notifications.NotificationCenter.postNotification (NotificationCenter.java:55) at com.getcapacitor.community.media.photoviewer.fragments.ImageFragment.postNotification (ImageFragment.kt:103) at com.getcapacitor.community.media.photoviewer.fragments.ImageFragment.backPressed (ImageFragment.kt:96) at com.getcapacitor.community.media.photoviewer.fragments.ImageFragment.access$backPressed (ImageFragment.kt:26) at com.getcapacitor.community.media.photoviewer.fragments.ImageFragment$onCreateView$1$1.onKey (ImageFragment.kt:82) at android.view.View.dispatchKeyEvent (View.java:14204) at android.view.ViewGroup.dispatchKeyEvent (ViewGroup.java:1944) at android.view.ViewGroup.dispatchKeyEvent (ViewGroup.java:1949) at android.view.ViewGroup.dispatchKeyEvent (ViewGroup.java:1949) at android.view.ViewGroup.dispatchKeyEvent (ViewGroup.java:1949) at android.view.ViewGroup.dispatchKeyEvent (ViewGroup.java:1949) at android.view.ViewGroup.dispatchKeyEvent (ViewGroup.java:1949) at android.view.ViewGroup.dispatchKeyEvent (ViewGroup.java:1949) at android.view.ViewGroup.dispatchKeyEvent (ViewGroup.java:1949) at com.android.internal.policy.DecorView.superDispatchKeyEvent (DecorView.java:758) at com.android.internal.policy.PhoneWindow.superDispatchKeyEvent (PhoneWindow.java:1942) at android.app.Activity.dispatchKeyEvent (Activity.java:3998) at androidx.core.app.ComponentActivity.superDispatchKeyEvent (ComponentActivity.java:122) at androidx.core.view.KeyEventDispatcher.dispatchKeyEvent (KeyEventDispatcher.java:84) at androidx.core.app.ComponentActivity.dispatchKeyEvent (ComponentActivity.java:140) at androidx.appcompat.app.AppCompatActivity.dispatchKeyEvent (AppCompatActivity.java:599) at androidx.appcompat.view.WindowCallbackWrapper.dispatchKeyEvent (WindowCallbackWrapper.java:59) at androidx.appcompat.app.AppCompatDelegateImpl$AppCompatWindowCallback.dispatchKeyEvent (AppCompatDelegateImpl.java:3068) at com.android.internal.policy.DecorView.dispatchKeyEvent (DecorView.java:624) at android.view.ViewRootImpl$ViewPostImeInputStage.processKeyEvent (ViewRootImpl.java:6489) at android.view.ViewRootImpl$ViewPostImeInputStage.onProcess (ViewRootImpl.java:6353) at android.view.ViewRootImpl$InputStage.deliver (ViewRootImpl.java:5793) at android.view.ViewRootImpl$InputStage.onDeliverToNext (ViewRootImpl.java:5846) at android.view.ViewRootImpl$InputStage.forward (ViewRootImpl.java:5812) at android.view.ViewRootImpl$AsyncInputStage.forward (ViewRootImpl.java:5968) at android.view.ViewRootImpl$InputStage.apply (ViewRootImpl.java:5820) at android.view.ViewRootImpl$AsyncInputStage.apply (ViewRootImpl.java:6025) at android.view.ViewRootImpl$InputStage.deliver (ViewRootImpl.java:5793) at android.view.ViewRootImpl$InputStage.onDeliverToNext (ViewRootImpl.java:5846) at android.view.ViewRootImpl$InputStage.forward (ViewRootImpl.java:5812) at android.view.ViewRootImpl$InputStage.apply (ViewRootImpl.java:5820) at android.view.ViewRootImpl$InputStage.deliver (ViewRootImpl.java:5793) at android.view.ViewRootImpl$InputStage.onDeliverToNext (ViewRootImpl.java:5846) at android.view.ViewRootImpl$InputStage.forward (ViewRootImpl.java:5812) at android.view.ViewRootImpl$AsyncInputStage.forward (ViewRootImpl.java:6001) at android.view.ViewRootImpl$ImeInputStage.onFinishedInputEvent (ViewRootImpl.java:6170) at android.view.inputmethod.InputMethodManager$PendingEvent.run (InputMethodManager.java:3826) at android.view.inputmethod.InputMethodManager.invokeFinishedInputEventCallback (InputMethodManager.java:3308) at android.view.inputmethod.InputMethodManager.finishedInputEvent (InputMethodManager.java:3299) at android.view.inputmethod.InputMethodManager$ImeInputEventSender.onInputEventFinished (InputMethodManager.java:3803) at android.view.InputEventSender.dispatchInputEventFinished (InputEventSender.java:143) at android.os.MessageQueue.nativePollOnce (Native Method) at android.os.MessageQueue.next (MessageQueue.java:336) at android.os.Looper.loop (Looper.java:197) at android.app.ActivityThread.main (ActivityThread.java:8161) at java.lang.reflect.Method.invoke (Native Method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run (RuntimeInit.java:496) at com.android.internal.os.ZygoteInit.main (ZygoteInit.java:1100)

jepiqueau commented 2 years ago

@ivanov84 Can you tell me a bit more seems you were in a one image mode and you press the back press button Can you show the call of the photoviewer and the list of images url

ivanov84 commented 2 years ago

@jepiqueau yes, my javascript logic opens only 1 image per opening. This code:

const capImage: Image = {url: url, title: '_'};
const viewerOptions: ViewerOptions = {share: true, title: false};
const capOptions: capShowOptions = {images: [capImage], options: viewerOptions };
PhotoViewer.show(capOptions);

Example of image url: https://olympapp.com/content/user/caps/799aad95-997e-40e5-8113-a227a3d7bafd.jpg

jepiqueau commented 2 years ago

@ivanov84 Can you share your package.json

ivanov84 commented 2 years ago

@jepiqueau yes. This:

{
  "name": "capacitor-app",
  "version": "1.0.0",
  "description": "An Amazing Capacitor App",
  "main": "index.js",
  "keywords": [
    "capacitor",
    "mobile"
  ],
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "dependencies": {
    "@awesome-cordova-plugins/core": "^5.37.3",
    "@awesome-cordova-plugins/social-sharing": "^5.37.3",
    "@capacitor-community/admob": "^3.2.0",
    "@capacitor-community/firebase-analytics": "^1.0.1",
    "@capacitor-community/photoviewer": "^1.1.1",
    "@capacitor/android": "^3.2.5",
    "@capacitor/app": "^1.0.5",
    "@capacitor/browser": "^1.0.5",
    "@capacitor/camera": "^1.1.2",
    "@capacitor/clipboard": "^1.0.5",
    "@capacitor/core": "^3.2.5",
    "@capacitor/device": "^1.0.5",
    "@capacitor/keyboard": "^1.1.2",
    "@capacitor/local-notifications": "^1.0.9",
    "@capacitor/push-notifications": "^1.0.6",
    "@capacitor/splash-screen": "^1.1.5",
    "@capacitor/status-bar": "^1.0.6",
    "@capacitor/storage": "^1.2.2",
    "cordova-plugin-purchase": "^11.0.0",
    "cordova-plugin-x-socialsharing": "^6.0.3",
    "es6-promise-plugin": "^4.2.2"
  },
  "devDependencies": {
    "@capacitor/cli": "latest"
  },
  "author": "",
  "license": "ISC"
} 
jepiqueau commented 2 years ago

@ivanov84 Which framework are you using? Vue, React, Angular, Ionic/Vue, Ionict/React, Ionic/Angular

ivanov84 commented 2 years ago

@jepiqueau angular. This pack:

{
  "name": "Widget",
  "version": "1.0.0",
  "author": "Ionic Framework",
  "homepage": "https://ionicframework.com/",
  "scripts": {
    "ng": "ng",
    "start": "ng serve",
    "build": "ng build",
    "test": "ng test",
    "lint": "ng lint",
    "e2e": "ng e2e",
    "ionic:build:after": "gulp strip-debug"
  },
  "private": true,
  "dependencies": {
    "@angular/common": "~12.1.1",
    "@angular/core": "~12.1.1",
    "@angular/forms": "~12.1.1",
    "@angular/platform-browser": "~12.1.1",
    "@angular/platform-browser-dynamic": "~12.1.1",
    "@angular/router": "~12.1.1",
    "@awesome-cordova-plugins/core": "^5.37.3",
    "@awesome-cordova-plugins/social-sharing": "^5.37.3",
    "@capacitor-community/admob": "^3.2.0",
    "@capacitor-community/firebase-analytics": "^1.0.1",
    "@capacitor-community/photoviewer": "^1.1.1",
    "@capacitor/app": "^1.0.5",
    "@capacitor/browser": "^1.0.3",
    "@capacitor/camera": "^1.1.0",
    "@capacitor/clipboard": "^1.0.3",
    "@capacitor/device": "^1.0.3",
    "@capacitor/local-notifications": "^1.0.9",
    "@capacitor/push-notifications": "^1.0.4",
    "@capacitor/splash-screen": "^1.1.3",
    "@capacitor/status-bar": "^1.0.6",
    "@capacitor/storage": "^1.2.0",
    "@ionic-native/core": "^5.36.0",
    "@ionic-native/in-app-purchase-2": "^5.36.0",
    "@ionic/angular": "^5.8.4",
    "@microsoft/signalr": "^6.0.2",
    "@ngx-translate/core": "^13.0.0",
    "@ngx-translate/http-loader": "^6.0.0",
    "fabric": "^5.1.0",
    "ionic2-calendar": "^0.6.9",
    "moment": "^2.29.1",
    "rxjs": "~6.6.0",
    "simple-color-picker": "^1.0.5",
    "tslib": "^2.2.0",
    "zone.js": "~0.11.4"
  },
  "devDependencies": {
    "@angular-devkit/build-angular": "~12.1.1",
    "@angular-eslint/builder": "~12.0.0",
    "@angular-eslint/eslint-plugin": "~12.0.0",
    "@angular-eslint/eslint-plugin-template": "~12.0.0",
    "@angular-eslint/template-parser": "~12.0.0",
    "@angular/cli": "~12.1.1",
    "@angular/compiler": "~12.1.1",
    "@angular/compiler-cli": "~12.1.1",
    "@angular/language-service": "~12.0.1",
    "@ionic/angular-toolkit": "^4.0.0",
    "@types/fabric": "^4.5.7",
    "@types/jasmine": "~3.6.0",
    "@types/jasminewd2": "~2.0.3",
    "@types/node": "^12.11.1",
    "@typescript-eslint/eslint-plugin": "4.16.1",
    "@typescript-eslint/parser": "4.16.1",
    "eslint": "^7.6.0",
    "eslint-plugin-import": "2.22.1",
    "eslint-plugin-jsdoc": "30.7.6",
    "eslint-plugin-prefer-arrow": "1.2.2",
    "gulp": "^4.0.2",
    "gulp-strip-debug": "^4.0.0",
    "jasmine-core": "~3.8.0",
    "jasmine-spec-reporter": "~5.0.0",
    "karma": "~6.3.2",
    "karma-chrome-launcher": "~3.1.0",
    "karma-coverage": "~2.0.3",
    "karma-coverage-istanbul-reporter": "~3.0.2",
    "karma-jasmine": "~4.0.0",
    "karma-jasmine-html-reporter": "^1.5.0",
    "protractor": "~7.0.0",
    "ts-node": "~8.3.0",
    "typescript": "~4.2.4"
  },
  "description": "An Ionic project"
} 
jepiqueau commented 2 years ago

@ivanov84 Well i cannot reproduce it, can you share your app or a small app where you reproduce the issue

ivanov84 commented 2 years ago

@jepiqueau thank you, that you helps with this issue. This error appeared in Google Play Developer Console. I cannot reproduce it too. Sometimes I just delete some part of code. Can I just delete strings number 54-59 from file NotificationCenter.java? Because I don't know what that part of the code is doing.

My app: https://play.google.com/store/apps/details?id=com.olympapp.lovewidget.android

jepiqueau commented 2 years ago

@ivanov84 No you cannot. How do you use Google Play developer Console with an Android project ? I did all my tests in Android Studio and i did not get any error

const capOptions: capShowOptions = {images: [capImage], mode:'one', startFrom: 0; options: viewerOptions };
ivanov84 commented 2 years ago

@jepiqueau I use url: https://play.google.com/console/developers

Thank you, that you did all tests and got no errors.

May be I could put that logic in a try-catch. What do you think - can this help with the error?

jepiqueau commented 2 years ago

@ivanov84 yes a try ... catch and a const ret = await PhotoViewer.show(capOptions); and check for ret.result and/or ret.message

ivanov84 commented 2 years ago

@jepiqueau thank you. I meant if I add try-catch block in file NotificationCenter.java. I want to fix the error that appear in Google Play Console only because it decrease user count.

jepiqueau commented 2 years ago

@ivanov84 https://play.google.com/console/developers you need to pay for using it, so i am not going to pay for this. I do not have that issue in using Android Studio try do do this

    public synchronized void postNotification(String notificationName, Map<String, Object> _info) {
        ArrayList<MyRunnable> list = registeredObjects.get(notificationName);
        if (list != null) {
            for (MyRunnable r : list) {
              if (r != null) {
                r.setInfo(_info);
                r.run();
              }
            }
        }
    }

and tell me if it works

jepiqueau commented 2 years ago

@ivanov84 in the next release i will modify the code that way

    public synchronized void postNotification(String notificationName, Map<String, Object> _info) {
        ArrayList<MyRunnable> list = registeredObjects.get(notificationName);
        if (list != null) {
          for ( Iterator<MyRunnable> itr = list.iterator(); itr.hasNext();) {
            MyRunnable r = itr.next();
            if (r != null) {
              r.setInfo(_info);
              r.run();
            }
          }
        }
    }

As for me all of the proposed codes were working i am relying on you to test the latest one on https://play.google.com/console/developers

jepiqueau commented 2 years ago

@ivanov84 this should be fixed in version 1.1.2. Please confirm

jepiqueau commented 2 years ago

@ivanov84 look at 1.1.3, 1.1.2 must be discarded

ivanov84 commented 2 years ago

@jepiqueau Thank you very much!

mgravindran commented 7 months ago

@jepiqueau - We are using this plugin version 2.0.5 on a capacitor 4 project with angular 13. compileSdkVersion is 33. The crash due to this error still happens on many devices as reported by google play. Can you please help?

Exception java.util.ConcurrentModificationException: at java.util.ArrayList$Itr.checkForComodification (ArrayList.java:1029) at java.util.ArrayList$Itr.next (ArrayList.java:982) at com.getcapacitor.community.media.photoviewer.Notifications.NotificationCenter.postNotification (NotificationCenter.java:56) at com.getcapacitor.community.media.photoviewer.fragments.ImageFragment.postNotification (ImageFragment.kt:107) at com.getcapacitor.community.media.photoviewer.fragments.ImageFragment.backPressed (ImageFragment.kt:100) at com.getcapacitor.community.media.photoviewer.fragments.ImageFragment.access$backPressed (ImageFragment.kt:30) at com.getcapacitor.community.media.photoviewer.fragments.ImageFragment$onCreateView$1$1.onKey (ImageFragment.kt:86) at android.view.View.dispatchKeyEvent (View.java:14789) at android.view.ViewGroup.dispatchKeyEvent (ViewGroup.java:1966) at android.view.ViewGroup.dispatchKeyEvent (ViewGroup.java:1971) at android.view.ViewGroup.dispatchKeyEvent (ViewGroup.java:1971) at android.view.ViewGroup.dispatchKeyEvent (ViewGroup.java:1971) at android.view.ViewGroup.dispatchKeyEvent (ViewGroup.java:1971) at android.view.ViewGroup.dispatchKeyEvent (ViewGroup.java:1971) at android.view.ViewGroup.dispatchKeyEvent (ViewGroup.java:1971) at android.view.ViewGroup.dispatchKeyEvent (ViewGroup.java:1971) at com.android.internal.policy.DecorView.superDispatchKeyEvent (DecorView.java:557) at com.android.internal.policy.PhoneWindow.superDispatchKeyEvent (PhoneWindow.java:1885) at android.app.Activity.dispatchKeyEvent (Activity.java:4279) at androidx.core.app.ComponentActivity.superDispatchKeyEvent (ComponentActivity.java:126) at androidx.core.view.KeyEventDispatcher.dispatchKeyEvent (KeyEventDispatcher.java:86) at androidx.core.app.ComponentActivity.dispatchKeyEvent (ComponentActivity.java:144) at androidx.appcompat.app.AppCompatActivity.dispatchKeyEvent (AppCompatActivity.java:599) at androidx.appcompat.view.WindowCallbackWrapper.dispatchKeyEvent (WindowCallbackWrapper.java:59) at androidx.appcompat.app.AppCompatDelegateImpl$AppCompatWindowCallback.dispatchKeyEvent (AppCompatDelegateImpl.java:3089) at com.android.internal.policy.DecorView.dispatchKeyEvent (DecorView.java:433) at android.view.ViewRootImpl$ViewPostImeInputStage.processKeyEvent (ViewRootImpl.java:6583) at android.view.ViewRootImpl$ViewPostImeInputStage.onProcess (ViewRootImpl.java:6430) at android.view.ViewRootImpl$InputStage.deliver (ViewRootImpl.java:5888) at android.view.ViewRootImpl$InputStage.onDeliverToNext (ViewRootImpl.java:5945) at android.view.ViewRootImpl$InputStage.forward (ViewRootImpl.java:5911) at android.view.ViewRootImpl$AsyncInputStage.forward (ViewRootImpl.java:6076) at android.view.ViewRootImpl$InputStage.apply (ViewRootImpl.java:5919) at android.view.ViewRootImpl$AsyncInputStage.apply (ViewRootImpl.java:6133) at android.view.ViewRootImpl$InputStage.deliver (ViewRootImpl.java:5892) at android.view.ViewRootImpl$InputStage.onDeliverToNext (ViewRootImpl.java:5945) at android.view.ViewRootImpl$InputStage.forward (ViewRootImpl.java:5911) at android.view.ViewRootImpl$InputStage.apply (ViewRootImpl.java:5919) at android.view.ViewRootImpl$InputStage.deliver (ViewRootImpl.java:5892) at android.view.ViewRootImpl$InputStage.onDeliverToNext (ViewRootImpl.java:5945) at android.view.ViewRootImpl$InputStage.forward (ViewRootImpl.java:5911) at android.view.ViewRootImpl$AsyncInputStage.forward (ViewRootImpl.java:6109) at android.view.ViewRootImpl$ImeInputStage.onFinishedInputEvent (ViewRootImpl.java:6283) at android.view.inputmethod.InputMethodManager$PendingEvent.run (InputMethodManager.java:3158) at android.view.inputmethod.InputMethodManager.invokeFinishedInputEventCallback (InputMethodManager.java:2722) at android.view.inputmethod.InputMethodManager.finishedInputEvent (InputMethodManager.java:2713) at android.view.inputmethod.InputMethodManager$ImeInputEventSender.onInputEventFinished (InputMethodManager.java:3135) at android.view.InputEventSender.dispatchInputEventFinished (InputEventSender.java:154) at android.os.MessageQueue.nativePollOnce at android.os.MessageQueue.next (MessageQueue.java:337) at android.os.Looper.loopOnce (Looper.java:168) at android.os.Looper.loop (Looper.java:299) at android.app.ActivityThread.main (ActivityThread.java:8250) at java.lang.reflect.Method.invoke at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run (RuntimeInit.java:556) at com.android.internal.os.ZygoteInit.main (ZygoteInit.java:1045)

jepiqueau commented 7 months ago

@mgravindran update your project to Capacitor 5 and the latest release of @capacitor-community/photoviewer

mgravindran commented 7 months ago

update your project to Capacitor 5 and the latest release of @capacitor-community/photoviewer

@jepiqueau Is there any workaround to make it work with Capacitor 4?

jepiqueau commented 7 months ago

@mgravindran no Capacitor 6 will be release soon so i will encourage you to move your project to Capacitor 5. I cannot maintain so many releases