-
-
Notifications
You must be signed in to change notification settings - Fork 14
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
59 changed files
with
1,922 additions
and
14 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,192 @@ | ||
# Chamber | ||
Simplifies sharing fields and communication between Android components with custom scopes that are lifecycle aware. | ||
|
||
<p align="center"> | ||
<a href="https://opensource.org/licenses/Apache-2.0"><img alt="License" src="https://img.shields.io/badge/License-Apache%202.0-blue.svg"/></a> | ||
<a href="https://android-arsenal.com/api?level=15"><img alt="API" src="https://img.shields.io/badge/API-15%2B-brightgreen.svg?style=flat"/></a> | ||
</p> | ||
|
||
<p align="center"> | ||
Simplifies sharing fields and communication between <br> | ||
Android components with custom scopes that are lifecycle aware. | ||
</p> | ||
|
||
> <p align="center">Android components are the essential building blocks of an Android application. <br>These independent components are loosely coupled. The benefit is that they are really independently reusable,<br> but it makes to hard communicate with each other. </p> | ||
><p align="center"> The goal of this library is making easier to communicate and flow data with each other <br>component like Activity, Fragment, Services, etc.<br> And using custom scopes that are lifecycle aware makes<br> developers can designate scoped data holder on their taste.</p> | ||
## When is useful? | ||
>When we need to hold some immutable data and it needs to be synchronized as the same data at each other components. For example, there is `Activity A`, `Activity B`, `Activity C`. And we need to use the same data in all Activity A~C that can be changed. Then we should pass a parcelable data A to B and B to C and getting the changed data reversely through onActivityResult. | ||
>Then how about the communication with fragments? We can solve it by implementing an interface, singleton pattern, observer pattern or etc, but the data flow would be quite complicated. Chamber helps to simplify those communications between Chamber scope owners. | ||
## Download | ||
|
||
### Gradle | ||
Add a dependency code to your **module**'s `build.gradle` file. | ||
```gradle | ||
dependencies { | ||
implementation "com.github.skydoves:chamber:1.0.0" | ||
} | ||
``` | ||
|
||
## Usage | ||
Chamber is scoped data holder with custom scopes that are lifecycle aware. | ||
### ChamberScope | ||
The basic usage is creating a customized scope annotation using a `@ChamberScope` annotation. <br> | ||
`@ChamberScope` is used to build custom scopes that are lifecycle aware. Each scope is a temporal data holder that has `ChamberField` data and lifecycle stack. It should be annotated a class (activity, fragment, repository or any classes) that has `ChamberField` fields. | ||
```kotlin | ||
@ChamberScope | ||
@Retention(AnnotationRetention.RUNTIME) | ||
annotation class UserScope | ||
``` | ||
|
||
### ChamberField | ||
ChamberField is an interactive class to the internal Chamber data holder and a lifecycleObserver <br>that can be observable. | ||
It should be used with `@ShareProperty` annotation that has a key name. If we want to use the same synchronized value on the same custom scope and different classes, we should use the same key. | ||
|
||
```kotlin | ||
@ShareProperty("name") // name is a key name. | ||
var username = ChamberField("skydoves") // ChamberField can be initialized with any object. | ||
``` | ||
|
||
#### setValue | ||
Using the `setValue` method, we can change the `ChamberField`'s value. | ||
```kotlin | ||
username.setValue("user name is changed") | ||
``` | ||
#### postValue | ||
Posts a task to a main thread to set the given value. So if you have a following code executed in the main thread: | ||
```kotlin | ||
username.postValue("a") | ||
username.setValue("b") | ||
``` | ||
The value `b` would be set at first and later the main thread would override it with the value `a`. | ||
|
||
#### observe | ||
We can observe the value is changed using the `observe` method. | ||
```kotlin | ||
username.observe { | ||
log("data is changed to $it") | ||
} | ||
``` | ||
|
||
### ShareLifecycle | ||
Chamber synchronizes the ChamberField that has the same scope and same key. <br> | ||
Also pushes a lifecycleOwner to the Chamber's lifecycle stack.<br> | ||
Here is an example that has _MainActivity_ and _SecondActivity_. | ||
|
||
#### MainActivity | ||
__Chamber__ will create a `@UserScope` data holder. <br> | ||
when `Chamber.shareLifecycle` method called, the `name` field that has `nickname` key will be managed by Chamber and Chamber will observe the _MainActivity_'s lifecycle state. | ||
|
||
```kotlin | ||
@UserScope // custom scope | ||
class MainActivity : AppCompatActivity() { | ||
|
||
@ShareProperty("nickname") | ||
private var name = ChamberField("skydoves") | ||
|
||
override fun onCreate(savedInstanceState: Bundle?) { | ||
super.onCreate(savedInstanceState) | ||
setContentView(R.layout.activity_main) | ||
|
||
Chamber.shareLifecycle(scopeOwner = this, lifecycleOwner = this) | ||
|
||
name.value = "name value is changed" | ||
|
||
startActivity(SecondActivity::class.java) | ||
} | ||
} | ||
``` | ||
|
||
#### MainActivity -> SecondActivity | ||
_MainActivity_ starts _SecondActivity_ using startActivity. <br>__Chamber__ will observe the _SecondActivity_'s lifecycle state. And the `name` field's value on the <br>_SecondActivity_ will be updated by __Chamber__ when `shareLifecycle` method called. | ||
```kotlin | ||
@UserScope | ||
class SecondActivity : AppCompatActivity() { | ||
|
||
@ShareProperty("nickname") | ||
private var name = ChamberField("skydoves") | ||
|
||
override fun onCreate(savedInstanceState: Bundle?) { | ||
super.onCreate(savedInstanceState) | ||
setContentView(R.layout.activity_second) | ||
|
||
Chamber.shareLifecycle(scopeOwner = this, lifecycleOwner = this) | ||
|
||
// the value is "name value is changed". because it was set in MainActivity. | ||
log("name value is .. ${username.value}") | ||
|
||
name.value = "changed in SecondActivity" | ||
|
||
finish() | ||
} | ||
} | ||
``` | ||
|
||
#### SeondActivity -> MainActivity | ||
`finish` method called in _SecondActivity_ and we come back to the _MainActivity_. <br>when _SecondActivity_'s lifecycle state is `onDestroy`, __Chamber__ will not interact anymore with the _SecondActivity_'s `ChamberField` and not observe lifecycle state. <br>And when _MainActivity_'s lifecycle state is `onResume`, __Chamber__ will update the `ChamberField`'s value in _MainActivity_. | ||
```kotlin | ||
@UserScope | ||
class MainActivity : AppCompatActivity() { | ||
|
||
@ShareProperty("nickname") | ||
private var name = ChamberField("skydoves") | ||
|
||
override fun onCreate(savedInstanceState: Bundle?) { | ||
super.onCreate(savedInstanceState) | ||
setContentView(R.layout.activity_second) | ||
|
||
// the value is "changed in SecondActivity". because it was set in SecondActivity. | ||
name.observe { | ||
log("name value is .. ${username.value}") | ||
} | ||
} | ||
} | ||
``` | ||
#### finish MainActivity | ||
After all lifecycle owners are destroyed (all lifecycleOwners are popped from the __Chamber__'s lifecycle stack), the custom scope data space will be cleared in the internal data holder. | ||
|
||
### Using on repository pattern | ||
Architecturally, UI components should do work relate to UI works.<br>So it is more preferred to implement Chamber scope class on repository class. | ||
|
||
```kotlin | ||
@UserScope // custom scope | ||
class MainActivityRepository(lifecycleOwner: LifecycleOwner) { | ||
|
||
@ShareProperty("nickname") | ||
var name = ChamberField("skydoves") | ||
|
||
init { | ||
// inject field data and add a lifecycleOwner to the UserScope scope stack. | ||
Chamber.shareLifecycle(scopeOwner = this, lifecycleOwner = lifecycleOwner) | ||
} | ||
} | ||
|
||
class MainActivity : AppCompatActivity() { | ||
|
||
private val repository = MainActivityRepository(this) | ||
|
||
// ... | ||
} | ||
``` | ||
|
||
## Find this library useful? :heart: | ||
Support it by joining __[stargazers](https://github.com/skydoves/chamber/stargazers)__ for this repository. :star: | ||
|
||
# License | ||
```xml | ||
Copyright 2019 skydoves (Jaewoong Eum) | ||
|
||
Licensed under the Apache License, Version 2.0 (the "License"); | ||
you may not use this file except in compliance with the License. | ||
You may obtain a copy of the License at | ||
|
||
http://www.apache.org/licenses/LICENSE-2.0 | ||
|
||
Unless required by applicable law or agreed to in writing, software | ||
distributed under the License is distributed on an "AS IS" BASIS, | ||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
See the License for the specific language governing permissions and | ||
limitations under the License. | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
/build |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
apply plugin: 'com.android.application' | ||
apply plugin: 'kotlin-android' | ||
apply plugin: 'kotlin-android-extensions' | ||
apply from: '../dependencies.gradle' | ||
|
||
android { | ||
compileSdkVersion versions.compileSdk | ||
defaultConfig { | ||
applicationId "com.skydoves.chamberdemo" | ||
minSdkVersion versions.minSdk | ||
targetSdkVersion versions.compileSdk | ||
versionCode versions.versionCode | ||
versionName versions.versionName | ||
} | ||
buildTypes { | ||
release { | ||
minifyEnabled false | ||
} | ||
} | ||
} | ||
|
||
dependencies { | ||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$versions.kotlin" | ||
implementation "androidx.appcompat:appcompat:$versions.androidxAppcompat" | ||
implementation project(":chamber") | ||
} | ||
|
||
apply from: '../spotless.gradle' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
# Add project specific ProGuard rules here. | ||
# You can control the set of applied configuration files using the | ||
# proguardFiles setting in build.gradle. | ||
# | ||
# For more details, see | ||
# http://developer.android.com/guide/developing/tools/proguard.html | ||
|
||
# If your project uses WebView with JS, uncomment the following | ||
# and specify the fully qualified class name to the JavaScript interface | ||
# class: | ||
#-keepclassmembers class fqcn.of.javascript.interface.for.webview { | ||
# public *; | ||
#} | ||
|
||
# Uncomment this to preserve the line number information for | ||
# debugging stack traces. | ||
#-keepattributes SourceFile,LineNumberTable | ||
|
||
# If you keep the line number information, uncomment this to | ||
# hide the original source file name. | ||
#-renamesourcefileattribute SourceFile |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
<?xml version="1.0" encoding="utf-8"?> | ||
<manifest xmlns:android="http://schemas.android.com/apk/res/android" | ||
xmlns:tools="http://schemas.android.com/tools" | ||
package="com.skydoves.chamberdemo"> | ||
|
||
<application | ||
android:allowBackup="true" | ||
android:icon="@mipmap/ic_launcher" | ||
android:label="@string/app_name" | ||
android:roundIcon="@mipmap/ic_launcher_round" | ||
android:supportsRtl="true" | ||
android:theme="@style/AppTheme" | ||
tools:ignore="AllowBackup,GoogleAppIndexingWarning"> | ||
<activity android:name=".ThirdActivity" /> | ||
<activity android:name=".SecondActivity" /> | ||
<activity android:name=".MainActivity"> | ||
<intent-filter> | ||
<action android:name="android.intent.action.MAIN" /> | ||
<category android:name="android.intent.category.LAUNCHER" /> | ||
</intent-filter> | ||
</activity> | ||
</application> | ||
</manifest> |
49 changes: 49 additions & 0 deletions
49
app/src/main/java/com/skydoves/chamberdemo/MainActivity.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
/* | ||
* Copyright (C) 2019 skydoves | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
package com.skydoves.chamberdemo | ||
|
||
import android.content.Intent | ||
import android.os.Bundle | ||
import android.util.Log | ||
import androidx.appcompat.app.AppCompatActivity | ||
import kotlinx.android.synthetic.main.activity_main.* | ||
|
||
class MainActivity : AppCompatActivity() { | ||
|
||
private val repository = MainActivityRepository(this) | ||
|
||
override fun onResume() { | ||
super.onResume() | ||
Log.e("Test", repository.username.value) | ||
} | ||
|
||
override fun onCreate(savedInstanceState: Bundle?) { | ||
super.onCreate(savedInstanceState) | ||
setContentView(R.layout.activity_main) | ||
|
||
repository.username.value = "skydoves on MainActivity" | ||
repository.username.observe { Log.e("Test", "data is changed! : $it") } | ||
|
||
button.setOnClickListener { | ||
startActivity(Intent(this, SecondActivity::class.java)) | ||
} | ||
|
||
button2.setOnClickListener { | ||
Log.e("Test", repository.username.value) | ||
} | ||
} | ||
} |
Oops, something went wrong.