Skip to content

Commit 035d866

Browse files
authored
Merge pull request #23 from launchdarkly/2.0.2
2.0.2
2 parents e2b310e + 8f19248 commit 035d866

File tree

5 files changed

+24
-18
lines changed

5 files changed

+24
-18
lines changed

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,11 @@
33

44
All notable changes to the LaunchDarkly Android SDK will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org).
55

6+
## [2.0.2] - 2017-05-03
7+
### Changed
8+
- Improved thread safety in UserManager when removing change listeners.
9+
- Streamlined SDK initialization.
10+
611
## [2.0.1] - 2017-04-28
712
### Fixed
813
- The `Future<LDClient>` returned from `LDClient.init` now also waits for the feature flag rules to be retrieved.

launchdarkly-android-client/build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ apply plugin: 'com.getkeepsafe.dexcount'
77

88
allprojects {
99
group = 'com.launchdarkly'
10-
version = '2.0.1'
10+
version = '2.0.2'
1111
sourceCompatibility = 1.7
1212
targetCompatibility = 1.7
1313
}

launchdarkly-android-client/src/androidTest/java/com/launchdarkly/android/UserManagerTest.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,8 @@ private Future<Void> setUser(String userKey, JsonObject flags) {
115115
ListenableFuture<JsonObject> jsonObjectFuture = Futures.immediateFuture(flags);
116116
expect(fetcher.fetch(user)).andReturn(jsonObjectFuture);
117117
replayAll();
118-
Future<Void> future = userManager.setCurrentUser(user);
118+
userManager.setCurrentUser(user);
119+
Future<Void> future = userManager.updateCurrentUser();
119120
reset(fetcher);
120121
return future;
121122
}
@@ -128,8 +129,8 @@ private void setUserAndFailToFetchFlags(String userKey) throws InterruptedExcept
128129

129130
expect(fetcher.fetch(user)).andReturn(failedFuture);
130131
replayAll();
131-
132-
Future<Void> future = userManager.setCurrentUser(user);
132+
userManager.setCurrentUser(user);
133+
Future<Void> future = userManager.updateCurrentUser();
133134
try {
134135
future.get();
135136
} catch (ExecutionException e) {

launchdarkly-android-client/src/main/java/com/launchdarkly/android/LDClient.java

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818
import java.io.IOException;
1919
import java.util.Map;
2020
import java.util.UUID;
21-
import java.util.concurrent.Callable;
2221
import java.util.concurrent.ExecutionException;
2322
import java.util.concurrent.Future;
2423
import java.util.concurrent.TimeUnit;
@@ -70,7 +69,7 @@ public static synchronized Future<LDClient> init(Application application, LDConf
7069
return settableFuture;
7170
}
7271
instance = new LDClient(application, config);
73-
ListenableFuture<Void> userFuture = instance.userManager.setCurrentUser(user);
72+
instance.userManager.setCurrentUser(user);
7473

7574
if (instance.isOffline() || !isInternetConnected(application)) {
7675
settableFuture.set(instance);
@@ -82,9 +81,10 @@ public static synchronized Future<LDClient> init(Application application, LDConf
8281
ListenableFuture<Void> initFuture = instance.updateProcessor.start();
8382
instance.sendEvent(new IdentifyEvent(user));
8483

85-
return Futures.whenAllComplete(userFuture, initFuture).call(new Callable<LDClient>() {
84+
// Transform initFuture so its result is the instance:
85+
return Futures.transform(initFuture, new Function<Void, LDClient>() {
8686
@Override
87-
public LDClient call() throws Exception {
87+
public LDClient apply(Void input) {
8888
return instance;
8989
}
9090
});
@@ -134,7 +134,7 @@ protected LDClient(final Application application, final LDConfig config) {
134134
this.config = config;
135135
this.isOffline = config.isOffline();
136136

137-
SharedPreferences instanceIdSharedPrefs = application.getSharedPreferences("id", Context.MODE_PRIVATE);
137+
SharedPreferences instanceIdSharedPrefs = application.getSharedPreferences("LaunchDarkly-id", Context.MODE_PRIVATE);
138138

139139
if (!instanceIdSharedPrefs.contains(INSTANCE_ID_KEY)) {
140140
String uuid = UUID.randomUUID().toString();
@@ -215,7 +215,8 @@ public synchronized Future<Void> identify(LDUser user) {
215215
if (user.getKey() == null) {
216216
Log.w(TAG, "identify called with null user or null user key!");
217217
}
218-
Future<Void> doneFuture = userManager.setCurrentUser(user);
218+
userManager.setCurrentUser(user);
219+
Future<Void> doneFuture = userManager.updateCurrentUser();
219220
sendEvent(new IdentifyEvent(user));
220221
return doneFuture;
221222
}

launchdarkly-android-client/src/main/java/com/launchdarkly/android/UserManager.java

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
import com.google.common.base.Function;
1313
import com.google.common.collect.ArrayListMultimap;
1414
import com.google.common.collect.Multimap;
15+
import com.google.common.collect.Multimaps;
1516
import com.google.common.util.concurrent.FutureCallback;
1617
import com.google.common.util.concurrent.Futures;
1718
import com.google.common.util.concurrent.ListenableFuture;
@@ -26,7 +27,6 @@
2627
import java.util.LinkedList;
2728
import java.util.List;
2829
import java.util.Map;
29-
import java.util.concurrent.Future;
3030

3131
/**
3232
* Persists and retrieves feature flag values for different {@link LDUser}s.
@@ -51,13 +51,14 @@ class UserManager {
5151

5252
private final Application application;
5353
// Maintains references enabling (de)registration of listeners for realtime updates
54-
private final Multimap<String, Pair<FeatureFlagChangeListener, OnSharedPreferenceChangeListener>> listeners = ArrayListMultimap.create();
54+
private final Multimap<String, Pair<FeatureFlagChangeListener, OnSharedPreferenceChangeListener>> listeners =
55+
Multimaps.synchronizedMultimap(ArrayListMultimap.<String, Pair<FeatureFlagChangeListener,OnSharedPreferenceChangeListener>>create());
5556

5657
// The current user- we'll always fetch this user from the response we get from the api
5758
private SharedPreferences currentUserSharedPrefs;
5859
private LDUser currentUser;
5960

60-
static UserManager init(Application application, FeatureFlagFetcher fetcher) {
61+
static synchronized UserManager init(Application application, FeatureFlagFetcher fetcher) {
6162
if (instance != null) {
6263
return instance;
6364
}
@@ -91,12 +92,12 @@ SharedPreferences getCurrentUserSharedPrefs() {
9192
*
9293
* @param user
9394
*/
94-
ListenableFuture<Void> setCurrentUser(final LDUser user) {
95+
void setCurrentUser(final LDUser user) {
9596
String userBase64 = user.getAsUrlSafeBase64();
9697
Log.d(TAG, "Setting current user to: [" + userBase64 + "] [" + userBase64ToJson(userBase64) + "]");
9798
currentUser = user;
9899
currentUserSharedPrefs = loadSharedPrefsForUser(userBase64);
99-
ListenableFuture<Void> updateFuture = updateCurrentUser();
100+
100101
usersSharedPrefs.edit()
101102
.putLong(userBase64, System.currentTimeMillis())
102103
.apply();
@@ -111,8 +112,6 @@ ListenableFuture<Void> setCurrentUser(final LDUser user) {
111112
.remove(removed)
112113
.apply();
113114
}
114-
115-
return updateFuture;
116115
}
117116

118117
/**
@@ -130,7 +129,7 @@ private void deleteSharedPreferences(String userKey) {
130129
file.delete();
131130
}
132131

133-
synchronized ListenableFuture<Void> updateCurrentUser() {
132+
ListenableFuture<Void> updateCurrentUser() {
134133
ListenableFuture<JsonObject> fetchFuture = fetcher.fetch(currentUser);
135134

136135
Futures.addCallback(fetchFuture, new FutureCallback<JsonObject>() {

0 commit comments

Comments
 (0)