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.
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: