Skip to content

Commit f2bce07

Browse files
committed
- Added support for multiple StoreX instances with different storage supports
- Added support for custom Coroutine Scopes - Documentation updated
1 parent 87b39d3 commit f2bce07

File tree

12 files changed

+229
-19
lines changed

12 files changed

+229
-19
lines changed

README.md

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,22 +40,49 @@ dependencies {
4040

4141
| Latest Releases
4242
| ------------- |
43-
| 1.0.0 |
43+
| 1.2.0 |
4444

4545
---
4646

47+
### What's new in this version?
48+
- Multiple instance of StoreX with differnet configuration & storage
49+
- Added support for custom Coroutine Scopes
50+
4751
## Initialize
4852
````
49-
StoreXCore.init(application: Application, prefName: String)
53+
// Create multiple identifers
54+
object StoreXIdentifiers {
55+
val mainConfig : StoreXConfig = StoreXConfig("Something_1", "main_pref")
56+
val anotherConfig : StoreXConfig = StoreXConfig("Something_2", "secondary_pref")
57+
}
58+
````
59+
60+
````
61+
// Deprecated. Will be removed in the future version
62+
StoreXCore.init(this, getString(R.string.app_name))
63+
64+
// New method
65+
StoreXCore.init(this, mutableListOf(
66+
StoreXIdentifiers.mainConfig,
67+
StoreXIdentifiers.mainConfig,
68+
))
5069
````
5170

5271
## How To Access
5372
````
73+
// Deprecated. Will be removed in the future version
5474
StoreXCore.instance()
75+
76+
// New method
77+
StoreXCore.instance(configs: StoreXConfig)
5578
````
5679
or else, use the extension function
5780
````
81+
// Deprecated. Will be removed in the future version
5882
storeXInstance()
83+
84+
// New method
85+
fun storeXInstance(config: StoreXConfig)
5986
````
6087
which return an instance of `StoreX` [Note: You must initalize `StoreX` properly before accessing or else it will throw `NotInitializedException`]
6188

@@ -104,7 +131,7 @@ First setup an callback for the data changes
104131
}
105132
}
106133
````
107-
Create a new sunscriber.
134+
Create a new subscriber.
108135

109136
Create a new subscriber by providing the `Key`, `Observer ID (Must be unique)` and the `Callback`
110137

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
package com.rommansabbir.storex
22

3+
@Deprecated("Use new method StoreXCore.instance(config: StoreXConfig) to get specific instance", ReplaceWith("StoreXCore.instance(config: StoreXConfig)"))
34
fun storeXInstance(): StoreX = StoreXCore.instance()
45

6+
fun storeXInstance(config: StoreXConfig): StoreX = StoreXCore.instance(config)
7+
58
internal fun Subscriber.getKey(): String {
69
return "${this.key}_${this.subscriberID}"
710
}

StoreX/src/main/java/com/rommansabbir/storex/StoreX.kt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,26 @@ package com.rommansabbir.storex
22

33
import com.rommansabbir.storex.callbacks.GetCallback
44
import com.rommansabbir.storex.callbacks.SaveCallback
5+
import kotlinx.coroutines.CoroutineScope
56

67
interface StoreX {
78
@Throws(RuntimeException::class)
89
fun put(key: String, value: StoreAbleObject): Boolean
910

11+
@Throws(RuntimeException::class)
12+
fun put(scope : CoroutineScope, key: String, value: StoreAbleObject)
13+
1014
fun <T : StoreAbleObject> put(key: String, value: StoreAbleObject, callback: SaveCallback<T>)
1115

16+
fun <T : StoreAbleObject> put(scope : CoroutineScope,key: String, value: StoreAbleObject, callback: SaveCallback<T>)
17+
1218
@Throws(RuntimeException::class)
1319
fun <T : StoreAbleObject> get(key: String, objectType: Class<T>): T
1420

1521
fun <T : StoreAbleObject> get(key: String, objectType: Class<T>, callback: GetCallback<T>)
1622

23+
fun <T : StoreAbleObject> get(scope : CoroutineScope,key: String, objectType: Class<T>, callback: GetCallback<T>)
24+
1725
@Throws(RuntimeException::class)
1826
fun addSubscriber(subscriber: Subscriber)
1927

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package com.rommansabbir.storex
2+
3+
/**
4+
* Represent the configuration for [StoreX].
5+
* uId must be an unique identifier.
6+
*
7+
* @param uId, Unique identifier for the config
8+
* @param prefName, SharedPref name for the config
9+
*/
10+
data class StoreXConfig(val uId : String, val prefName : String)

StoreX/src/main/java/com/rommansabbir/storex/StoreXCore.kt

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,26 @@ package com.rommansabbir.storex
22

33
import android.app.Application
44
import com.google.gson.Gson
5+
import com.rommansabbir.storex.execptions.DuplicateStoreXConfigException
56
import com.rommansabbir.storex.execptions.InvalidEncryptionKeyException
7+
import com.rommansabbir.storex.execptions.NoConfigFoundException
68
import com.rommansabbir.storex.execptions.NotInitializedException
79

810
object StoreXCore {
911
private var isInitialized: Boolean = false
1012
private var instance: StoreXInstance? = null
1113

14+
private var instanceStates: HashMap<String, StoreXState> = HashMap()
15+
16+
/**
17+
* When you go crazy and want to delete all the cache, call this method.
18+
*/
19+
fun clearAllStates() {
20+
instanceStates.clear()
21+
}
22+
23+
@Deprecated("Use new method StoreXCore.instance(config: StoreXConfig) to get specific instance",
24+
ReplaceWith("StoreXCore.instance(config: StoreXConfig)"))
1225
@Throws(RuntimeException::class)
1326
fun instance(): StoreX {
1427
if (isInitialized) {
@@ -18,6 +31,33 @@ object StoreXCore {
1831
}
1932
}
2033

34+
@Throws(RuntimeException::class)
35+
fun instance(configs: StoreXConfig): StoreX {
36+
if (isInitialized) {
37+
instanceStates[configs.uId]?.let {
38+
return it.storeXInstance
39+
} ?: run {
40+
throw NoConfigFoundException()
41+
}
42+
} else {
43+
throw NotInitializedException()
44+
}
45+
}
46+
47+
@Throws(RuntimeException::class)
48+
fun init(application: Application, configs: MutableList<StoreXConfig>) {
49+
val gson = Gson()
50+
configs.forEach {
51+
if (instanceStates[it.uId] != null) {
52+
throw DuplicateStoreXConfigException()
53+
}
54+
instanceStates[it.uId] = StoreXState(StoreXInstance(application, it.prefName, gson), it)
55+
}
56+
this.isInitialized = true
57+
}
58+
59+
@Deprecated("Use new method StoreXCore.init(application: Application, configs: MutableList<StoreXConfig>) initialize properly",
60+
ReplaceWith("StoreXCore.init(application: Application, configs: MutableList<StoreXConfig>)"))
2161
fun init(application: Application, prefName: String): StoreXCore {
2262
this.instance = StoreXInstance(application, prefName, Gson())
2363
this.instance!!.registerListener(this.instance!!.listener)

StoreX/src/main/java/com/rommansabbir/storex/StoreXInstance.kt

Lines changed: 107 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import com.rommansabbir.storex.execptions.NoStoreAbleObjectFound
1313
import kotlinx.coroutines.CoroutineScope
1414
import kotlinx.coroutines.Dispatchers
1515
import kotlinx.coroutines.launch
16+
import kotlinx.coroutines.withContext
1617

1718

1819
internal class StoreXInstance(
@@ -47,24 +48,75 @@ internal class StoreXInstance(
4748
}
4849
}
4950

51+
override fun put(scope: CoroutineScope, key: String, value: StoreAbleObject) {
52+
scope.launch {
53+
try {
54+
val serializedValue: String = serializer.toJson(value)
55+
if (StoreXCore.encryptionKey == StoreXCore.NO_ENCRYPTION) {
56+
doCache(key, serializedValue)
57+
} else {
58+
val encryptedValue = EncryptionTool.encrypt(serializedValue)
59+
doCache(key, encryptedValue)
60+
}
61+
} catch (e: Exception) {
62+
throw e
63+
}
64+
}
65+
}
66+
5067
override fun <T : StoreAbleObject> put(
5168
key: String,
5269
value: StoreAbleObject,
5370
callback: SaveCallback<T>
5471
) {
55-
CoroutineScope(Dispatchers.Main).launch {
72+
CoroutineScope(Dispatchers.IO).launch {
5673
try {
5774
val serializedValue: String = serializer.toJson(value)
5875
if (StoreXCore.encryptionKey == StoreXCore.NO_ENCRYPTION) {
5976
doCache(key, serializedValue)
60-
callback.onDone(value as T, null)
77+
withContext(Dispatchers.Main){
78+
callback.onDone(value as T, null)
79+
}
6180
} else {
6281
val encryptedValue = EncryptionTool.encrypt(serializedValue)
6382
doCache(key, encryptedValue)
64-
callback.onDone(value as T, null)
83+
withContext(Dispatchers.Main){
84+
callback.onDone(value as T, null)
85+
}
6586
}
6687
} catch (e: Exception) {
67-
callback.onDone(value as T, e)
88+
withContext(Dispatchers.Main){
89+
callback.onDone(value as T, e)
90+
}
91+
}
92+
}
93+
}
94+
95+
override fun <T : StoreAbleObject> put(
96+
scope: CoroutineScope,
97+
key: String,
98+
value: StoreAbleObject,
99+
callback: SaveCallback<T>,
100+
) {
101+
scope.launch {
102+
try {
103+
val serializedValue: String = serializer.toJson(value)
104+
if (StoreXCore.encryptionKey == StoreXCore.NO_ENCRYPTION) {
105+
doCache(key, serializedValue)
106+
withContext(Dispatchers.Main){
107+
callback.onDone(value as T, null)
108+
}
109+
} else {
110+
val encryptedValue = EncryptionTool.encrypt(serializedValue)
111+
doCache(key, encryptedValue)
112+
withContext(Dispatchers.Main){
113+
callback.onDone(value as T, null)
114+
}
115+
}
116+
} catch (e: Exception) {
117+
withContext(Dispatchers.Main){
118+
callback.onDone(value as T, e)
119+
}
68120
}
69121
}
70122
}
@@ -99,26 +151,72 @@ internal class StoreXInstance(
99151
objectType: Class<T>,
100152
callback: GetCallback<T>
101153
) {
102-
CoroutineScope(Dispatchers.Main).launch {
154+
CoroutineScope(Dispatchers.IO).launch {
103155
try {
104156
when (val value = getCache(key)) {
105157
null -> {
106-
callback.onSuccess(null, NoStoreAbleObjectFound())
158+
withContext(Dispatchers.Main){
159+
callback.onSuccess(null, NoStoreAbleObjectFound())
160+
}
107161
}
108162
else -> {
109163
when (StoreXCore.encryptionKey == StoreXCore.NO_ENCRYPTION) {
110164
true -> {
111-
callback.onSuccess(serializer.fromJson(value, objectType))
165+
withContext(Dispatchers.Main){
166+
callback.onSuccess(serializer.fromJson(value, objectType))
167+
}
112168
}
113169
else -> {
114170
val decryptedValue = EncryptionTool.decrypt(value)
115-
callback.onSuccess(serializer.fromJson(decryptedValue, objectType))
171+
withContext(Dispatchers.Main){
172+
callback.onSuccess(serializer.fromJson(decryptedValue, objectType))
173+
}
116174
}
117175
}
118176
}
119177
}
120178
} catch (e: Exception) {
121-
callback.onSuccess(null, e)
179+
withContext(Dispatchers.Main){
180+
callback.onSuccess(null, e)
181+
}
182+
}
183+
}
184+
}
185+
186+
override fun <T : StoreAbleObject> get(
187+
scope: CoroutineScope,
188+
key: String,
189+
objectType: Class<T>,
190+
callback: GetCallback<T>,
191+
) {
192+
scope.launch {
193+
try {
194+
when (val value = getCache(key)) {
195+
null -> {
196+
withContext(Dispatchers.Main){
197+
callback.onSuccess(null, NoStoreAbleObjectFound())
198+
}
199+
}
200+
else -> {
201+
when (StoreXCore.encryptionKey == StoreXCore.NO_ENCRYPTION) {
202+
true -> {
203+
withContext(Dispatchers.Main){
204+
callback.onSuccess(serializer.fromJson(value, objectType))
205+
}
206+
}
207+
else -> {
208+
val decryptedValue = EncryptionTool.decrypt(value)
209+
withContext(Dispatchers.Main){
210+
callback.onSuccess(serializer.fromJson(decryptedValue, objectType))
211+
}
212+
}
213+
}
214+
}
215+
}
216+
} catch (e: Exception) {
217+
withContext(Dispatchers.Main){
218+
callback.onSuccess(null, e)
219+
}
122220
}
123221
}
124222
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
package com.rommansabbir.storex
2+
3+
internal data class StoreXState(internal val storeXInstance: StoreXInstance, val config : StoreXConfig)
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
package com.rommansabbir.storex.execptions
2+
3+
class DuplicateStoreXConfigException(@JvmField override val message: String = "Duplicate StoreXConfig found.") :
4+
RuntimeException(message)
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
package com.rommansabbir.storex.execptions
2+
3+
class NoConfigFoundException(@JvmField override val message: String = "No valid instance found for this StoreXConfig") :
4+
RuntimeException(message)

0 commit comments

Comments
 (0)