Agera Deployment & Usage Guide
Reactive Programming for Android
1. Prerequisites
- Android Studio: Latest stable version (3.0+ recommended)
- JDK: Java 8 or higher
- Android SDK: API level 9 (Android 2.3 Gingerbread) minimum; API 16+ recommended for extensions
- Gradle: 3.0+ (Android Gradle Plugin) or use the included wrapper
- Build Tools: Android SDK Build-Tools 28.0.0 or higher
2. Installation
Option A: Add as Dependency (Recommended)
Add to your app's build.gradle:
dependencies {
// Core library
implementation 'com.google.android.agera:agera:1.4.0'
// Optional extensions
implementation 'com.google.android.agera:content:1.4.0' // BroadcastReceiver, SharedPreferences
implementation 'com.google.android.agera:database:1.4.0' // SQLiteDatabase
implementation 'com.google.android.agera:net:1.4.0' // HTTPUrlConnection
implementation 'com.google.android.agera:rvadapter:1.4.0' // RecyclerView
implementation 'com.google.android.agera:rvdatabinding:1.4.0' // RecyclerView data binding
}
Option B: Build from Source
# Clone repository
git clone https://github.com/google/agera.git
cd agera
# Build library
./gradlew assembleRelease
# Run tests
./gradlew test
# Install to local Maven repository
./gradlew publishToMavenLocal
3. Configuration
Gradle Configuration
Ensure minSdkVersion is set appropriately:
android {
defaultConfig {
minSdkVersion 9 // Minimum required by Agera
targetSdkVersion 28
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}
AndroidManifest.xml (Net Extension)
If using the net extension, add internet permission:
<uses-permission android:name="android.permission.INTERNET" />
ProGuard/R8 Rules
Add to proguard-rules.pro if using code shrinking:
-keep class com.google.android.agera.** { *; }
-dontwarn com.google.android.agera.**
4. Build & Run
Local Development Build
# Clean build
./gradlew clean
# Build all modules
./gradlew build
# Run unit tests
./gradlew test
# Run connected Android tests (requires device/emulator)
./gradlew connectedAndroidTest
Basic Usage Example
Create a reactive repository in your Activity or Fragment:
import com.google.android.agera.Repository;
import com.google.android.agera.Updatable;
import static com.google.android.agera.Repositories.repositoryWithInitialValue;
import static com.google.android.agera.RepositoryConfig.SEND_INTERRUPT;
public class MainActivity extends AppCompatActivity implements Updatable {
private Repository<String> dataRepository;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Compile a repository with data flow
dataRepository = repositoryWithInitialValue("Initial")
.observe() // Add observables here
.onUpdatesPerLoop()
.goTo(Executors.newSingleThreadExecutor()) // Background thread
.thenGetFrom(() -> fetchDataFromNetwork()) // Supplier
.thenTransform(data -> processData(data)) // Function
.onDeactivation(SEND_INTERRUPT)
.compile();
}
@Override
protected void onResume() {
super.onResume();
dataRepository.addUpdatable(this);
}
@Override
protected void onPause() {
super.onPause();
dataRepository.removeUpdatable(this);
}
@Override
public void update() {
// Called when repository data changes
String newData = dataRepository.get();
updateUI(newData);
}
}
Using Result<T> for Error Handling
import com.google.android.agera.Result;
import static com.google.android.agera.Result.success;
import static com.google.android.agera.Result.failure;
public Result<String> fetchData() {
try {
String data = makeNetworkCall();
return success(data);
} catch (IOException e) {
return failure(e);
}
}
// Usage
Result<String> result = fetchData();
if (result.succeeded()) {
String value = result.get();
} else {
Throwable error = result.getFailure();
}
RecyclerView Integration (RVAdapter Extension)
import com.google.android.agera.rvadapter.RepositoryAdapter;
RepositoryAdapter adapter = new RepositoryAdapter.Builder()
.add(dataRepository, new DataPresenter()) // Your presenter implementation
.build();
recyclerView.setAdapter(adapter);
adapter.startObserving(); // Don't forget to stopObserving() in onDestroy
5. Deployment
Production Integration
For production Android apps, pin the version and exclude transitive dependencies if conflicts arise:
dependencies {
implementation('com.google.android.agera:agera:1.4.0') {
exclude group: 'com.android.support'
}
}
Publishing Custom Fork (Library Maintainers)
If modifying Agera for internal use:
# Build release AAR
./gradlew :agera:assembleRelease
# Output location
# agera/build/outputs/aar/agera-release.aar
# Publish to internal Maven/Bintray
./gradlew bintrayUpload
Version Management Strategy
- Stable releases: Use
1.4.0tag - Snapshot builds: Available via JCenter snapshot repository
- Extension compatibility: Ensure all extensions use the same version number
6. Troubleshooting
Dependency Resolution Failures
Issue: Could not find com.google.android.agera:agera:1.4.0
Solution: Ensure repositories include JCenter:
repositories {
jcenter()
google()
}
Threading Exceptions
Issue: IllegalStateException: Not on main thread
Solution: Agera requires Updatable registration/unregistration on main thread. Use:
runOnUiThread(() -> repository.addUpdatable(this));
Memory Leaks
Issue: Activity leaked after destruction
Solution: Always remove updatables in lifecycle callbacks:
@Override
protected void onDestroy() {
super.onDestroy();
repository.removeUpdatable(this);
adapter.stopObserving(); // If using RepositoryAdapter
}
Result Type Conflicts
Issue: Result class collision with other libraries
Solution: Use fully qualified class names:
com.google.android.agera.Result<String> result = ...
ProGuard Issues
Issue: ClassNotFoundException for compiled repositories at runtime
Solution: Keep Agera internals:
-keepclassmembers class * {
@com.google.android.agera.BindTo <methods>;
}