Leanplum/Leanplum-Android-SDK

com.leanplum.actions.internal.ActionDefinition.getName() - NullPointerException

michalkierasinski opened this issue · 6 comments

Fatal Exception: java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String com.leanplum.actions.internal.ActionDefinition.getName()' on a null object reference
       at com.leanplum.actions.internal.ActionManagerDefinitionKt.defineAction(ActionManagerDefinition.kt:87)
       at com.leanplum.messagetemplates.MessageTemplates.register(MessageTemplates.java:123)
       at com.leanplum.messagetemplates.MessageTemplates.registerTemplate(MessageTemplates.java:82)

Expected Behavior

The application is not crashing

Actual Behavior

Application is crashing

Steps to Reproduce the Problem

  1. Open the application with some custom action

Specifications

  • Version: 6.0.0
  • Platform: Android
  • Subsystem:

Probably connected with:

Fatal Exception: java.util.ConcurrentModificationException:
       at java.util.ArrayList$Itr.next(ArrayList.java:860)
       at com.leanplum.actions.internal.ActionManagerDefinitionKt.defineAction(ActionManagerDefinition.kt:130)
       at com.leanplum.messagetemplates.MessageTemplates.register(MessageTemplates.java:123)
       at com.leanplum.messagetemplates.MessageTemplates.registerTemplate(MessageTemplates.java:82)

@michalkierasinski
Can you share your custom action definition and which thread executes it?

I would suggest using the UI thread when registering the actions to avoid such issues. The action queue mechanism is triggered on the UI thread, which probably is the cause of the crash. The heavy network operations are executed in a background threads.

class OpenAction @Inject constructor() : MessageTemplate {

    override fun getName() = ACTION_NAME

    override fun createActionArgs(context: Context): ActionArgs = ActionArgs().with(URL, "")

    override fun present(actionContext: ActionContext): Boolean {
        val url: String = actionContext.stringNamed(URL)

        if (!deepLinkManager.isLinkSupported(url)) {
            Timber.e("Deep Link is not supported")
            return false
        }

        // TODO: Open deep link
        actionContext.actionDismissed()
        return true
    }

    override fun dismiss(context: ActionContext): Boolean = true

    private companion object {
        const val ACTION_NAME = "Action Name"

        const val URL = "URL"
    }
}

Actions are registered on a different thread than UI.

Thanks, I will rise a bug about that, meanwhile could you use the UI thread when registering them. The registration is a light operation, that doesn't involve any network requests, and wouldn't freeze the UI thread.

Ok, thanks. Please fix it or update the documentation.

@michalkierasinski
Fixed in #534 and will be included in next release.
Thank you for your feedback!