Skip to content

Commit d4f4870

Browse files
authored
Add async functionality to Action Queue (#543)
* Add async functionality to Action Queue * Offload all listener methods from Main thread.
1 parent b7c656e commit d4f4870

File tree

5 files changed

+83
-9
lines changed

5 files changed

+83
-9
lines changed

AndroidSDKCore/src/main/java/com/leanplum/actions/LeanplumActions.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,4 +117,7 @@ object LeanplumActions {
117117
*/
118118
@JvmStatic
119119
fun isQueueEnabled() = ActionManager.getInstance().isEnabled
120+
121+
@JvmStatic
122+
var useWorkerThreadForDecisionHandlers = false
120123
}

AndroidSDKCore/src/main/java/com/leanplum/actions/internal/ActionManagerExecution.kt

Lines changed: 38 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,9 @@
2222
package com.leanplum.actions.internal
2323

2424
import androidx.annotation.UiThread
25+
import com.leanplum.ActionContext
2526
import com.leanplum.Leanplum
27+
import com.leanplum.actions.LeanplumActions
2628
import com.leanplum.actions.MessageDisplayChoice
2729
import com.leanplum.callbacks.VariablesChangedCallback
2830
import com.leanplum.internal.*
@@ -104,7 +106,9 @@ private fun ActionManager.performActionsImpl() {
104106

105107
// do not continue if we have action running
106108
if (currentAction != null) {
107-
prioritizePushNotificationActions()
109+
if (!LeanplumActions.useWorkerThreadForDecisionHandlers) { // disable prioritization with worker thread
110+
prioritizePushNotificationActions()
111+
}
108112
return
109113
}
110114

@@ -122,6 +126,15 @@ private fun ActionManager.performActionsImpl() {
122126
return
123127
}
124128

129+
if (LeanplumActions.useWorkerThreadForDecisionHandlers) {
130+
OperationQueue.sharedInstance().addActionOperation { askUserAndPresentAction(currentContext) }
131+
} else {
132+
askUserAndPresentAction(currentContext)
133+
}
134+
}
135+
136+
private fun ActionManager.askUserAndPresentAction(currentContext: ActionContext) {
137+
125138
// decide if we are going to display the message
126139
// by calling delegate and let it decide what we are supposed to do
127140
val displayDecision = messageDisplayController?.shouldDisplayMessage(currentContext)
@@ -162,16 +175,34 @@ private fun ActionManager.performActionsImpl() {
162175

163176
// 3) set dismiss block
164177
currentContext.setActionDidDismiss {
165-
Log.d("[ActionManager]: actionDidDismiss: ${currentContext}.")
166-
messageDisplayListener?.onMessageDismissed(currentContext)
167-
currentAction = null // stop executing current action
168-
performActions()
178+
val dismissOperation = {
179+
Log.d("[ActionManager]: actionDidDismiss: ${currentContext}.")
180+
messageDisplayListener?.onMessageDismissed(currentContext)
181+
currentAction = null // stop executing current action
182+
performActions()
183+
}
184+
185+
if (LeanplumActions.useWorkerThreadForDecisionHandlers) {
186+
OperationQueue.sharedInstance().addActionOperation(dismissOperation)
187+
} else {
188+
dismissOperation.invoke()
189+
}
190+
169191
}
170192

171193
// 2) set the action block
172194
currentContext.setActionDidExecute { actionNamedContext ->
173-
Log.d("[ActionManager]: actionDidExecute: ${actionNamedContext}.")
174-
messageDisplayListener?.onActionExecuted(actionNamedContext.actionName(), actionNamedContext)
195+
val actionExecutedOperation = {
196+
Log.d("[ActionManager]: actionDidExecute: ${actionNamedContext}.")
197+
messageDisplayListener?.onActionExecuted(actionNamedContext.actionName(), actionNamedContext)
198+
Unit
199+
}
200+
201+
if (LeanplumActions.useWorkerThreadForDecisionHandlers) {
202+
OperationQueue.sharedInstance().addActionOperation(actionExecutedOperation)
203+
} else {
204+
actionExecutedOperation.invoke()
205+
}
175206
}
176207

177208
// 1) ask to present, return if it's not

AndroidSDKCore/src/main/java/com/leanplum/actions/internal/ActionManagerTriggering.kt

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,21 +22,43 @@
2222
package com.leanplum.actions.internal
2323

2424
import com.leanplum.ActionContext
25+
import com.leanplum.actions.LeanplumActions
2526
import com.leanplum.internal.ActionManager
2627
import com.leanplum.internal.Log
28+
import com.leanplum.internal.OperationQueue
2729

2830
fun ActionManager.trigger(
2931
context: ActionContext,
3032
priority: Priority = Priority.DEFAULT) {
3133

32-
trigger(listOf(context), priority)
34+
if (LeanplumActions.useWorkerThreadForDecisionHandlers) {
35+
OperationQueue.sharedInstance().addActionOperation {
36+
triggerImpl(listOf(context), priority)
37+
}
38+
} else {
39+
triggerImpl(listOf(context), priority)
40+
}
3341
}
3442

3543
fun ActionManager.trigger(
3644
contexts: List<ActionContext>,
3745
priority: Priority = Priority.DEFAULT,
3846
trigger: ActionsTrigger? = null) {
3947

48+
if (LeanplumActions.useWorkerThreadForDecisionHandlers) {
49+
OperationQueue.sharedInstance().addActionOperation {
50+
triggerImpl(contexts, priority, trigger)
51+
}
52+
} else {
53+
triggerImpl(contexts, priority, trigger)
54+
}
55+
}
56+
57+
private fun ActionManager.triggerImpl(
58+
contexts: List<ActionContext>,
59+
priority: Priority = Priority.DEFAULT,
60+
trigger: ActionsTrigger? = null) {
61+
4062
if (contexts.isEmpty()) return
4163

4264
// By default, add only one message to queue if `prioritizeMessages` is not implemented

AndroidSDKCore/src/main/java/com/leanplum/internal/ActionManager.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ public class ActionManager {
6767
private final ActionQueue queue = new ActionQueue();
6868
private final ActionQueue delayedQueue = new ActionQueue();
6969
private final Definitions definitions = new Definitions();
70-
private Action currentAction;
70+
private volatile Action currentAction;
7171
private boolean dismissOnPushOpened = true;
7272
private boolean continueOnActivityResumed = true;
7373

AndroidSDKCore/src/main/java/com/leanplum/internal/OperationQueue.java

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ public class OperationQueue {
3434
private static OperationQueue instance;
3535

3636
private static final String OPERATION_QUEUE_NAME = "com.leanplum.operation_queue";
37+
private static final String ACTION_QUEUE_NAME = "com.leanplum.action_queue";
3738
private static final int OPERATION_QUEUE_PRIORITY = Process.THREAD_PRIORITY_DEFAULT;
3839

3940
private HandlerThread handlerThread;
@@ -42,6 +43,9 @@ public class OperationQueue {
4243

4344
private Executor executor = Executors.newCachedThreadPool();
4445

46+
private Handler actionsHandler;
47+
private HandlerThread actionsThread;
48+
4549
public static OperationQueue sharedInstance() {
4650
if (instance == null) {
4751
instance = new OperationQueue();
@@ -161,4 +165,18 @@ public void removeAllOperations() {
161165
handler.removeCallbacksAndMessages(null);
162166
}
163167
}
168+
169+
/**
170+
* Add operation related to Action Queue. Will execute operations sequentially.
171+
*/
172+
public void addActionOperation(Runnable operation) {
173+
if (actionsHandler == null) {
174+
actionsThread = new HandlerThread(ACTION_QUEUE_NAME, OPERATION_QUEUE_PRIORITY);
175+
actionsThread.start();
176+
actionsHandler = new Handler(actionsThread.getLooper());
177+
}
178+
if (operation != null) {
179+
actionsHandler.post(operation);
180+
}
181+
}
164182
}

0 commit comments

Comments
 (0)