javaandroidfirebasegoogle-cloud-platformgoogle-cloud-firestore

I can write to my Firebase Firestore database, but am unable to read from it (Android Studio using Java)


I am trying to connect my Android app to my Firestore database. I can write to my database from my app, but I am unable to read from it.

AndroidManifest:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">

    <uses-permission android:name="android.permission.INTERNET" />

    <application
        android:allowBackup="true"
        android:dataExtractionRules="@xml/data_extraction_rules"
        android:fullBackupContent="@xml/backup_rules"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.Cerebrospinal"
        tools:targetApi="31">
        <activity
            android:name=".SudokuActivity"
            android:exported="false" />
        <activity
            android:name=".Activity2048"
            android:exported="false" />
        <activity
            android:name=".WordleActivity"
            android:exported="false" />
        <activity
            android:name=".MainActivity"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

App level build.gradle

plugins {
    alias(libs.plugins.android.application)
    id("com.google.gms.google-services")
}

android {
    namespace = "com.example.cerebrospinal"
    compileSdk = 34

    defaultConfig {
        applicationId = "com.example.cerebrospinal"
        minSdk = 24
        targetSdk = 34
        versionCode = 1
        versionName = "1.0"

        testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
    }

    buildTypes {
        release {
            isMinifyEnabled = false
            proguardFiles(
                getDefaultProguardFile("proguard-android-optimize.txt"),
                "proguard-rules.pro"
            )
        }
    }
    compileOptions {
        sourceCompatibility = JavaVersion.VERSION_1_8
        targetCompatibility = JavaVersion.VERSION_1_8
    }
}

dependencies {

    implementation(platform("com.google.firebase:firebase-bom:33.5.1"))
    implementation("com.google.firebase:firebase-analytics")

    // Firestore
    implementation("com.google.firebase:firebase-firestore:25.1.1")

    // Other Firebase/Play services deps
    implementation("com.google.firebase:firebase-auth:21.0.1")
    implementation("com.google.android.gms:play-services-auth:21.2.0")

    // FirebaseUI (for authentication)
    implementation("com.firebaseui:firebase-ui-auth:8.0.0")

    implementation(libs.appcompat)
    implementation(libs.material)
    implementation(libs.activity)
    implementation(libs.constraintlayout)
    testImplementation(libs.junit)
    androidTestImplementation(libs.ext.junit)
    androidTestImplementation(libs.espresso.core)
}

Project level build.gradle:

// Top-level build file where you can add configuration options common to all sub-projects/modules.
plugins {
    alias(libs.plugins.android.application) apply false
    id("com.google.gms.google-services") version "4.4.2" apply false
}

Test code I am using to access my database:

oneButton = findViewById(R.id.button1);
        oneButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (sudokuController.getPencilMode() && sudokuController.getSelectedRow() > 0
                        && sudokuController.getSelectedColumn() > 0) {
                    sudokuController.setSelectedNumber(1);
                    sudokuController.setBoardTile();
                    sudokuBoard.invalidate();
                }
                FirebaseFirestore db = FirebaseFirestore.getInstance();
                // Create a new user with a first and last name
                Map<String, Object> user = new HashMap<>();
                user.put("first", "Ada");
                user.put("last", "Lovelace");
                user.put("born", 1815);

                // Add a new document with a generated ID
                db.collection("users")
                        .add(user)
                        .addOnSuccessListener(new OnSuccessListener<DocumentReference>() {
                            @Override
                            public void onSuccess(DocumentReference documentReference) {
                                Log.d(TAG, "DocumentSnapshot added with ID: " + documentReference.getId());
                            }
                        })
                        .addOnFailureListener(new OnFailureListener() {
                            @Override
                            public void onFailure(@NonNull Exception e) {
                                Log.w(TAG, "Error adding document", e);
                            }
                        });

                // Create a new user with a first, middle, and last name
                user = new HashMap<>();
                user.put("first", "Alan");
                user.put("middle", "Mathison");
                user.put("last", "Turing");
                user.put("born", 1912);

                // Add a new document with a generated ID
                db.collection("users")
                        .add(user)
                        .addOnSuccessListener(new OnSuccessListener<DocumentReference>() {
                            @Override
                            public void onSuccess(DocumentReference documentReference) {
                                Log.d(TAG, "DocumentSnapshot added with ID: " + documentReference.getId());
                            }
                        })
                        .addOnFailureListener(new OnFailureListener() {
                            @Override
                            public void onFailure(@NonNull Exception e) {
                                Log.w(TAG, "Error adding document", e);
                            }
                        });

                db.collection("users")
                        .get()
                        .addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
                            @Override
                            public void onComplete(@NonNull Task<QuerySnapshot> task) {
                                if (task.isSuccessful()) {
                                    for (QueryDocumentSnapshot document : task.getResult()) {
                                        Log.d(TAG, document.getId() + " => " + document.getData());
                                    }
                                } else {
                                    Log.w(TAG, "Error getting documents.", task.getException());
                                }
                            }
                        });
            }
        });

