6

I am using Firebase Emulator Suite to test my Firebase Cloud Functions before deploying them into production.

Exploring this approach to trigger the callable firebase cloud functions from my Andriod device.

My App is crashing when I run it.

Error:

java.lang.IllegalStateException: Cannot call useEmulator() after instance has already been initialized.

Source of the error - FirebaseFirestore.java:

/**
   * Modifies this FirebaseDatabase instance to communicate with the Cloud Firestore emulator.
   *
   * <p>Note: Call this method before using the instance to do any database operations.
   *
   * @param host the emulator host (for example, 10.0.2.2)
   * @param port the emulator port (for example, 8080)
   */
  public void useEmulator(@NonNull String host, int port) {
    if (this.client != null) {
      throw new IllegalStateException(
          "Cannot call useEmulator() after instance has already been initialized.");
    }

    this.emulatorSettings = new EmulatedServiceSettings(host, port);
    this.settings = mergeEmulatorSettings(this.settings, this.emulatorSettings);
  }

Firestore is injected using the following method: (Using Hilt in my project)

@Provides
fun provideFirebaseFirestore(): FirebaseFirestore {

    val firebaseFirestoreSettings = FirebaseFirestoreSettings.Builder()
    firebaseFirestoreSettings.isPersistenceEnabled = false

    val firestore = FirebaseFirestore.getInstance()
    firestore.useEmulator("192.168.1.102", 8080)
    firestore.firestoreSettings = firebaseFirestoreSettings.build()

    return firestore
}

My doubt is useEmulator() in FirebaseFirestore.java is not a static method.
How can I call it before creating an instance of Firebase Firestore?

Doug Stevenson
  • 297,357
  • 32
  • 422
  • 441
Abhimanyu
  • 11,351
  • 7
  • 51
  • 121
  • Do you have any other code anywhere else in your app that calls `FirebaseFirestore.getInstance()`? – Doug Stevenson Nov 14 '20 at 16:34
  • @DougStevenson, Nope, the dependency is inside `@Module @InstallIn(ApplicationComponent::class) class FirebaseModule {....}` – Abhimanyu Nov 14 '20 at 17:01
  • Single module app at the moment. – Abhimanyu Nov 14 '20 at 17:01
  • 1
    If you have a stripped down, absolutely minimal application that generates this error with only the code you have here, I suggest filing a bug report with an explanation how to reproduce it. https://github.com/firebase/firebase-android-sdk – Doug Stevenson Nov 14 '20 at 17:03

4 Answers4

2

I have the same problem and the way I solved it wrap the firestore.useEmulator("192.168.1.102", 8080) in a try catch block like this

    try {
            firestore.useEmulator("192.168.1.102", 8080)
        } catch (e: IllegalStateException) {

        }
ilatyphi95
  • 555
  • 5
  • 22
0

That could be because the Firebase state is kept between tests. The useEmulator is then called twice against the same firebase app instance, raising the error. At least, that was what happened to me during tests.

The approach to check a nested "host" property in the firestore instance -- described in this answer -- was what worked for me.

João Melo
  • 784
  • 6
  • 16
0

Adding @Singleton to the function provideFirebaseFirestore() solved the issue for me, as it makes sure the class only gets instantiated once.

Adri_Dona
  • 1
  • 1
0

I had same issue with com.google.firebase:firebase-bom:32.0.0

As the documentation of useEmulator() method says:

Note: Call this method before using the instance to do any database operations.

I was calling these method before very first use during dependency injection, that was causing the issue.

Anyway SOLVED by lifting those call to MainActivitys onCreate method as:

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        if (USE_EMULATOR) {
            Firebase.auth.useEmulator(HOST, AUTH_PORT)
            Firebase.firestore.useEmulator(HOST, FIRESTORE_PORT)
        }
        setContent { MainContent() }
    }
}