Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
## XX.XX.XX
* Improved Content refresh mechanics.

## 25.4.9
* Added a new config option `disableViewRestartForManualRecording()` to disable auto close/restart behavior of manual views on app background/foreground actions.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
Expand Down Expand Up @@ -1174,7 +1175,6 @@ private int[] setupTest_allFeatures(JSONObject serverConfig) {
countlyConfig.metricProviderOverride = new MockedMetricProvider();
Countly.sharedInstance().init(countlyConfig);
Countly.sharedInstance().moduleContent.CONTENT_START_DELAY_MS = 0; // make it zero to catch content immediate request
Countly.sharedInstance().moduleContent.REFRESH_CONTENT_ZONE_DELAY_MS = 0; // make it zero to catch content immediate request
return counts;
}

Expand Down Expand Up @@ -1224,6 +1224,11 @@ private void immediateFlow_allFeatures() throws InterruptedException {
Thread.sleep(1000);

Countly.sharedInstance().contents().refreshContentZone(); // will add one more content immediate request
try {
// wait for refresh to complete
Countly.sharedInstance().moduleContent.refreshContentZoneInternalFuture.get(5, TimeUnit.SECONDS);
} catch (Exception ignored) {
}
}

private void feedbackFlow_allFeatures() {
Expand Down
32 changes: 30 additions & 2 deletions sdk/src/main/java/ly/count/android/sdk/ConnectionQueue.java
Original file line number Diff line number Diff line change
Expand Up @@ -887,6 +887,15 @@ void ensureExecutor() {
* Should only be called if SDK is initialized
*/
public void tick() {
tick(false);
}

/**
* This function blocks caller until RQ flushes, so be cautious when using it.
*
* @param forceFlushRQ if true, will block until RQ is fully flushed
*/
public void tick(boolean forceFlushRQ) {
//todo enable later
//assert storageProvider != null;
if (backoff_.get()) {
Expand All @@ -904,10 +913,29 @@ public void tick() {
return;
}

if (forceFlushRQ && connectionProcessorFuture_ != null && !connectionProcessorFuture_.isDone()) {
L.d("[ConnectionQueue] tick, forceFlushRQ ongoing future closing it");
try {
connectionProcessorFuture_.get();
cpDoneIfOngoing = true;
} catch (Exception e) {
L.e("[ConnectionQueue] tick, forceFlushRQ ongoing future encountered an error: " + e.getMessage());
}
}

if (!rqEmpty && (connectionProcessorFuture_ == null || cpDoneIfOngoing)) {
L.d("[ConnectionQueue] tick, Starting ConnectionProcessor");
ensureExecutor();
connectionProcessorFuture_ = executor_.submit(createConnectionProcessor());
Runnable cp = createConnectionProcessor();
if (forceFlushRQ) {
try {
cp.run();
} catch (Exception e) {
L.e("[ConnectionQueue] tick, forceFlushRQ encountered an error: " + e.getMessage());
}
} else {
ensureExecutor();
connectionProcessorFuture_ = executor_.submit(cp);
}
}
}

Expand Down
20 changes: 13 additions & 7 deletions sdk/src/main/java/ly/count/android/sdk/ModuleContent.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,16 @@
import java.util.Locale;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import org.jetbrains.annotations.NotNull;
import org.json.JSONObject;

public class ModuleContent extends ModuleBase {
private final ImmediateRequestGenerator iRGenerator;
private final ExecutorService refreshExecutor; // to not block main thread during refresh
Future<?> refreshContentZoneInternalFuture; // for test access
Content contentInterface;
CountlyTimer countlyTimer;
private boolean shouldFetchContents = false;
Expand All @@ -25,12 +30,12 @@ public class ModuleContent extends ModuleBase {
private final ContentCallback globalContentCallback;
private int waitForDelay = 0;
int CONTENT_START_DELAY_MS = 4000; // 4 seconds
int REFRESH_CONTENT_ZONE_DELAY_MS = 2500; // 2.5 seconds

ModuleContent(@NonNull Countly cly, @NonNull CountlyConfig config) {
super(cly, config);
L.v("[ModuleContent] Initialising, zoneTimerInterval: [" + config.content.zoneTimerInterval + "], globalContentCallback: [" + config.content.globalContentCallback + "]");
iRGenerator = config.immediateRequestGenerator;
refreshExecutor = Executors.newSingleThreadExecutor();

contentInterface = new Content();
countlyTimer = new CountlyTimer();
Expand Down Expand Up @@ -295,6 +300,7 @@ void halt() {
contentInterface = null;
countlyTimer.stopTimer(L);
countlyTimer = null;
refreshExecutor.shutdown();
}

@Override
Expand Down Expand Up @@ -329,13 +335,13 @@ private void refreshContentZoneInternal() {
return;
}

if (!shouldFetchContents) {
exitContentZoneInternal();
}
exitContentZoneInternal();

_cly.moduleRequestQueue.attemptToSendStoredRequestsInternal();

enterContentZoneInternal(null, REFRESH_CONTENT_ZONE_DELAY_MS);
refreshContentZoneInternalFuture = refreshExecutor.submit(() -> {
_cly.moduleRequestQueue.attemptToSendStoredRequestsInternal(true);
L.d("[ModuleContent] refreshContentZone, RQ flush done, re-entering content zone");
enterContentZoneInternal(null, 0);
});
}

public class Content {
Expand Down
15 changes: 13 additions & 2 deletions sdk/src/main/java/ly/count/android/sdk/ModuleRequestQueue.java
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,18 @@ public void flushQueuesInternal() {
* attempt to process stored requests on demand
*/
public void attemptToSendStoredRequestsInternal() {
L.i("[ModuleRequestQueue] Calling attemptToSendStoredRequests");
attemptToSendStoredRequestsInternal(false);
}

/**
* This method sends all RQ synchronously if forceFlushRQ is true
*
* @param forceFlushRQ whether to force flush the request queue
* Be cautious when using this flag as it may cause ANRs if used on main thread
* Wrap calls in a separate thread to unsure non-Blocking UI or main thread
*/
protected void attemptToSendStoredRequestsInternal(boolean forceFlushRQ) {
L.i("[ModuleRequestQueue] attemptToSendStoredRequestsInternal, forceFlushRQ: [" + forceFlushRQ + "]");

//combine all available events into a request
sendEventsIfNeeded(true);
Expand All @@ -206,7 +217,7 @@ public void attemptToSendStoredRequestsInternal() {
_cly.moduleUserProfile.saveInternal();

//trigger the processing of the request queue
requestQueueProvider.tick();
requestQueueProvider.tick(forceFlushRQ);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ interface RequestQueueProvider {

void tick();

void tick(boolean forceFlushRQ);

ConnectionProcessor createConnectionProcessor();

String prepareRemoteConfigRequestLegacy(@Nullable String keysInclude, @Nullable String keysExclude, @NonNull String preparedMetrics);
Expand Down
Loading