Logcat output after pressing the "oneButton":

2024-11-14 19:37:17.284  9790-9849  ProfileInstaller        com.example.cerebrospinal            D  Installing profile for com.example.cerebrospinal
2024-11-14 19:37:19.383  9790-9809  EGL_emulation           com.example.cerebrospinal            D  app_time_stats: avg=304.30ms min=13.14ms max=3634.54ms count=13
2024-11-14 19:37:19.620  9790-9790  ContentValues           com.example.cerebrospinal            D  ArTLEmYycQ7AkM3Autjg => {middle=Mathison, last=Turing, born=1912, first=Alan}
2024-11-14 19:37:19.620  9790-9790  ContentValues           com.example.cerebrospinal            D  JUIWkKMuC3wWTimIDdmP => {last=Lovelace, born=1815, first=Ada}
2024-11-14 19:37:19.620  9790-9790  ContentValues           com.example.cerebrospinal            D  LQ1tECj91ivvL7ZhF7i8 => {last=Lovelace, born=1815, first=Ada}
2024-11-14 19:37:19.620  9790-9790  ContentValues           com.example.cerebrospinal            D  xAmdrpHnykJarOA4ibt0 => {middle=Mathison, last=Turing, born=1912, first=Alan}
2024-11-14 19:37:19.724  9790-9790  ContentValues           com.example.cerebrospinal            D  DocumentSnapshot added with ID: LQ1tECj91ivvL7ZhF7i8
2024-11-14 19:37:19.756  9790-9790  ContentValues           com.example.cerebrospinal            D  DocumentSnapshot added with ID: xAmdrpHnykJarOA4ibt0
2024-11-14 19:37:25.332  9790-9840  GoogleApiManager        com.example.cerebrospinal            E  Failed to get service from broker.  (Ask Gemini)
                                                                                                    java.lang.SecurityException: Unknown calling package name 'com.google.android.gms'.
                                                                                                        at android.os.Parcel.createExceptionOrNull(Parcel.java:3242)
                                                                                                        at android.os.Parcel.createException(Parcel.java:3226)
                                                                                                        at android.os.Parcel.readException(Parcel.java:3209)
                                                                                                        at android.os.Parcel.readException(Parcel.java:3151)
                                                                                                        at amxe.a(:com.google.android.gms@244337038@24.43.37 (260800-693941914):36)
                                                                                                        at amvl.z(:com.google.android.gms@244337038@24.43.37 (260800-693941914):143)
                                                                                                        at amcs.run(:com.google.android.gms@244337038@24.43.37 (260800-693941914):54)
                                                                                                        at android.os.Handler.handleCallback(Handler.java:959)
                                                                                                        at android.os.Handler.dispatchMessage(Handler.java:100)
                                                                                                        at bskq.mC(:com.google.android.gms@244337038@24.43.37 (260800-693941914):1)
                                                                                                        at bskq.dispatchMessage(:com.google.android.gms@244337038@24.43.37 (260800-693941914):5)
                                                                                                        at android.os.Looper.loopOnce(Looper.java:232)
                                                                                                        at android.os.Looper.loop(Looper.java:317)
                                                                                                        at android.os.HandlerThread.run(HandlerThread.java:85)
2024-11-14 19:42:19.801  9790-9867  TrafficStats            com.example.cerebrospinal            D  tagSocket(136) with statsTag=0xffffffff, statsUid=-1
2024-11-14 19:42:19.881  9790-9867  TrafficStats            com.example.cerebrospinal            D  tagSocket(5) with statsTag=0xffffffff, statsUid=-1

I followed Android documentation to use the database in my app, and am using their example code to test it. I expected to be able to both read and write from/to my database but am unable to read from it.


Solution

  • I can write to my Firebase Firestore database, but am unable to read from it.

    That is normal behavior because all Firebase Firestore operations are asynchronous. What you are trying to do is to read the data that comes from the addition of two different users, which is not quite possible because both addition operations take time. So by the time you're trying to read the data, the addition operations are not complete, so the data is not available so it can be read. The solution is always the same. All async operations that should be performed as a result of other async operations, need to be inside the onSuccess/onComplete method or be called from there.

    So if you need to read the data of both users, then you have to make sure that both operations of adding the data to Firestore are successful. You can achieve this by using custom callbacks or by nesting the calls:

    db.collection("users").add(user).addOnSuccessListener {
    
        //Add it inside onSuccess
        db.collection("users").add(user).addOnSuccessListener {
    
            //Add it inside onSuccess
            db.collection("users").get().addOnCompleteListener{
                //Your logic.
            }
        }
    }
    

    Because you're using Java, you might consider using observable objects live LiveData.

    If you are considering learning Kotlin at some point in time, which I highly recommend, then you should consider using Kotlin Coroutines. In this way, you'll be able to wait for the operation to complete in a simpler and more efficient way. Please check below some resources: