Kotlin
Introduction
Couchbase Lite Android 3.0.0 introduces full idiomatic support for Kotlin apps, out-of-the-box.
Kotlin developers can now build apps using common Kotlin Patterns, that integrate seamlessly with Couchbase Lite for Android and have full feature parity with the Java API; including some convenient Kotlin Extensions to get you started.
Key features include:
-
Nullability annotations
-
Named parameters
-
Kotlin Flows, for asynchronous event notifications
Java support and functionality continues for Android.
Kotlin Extensions
In addition to having full co-compatible access to the existing Java API, Kotlin developers can also access a number of Kotlin Extensions.
The Kotlin Extensions package includes:
-
Configuration Factories for the configuration of important Couchbase Lite objects such as Databases, Replicators and Listeners.
-
Change Flows that monitor key Couchbase Lite objects fpr change using Kotlin features such as, Co-routines and Flows.
See: Kotlin Extensions for extension API docs
Configuration Factories
Couchbase Lite provides a set of ConfigurationFactories and CommonConfigurationFactories, these allow use of named parameters to specify property settings.
Database
Use
DatabaseConfigurationFactory
to create a DatabaseConfiguration
object, overriding the receiver’s values with the passed parameters.
-
In Use
-
Definition
database = Database(
"getting-started",
DatabaseConfigurationFactory.create(context.filesDir.absolutePath)
)
val DatabaseConfigurationFactory: DatabaseConfiguration? = null
fun DatabaseConfiguration?.create(
databasePath: String? = null,
encryptionKey: EncryptionKey? = null
)
Replication
Use
ReplicatorConfigurationFactory
to create a ReplicatorConfiguration
object, overriding the receiver’s values with the passed parameters.
-
In Use
-
Definition
val replicator =
Replicator(
ReplicatorConfigurationFactory.create(
database = database,
target = URLEndpoint(URI("ws://localhost:4984/getting-started-db")),
type = ReplicatorType.PUSH_AND_PULL,
authenticator = BasicAuthenticator("sync-gateway", "password".toCharArray())
)
)
val ReplicatorConfigurationFactory: ReplicatorConfiguration? = null
fun ReplicatorConfiguration?.create(
database: Database? = null,
target: Endpoint? = null,
type: ReplicatorType? = null,
continuous: Boolean? = null,
authenticator: Authenticator? = null,
headers: Map<String, String>? = null,
pinnedServerCertificate: ByteArray? = null,
channels: List<String>? = null,
documentIDs: List<String>? = null,
pushFilter: ReplicationFilter? = null,
pullFilter: ReplicationFilter? = null,
conflictResolver: ConflictResolver? = null,
maxAttempts: Int? = null,
maxAttemptWaitTime: Int? = null,
heartbeat: Int? = null,
enableAutoPurge: Boolean? = null,
acceptOnlySelfSignedServerCertificate: Boolean? = null
)
val MessageEndpointListenerConfigurationFactory: MessageEndpointListenerConfiguration? = null
fun MessageEndpointListenerConfiguration?.create(
database: Database? = null,
protocolType: ProtocolType? = null
)
Full Text Search
Use
FullTextIndexConfigurationFactory
to create a FullTextIndexConfiguration
object, overriding the receiver’s values with the passed parameters.
-
In Use
-
Definition
db.createIndex("fts_index",
FullTextIndexConfigurationFactory.create(expressions = ["name","location"])
)
val FullTextIndexConfigurationFactory: FullTextIndexConfiguration? = null
fun FullTextIndexConfiguration?.create(expression: String? = null)
Indexing
Use
ValueIndexConfigurationFactory
to create a ValueIndexConfiguration
object, overriding the receiver’s values with the passed parameters.
-
In Use
-
Definition
db.createIndex("name_and_location_index",
ValueIndexConfigurationFactory.create(expressions = ["name","location"])
)
val ValueIndexConfigurationFactory: ValueIndexConfiguration? = null
fun ValueIndexConfiguration?.create(vararg expressions: String = emptyArray())
Logs
Use
LogFileConfigurationFactory
to create a LogFileConfiguration
object, overriding the receiver’s values with the passed parameters.
-
In Use
-
Definition
Database.log.file.let {
it.config = LogFileConfigurationFactory.create(
context.cacheDir.absolutePath, (1)
maxSize = 10240, (2)
maxRotateCount = 5, (3)
usePlainText = false
) (4)
it.level = LogLevel.INFO (5)
}
val LogFileConfigurationFactory: LogFileConfiguration? = null
.LogFileConfiguration.create()
fun LogFileConfiguration?.create(
directory: String? = null,
maxSize: Long? = null,
maxRotateCount: Int? = null,
usePlainText: Boolean? = null
)
Flows
These wrappers use Flowables to monitor for changes.
Database Change Flow
Use the databaseChangeFlow(Database,Executor) to monitor database change events.
-
In Use
-
Definition
val updatedDocs = db.databaseChangeFlow()
.map { it.documentIDs }
.asLiveData()
@ExperimentalCoroutinesApi
fun Database.databaseChangeFlow(executor: Executor? = null)
Document Change Flow
Use documentChangeFlow(Database,String,Executor) to monitor changes to a document.
-
In Use
-
Definition
val docModDate = db.documentChangeFlow("1001", null)
.map { it.database.getDocument(it.documentID)?.getString("lastModified") }
.asLiveData()
@ExperimentalCoroutinesApi
fun Database.documentChangeFlow(documentId: String, executor: Executor? = null)
Replicator Change Flow
Use replicatorChangeFlow(Replicator,Executor) to monitor replicator changes.
-
In Use
-
Definition
val replState = repl.replicatorChangesFlow()
.map { it.status.activityLevel }
.asLiveData()
@ExperimentalCoroutinesApi
fun Replicator.replicatorChangesFlow(executor: Executor? = null)
Document Replicator Change Flow
Use documentReplicationFlow(Replicator,Executor) to monitor document changes during replication.
-
In Use
-
Definition
val replicatedDocs = repl.documentReplicationFlow(testSerialExecutor)
.map { update -> update.documents }
.onEach { listView.setUpdated(it) }
.collect()
@ExperimentalCoroutinesApi
fun Replicator.documentReplicationFlow(executor: Executor? = null)
Query Change Flow
Use queryChangeFlow(Query,Executor) to monitor document changes during replication.
-
In Use
-
Definition
var liveQuery: LiveData<List<Any>?>? = null
@ExperimentalCoroutinesApi
fun watchQuery(query: Query): LiveData<List<Any>?> {
val queryFlow = query.queryChangeFlow()
.map {
val err = it.error
if (err != null) {
throw err
}
it.results?.allResults()?.flatMap { it.toList() }
}
.asLiveData()
liveQuery = queryFlow
return queryFlow
}
@ExperimentalCoroutinesApi
fun Query.queryChangeFlow(executor: Executor? = null)