← Back to google/agera

How to Deploy & Use google/agera

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.0 tag
  • 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>;
}