From 7d7ba26ed71de50a06b6600e507038d10de5597a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=BAlio=20Cotta?= Date: Sun, 25 Aug 2019 20:58:22 -0300 Subject: [PATCH 1/9] Migrate from Activity to Handler to avoid NullPointerException. --- .../cloudfirestore/CloudFirestorePlugin.java | 24 +++++++++---------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/packages/cloud_firestore/android/src/main/java/io/flutter/plugins/firebase/cloudfirestore/CloudFirestorePlugin.java b/packages/cloud_firestore/android/src/main/java/io/flutter/plugins/firebase/cloudfirestore/CloudFirestorePlugin.java index e13697ab4c7d..c19c122448bf 100644 --- a/packages/cloud_firestore/android/src/main/java/io/flutter/plugins/firebase/cloudfirestore/CloudFirestorePlugin.java +++ b/packages/cloud_firestore/android/src/main/java/io/flutter/plugins/firebase/cloudfirestore/CloudFirestorePlugin.java @@ -4,8 +4,8 @@ package io.flutter.plugins.firebase.cloudfirestore; -import android.app.Activity; import android.os.AsyncTask; +import android.os.Handler; import android.util.Log; import android.util.SparseArray; import androidx.annotation.NonNull; @@ -59,8 +59,7 @@ public class CloudFirestorePlugin implements MethodCallHandler { private static final String TAG = "CloudFirestorePlugin"; private final MethodChannel channel; - private final Activity activity; - + private final Handler handler = new Handler(); // Handles are ints used as indexes into the sparse array of active observers private int nextListenerHandle = 0; private int nextBatchHandle = 0; @@ -77,12 +76,11 @@ public static void registerWith(PluginRegistry.Registrar registrar) { registrar.messenger(), "plugins.flutter.io/cloud_firestore", new StandardMethodCodec(FirestoreMessageCodec.INSTANCE)); - channel.setMethodCallHandler(new CloudFirestorePlugin(channel, registrar.activity())); + channel.setMethodCallHandler(new CloudFirestorePlugin(channel)); } - private CloudFirestorePlugin(MethodChannel channel, Activity activity) { + private CloudFirestorePlugin(MethodChannel channel) { this.channel = channel; - this.activity = activity; } private FirebaseFirestore getFirestore(Map arguments) { @@ -383,7 +381,7 @@ public Map apply(@NonNull Transaction transaction) { completionTasks.append(transactionId, transactionTCS); // Start operations on Dart side. - activity.runOnUiThread( + handler.post( new Runnable() { @Override public void run() { @@ -467,7 +465,7 @@ protected Void doInBackground(Void... voids) { metadata.put("hasPendingWrites", documentSnapshot.getMetadata().hasPendingWrites()); metadata.put("isFromCache", documentSnapshot.getMetadata().isFromCache()); snapshotMap.put("metadata", metadata); - activity.runOnUiThread( + handler.post( new Runnable() { @Override public void run() { @@ -475,7 +473,7 @@ public void run() { } }); } catch (final FirebaseFirestoreException e) { - activity.runOnUiThread( + handler.post( new Runnable() { @Override public void run() { @@ -499,7 +497,7 @@ protected Void doInBackground(Void... voids) { Map data = (Map) arguments.get("data"); try { transaction.update(getDocumentReference(arguments), data); - activity.runOnUiThread( + handler.post( new Runnable() { @Override public void run() { @@ -507,7 +505,7 @@ public void run() { } }); } catch (final IllegalStateException e) { - activity.runOnUiThread( + handler.post( new Runnable() { @Override public void run() { @@ -530,7 +528,7 @@ public void run() { protected Void doInBackground(Void... voids) { Map data = (Map) arguments.get("data"); transaction.set(getDocumentReference(arguments), data); - activity.runOnUiThread( + handler.post( new Runnable() { @Override public void run() { @@ -550,7 +548,7 @@ public void run() { @Override protected Void doInBackground(Void... voids) { transaction.delete(getDocumentReference(arguments)); - activity.runOnUiThread( + handler.post( new Runnable() { @Override public void run() { From 76587b7c3d407eaaf45d6852f2bd001a5de18fd2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=BAlio=20Cotta?= Date: Sun, 25 Aug 2019 22:34:20 -0300 Subject: [PATCH 2/9] Removed AsyncTasks as it is not needed. Included Transaction in sample. --- .../cloudfirestore/CloudFirestorePlugin.java | 268 ++++++++---------- .../cloud_firestore/example/lib/main.dart | 8 +- 2 files changed, 128 insertions(+), 148 deletions(-) diff --git a/packages/cloud_firestore/android/src/main/java/io/flutter/plugins/firebase/cloudfirestore/CloudFirestorePlugin.java b/packages/cloud_firestore/android/src/main/java/io/flutter/plugins/firebase/cloudfirestore/CloudFirestorePlugin.java index c19c122448bf..28548d3fc6ff 100644 --- a/packages/cloud_firestore/android/src/main/java/io/flutter/plugins/firebase/cloudfirestore/CloudFirestorePlugin.java +++ b/packages/cloud_firestore/android/src/main/java/io/flutter/plugins/firebase/cloudfirestore/CloudFirestorePlugin.java @@ -4,7 +4,6 @@ package io.flutter.plugins.firebase.cloudfirestore; -import android.os.AsyncTask; import android.os.Handler; import android.util.Log; import android.util.SparseArray; @@ -153,7 +152,7 @@ private Map parseQuerySnapshot(QuerySnapshot querySnapshot) { for (DocumentSnapshot document : querySnapshot.getDocuments()) { paths.add(document.getReference().getPath()); documents.add(document.getData()); - Map metadata = new HashMap(); + Map metadata = new HashMap<>(); metadata.put("hasPendingWrites", document.getMetadata().hasPendingWrites()); metadata.put("isFromCache", document.getMetadata().isFromCache()); metadatas.add(metadata); @@ -182,7 +181,7 @@ private Map parseQuerySnapshot(QuerySnapshot querySnapshot) { change.put("newIndex", documentChange.getNewIndex()); change.put("document", documentChange.getDocument().getData()); change.put("path", documentChange.getDocument().getReference().getPath()); - Map metadata = new HashMap(); + Map metadata = new HashMap<>(); metadata.put( "hasPendingWrites", documentChange.getDocument().getMetadata().hasPendingWrites()); metadata.put("isFromCache", documentChange.getDocument().getMetadata().isFromCache()); @@ -203,12 +202,11 @@ private Transaction getTransaction(Map arguments) { return transactions.get((Integer) arguments.get("transactionId")); } + @SuppressWarnings("unchecked") private Query getQuery(Map arguments) { Query query = getReference(arguments); - @SuppressWarnings("unchecked") Map parameters = (Map) arguments.get("parameters"); if (parameters == null) return query; - @SuppressWarnings("unchecked") List> whereConditions = (List>) parameters.get("where"); for (List condition : whereConditions) { String fieldName = (String) condition.get(0); @@ -230,12 +228,14 @@ private Query getQuery(Map arguments) { // Invalid operator. } } - @SuppressWarnings("unchecked") + Number limit = (Number) parameters.get("limit"); if (limit != null) query = query.limit(limit.longValue()); - @SuppressWarnings("unchecked") + List> orderBy = (List>) parameters.get("orderBy"); + if (orderBy == null) return query; + for (List order : orderBy) { String orderByFieldName = (String) order.get(0); boolean descending = (boolean) order.get(1); @@ -243,14 +243,14 @@ private Query getQuery(Map arguments) { descending ? Query.Direction.DESCENDING : Query.Direction.ASCENDING; query = query.orderBy(orderByFieldName, direction); } - @SuppressWarnings("unchecked") + Map startAtDocument = (Map) parameters.get("startAtDocument"); - @SuppressWarnings("unchecked") + Map startAfterDocument = (Map) parameters.get("startAfterDocument"); - @SuppressWarnings("unchecked") + Map endAtDocument = (Map) parameters.get("endAtDocument"); - @SuppressWarnings("unchecked") + Map endBeforeDocument = (Map) parameters.get("endBeforeDocument"); if (startAtDocument != null @@ -268,24 +268,30 @@ private Query getQuery(Map arguments) { if (startAfterDocument != null) { query = query.startAfter(getDocumentValues(startAfterDocument, orderBy, arguments)); } - @SuppressWarnings("unchecked") + List startAt = (List) parameters.get("startAt"); + if (startAt != null) query = query.startAt(startAt.toArray()); - @SuppressWarnings("unchecked") + List startAfter = (List) parameters.get("startAfter"); + if (startAfter != null) query = query.startAfter(startAfter.toArray()); + if (endAtDocument != null) { query = query.endAt(getDocumentValues(endAtDocument, orderBy, arguments)); } if (endBeforeDocument != null) { query = query.endBefore(getDocumentValues(endBeforeDocument, orderBy, arguments)); } - @SuppressWarnings("unchecked") + List endAt = (List) parameters.get("endAt"); + if (endAt != null) query = query.endAt(endAt.toArray()); - @SuppressWarnings("unchecked") + List endBefore = (List) parameters.get("endBefore"); + if (endBefore != null) query = query.endBefore(endBefore.toArray()); + return query; } @@ -360,7 +366,7 @@ public void onFailure(@NonNull Exception e) { } @Override - public void onMethodCall(MethodCall call, final Result result) { + public void onMethodCall(final MethodCall call, @NonNull final Result result) { switch (call.method) { case "Firestore#runTransaction": { @@ -376,7 +382,7 @@ public void onMethodCall(MethodCall call, final Result result) { @Override public Map apply(@NonNull Transaction transaction) { // Store transaction. - int transactionId = (Integer) arguments.get("transactionId"); + Integer transactionId = call.argument("transactionId"); transactions.append(transactionId, transaction); completionTasks.append(transactionId, transactionTCS); @@ -417,7 +423,7 @@ public void notImplemented() { // Wait till transaction is complete. try { String timeoutKey = "transactionTimeout"; - long timeout = ((Number) arguments.get(timeoutKey)).longValue(); + Long timeout = call.argument(timeoutKey); final Map transactionResult = Tasks.await(transactionTCSTask, timeout, TimeUnit.MILLISECONDS); @@ -433,7 +439,7 @@ public void notImplemented() { .addOnCompleteListener( new OnCompleteListener>() { @Override - public void onComplete(Task> task) { + public void onComplete(@NonNull Task> task) { if (task.isSuccessful()) { result.success(task.getResult()); } else { @@ -448,116 +454,94 @@ public void onComplete(Task> task) { { final Map arguments = call.arguments(); final Transaction transaction = getTransaction(arguments); - new AsyncTask() { - @Override - protected Void doInBackground(Void... voids) { - try { - DocumentSnapshot documentSnapshot = - transaction.get(getDocumentReference(arguments)); - final Map snapshotMap = new HashMap<>(); - snapshotMap.put("path", documentSnapshot.getReference().getPath()); - if (documentSnapshot.exists()) { - snapshotMap.put("data", documentSnapshot.getData()); - } else { - snapshotMap.put("data", null); - } - Map metadata = new HashMap(); - metadata.put("hasPendingWrites", documentSnapshot.getMetadata().hasPendingWrites()); - metadata.put("isFromCache", documentSnapshot.getMetadata().isFromCache()); - snapshotMap.put("metadata", metadata); - handler.post( - new Runnable() { - @Override - public void run() { - result.success(snapshotMap); - } - }); - } catch (final FirebaseFirestoreException e) { - handler.post( - new Runnable() { - @Override - public void run() { - result.error("Error performing Transaction#get", e.getMessage(), null); - } - }); - } - return null; + + try { + DocumentSnapshot documentSnapshot = transaction.get(getDocumentReference(arguments)); + final Map snapshotMap = new HashMap<>(); + snapshotMap.put("path", documentSnapshot.getReference().getPath()); + if (documentSnapshot.exists()) { + snapshotMap.put("data", documentSnapshot.getData()); + } else { + snapshotMap.put("data", null); } - }.execute(); + Map metadata = new HashMap<>(); + metadata.put("hasPendingWrites", documentSnapshot.getMetadata().hasPendingWrites()); + metadata.put("isFromCache", documentSnapshot.getMetadata().isFromCache()); + snapshotMap.put("metadata", metadata); + handler.post( + new Runnable() { + @Override + public void run() { + result.success(snapshotMap); + } + }); + } catch (final FirebaseFirestoreException e) { + handler.post( + new Runnable() { + @Override + public void run() { + result.error("Error performing Transaction#get", e.getMessage(), null); + } + }); + } break; } case "Transaction#update": { final Map arguments = call.arguments(); final Transaction transaction = getTransaction(arguments); - new AsyncTask() { - @SuppressWarnings("unchecked") - @Override - protected Void doInBackground(Void... voids) { - Map data = (Map) arguments.get("data"); - try { - transaction.update(getDocumentReference(arguments), data); - handler.post( - new Runnable() { - @Override - public void run() { - result.success(null); - } - }); - } catch (final IllegalStateException e) { - handler.post( - new Runnable() { - @Override - public void run() { - result.error("Error performing Transaction#update", e.getMessage(), null); - } - }); - } - return null; - } - }.execute(); + + Map data = call.argument("data"); + try { + transaction.update(getDocumentReference(arguments), data); + handler.post( + new Runnable() { + @Override + public void run() { + result.success(null); + } + }); + } catch (final IllegalStateException e) { + handler.post( + new Runnable() { + @Override + public void run() { + result.error("Error performing Transaction#update", e.getMessage(), null); + } + }); + } break; } case "Transaction#set": { final Map arguments = call.arguments(); final Transaction transaction = getTransaction(arguments); - new AsyncTask() { - @SuppressWarnings("unchecked") - @Override - protected Void doInBackground(Void... voids) { - Map data = (Map) arguments.get("data"); - transaction.set(getDocumentReference(arguments), data); - handler.post( - new Runnable() { - @Override - public void run() { - result.success(null); - } - }); - return null; - } - }.execute(); + + Map data = call.argument("data"); + transaction.set(getDocumentReference(arguments), data); + handler.post( + new Runnable() { + @Override + public void run() { + result.success(null); + } + }); break; } case "Transaction#delete": { final Map arguments = call.arguments(); final Transaction transaction = getTransaction(arguments); - new AsyncTask() { - @Override - protected Void doInBackground(Void... voids) { - transaction.delete(getDocumentReference(arguments)); - handler.post( - new Runnable() { - @Override - public void run() { - result.success(null); - } - }); - return null; - } - }.execute(); + + transaction.delete(getDocumentReference(arguments)); + handler.post( + new Runnable() { + @Override + public void run() { + result.success(null); + } + }); + break; } case "WriteBatch#create": @@ -572,10 +556,9 @@ public void run() { case "WriteBatch#setData": { Map arguments = call.arguments(); - int handle = (Integer) arguments.get("handle"); + Integer handle = call.argument("handle"); DocumentReference reference = getDocumentReference(arguments); - @SuppressWarnings("unchecked") - Map options = (Map) arguments.get("options"); + Map options = call.argument("options"); WriteBatch batch = batches.get(handle); if (options != null && (boolean) options.get("merge")) { batch.set(reference, arguments.get("data"), SetOptions.merge()); @@ -588,10 +571,9 @@ public void run() { case "WriteBatch#updateData": { Map arguments = call.arguments(); - int handle = (Integer) arguments.get("handle"); + Integer handle = call.argument("handle"); DocumentReference reference = getDocumentReference(arguments); - @SuppressWarnings("unchecked") - Map data = (Map) arguments.get("data"); + Map data = call.argument("data"); WriteBatch batch = batches.get(handle); batch.update(reference, data); result.success(null); @@ -600,7 +582,7 @@ public void run() { case "WriteBatch#delete": { Map arguments = call.arguments(); - int handle = (Integer) arguments.get("handle"); + Integer handle = call.argument("handle"); DocumentReference reference = getDocumentReference(arguments); WriteBatch batch = batches.get(handle); batch.delete(reference); @@ -609,8 +591,7 @@ public void run() { } case "WriteBatch#commit": { - Map arguments = call.arguments(); - int handle = (Integer) arguments.get("handle"); + Integer handle = call.argument("handle"); WriteBatch batch = batches.get(handle); Task task = batch.commit(); batches.delete(handle); @@ -650,8 +631,7 @@ public void run() { } case "removeListener": { - Map arguments = call.arguments(); - int handle = (Integer) arguments.get("handle"); + Integer handle = call.argument("handle"); listenerRegistrations.get(handle).remove(); listenerRegistrations.remove(handle); observers.remove(handle); @@ -684,10 +664,8 @@ public void onFailure(@NonNull Exception e) { { Map arguments = call.arguments(); DocumentReference documentReference = getDocumentReference(arguments); - @SuppressWarnings("unchecked") - Map options = (Map) arguments.get("options"); - @SuppressWarnings("unchecked") - Map data = (Map) arguments.get("data"); + Map options = call.argument("options"); + Map data = call.argument("data"); Task task; if (options != null && (boolean) options.get("merge")) { task = documentReference.set(data, SetOptions.merge()); @@ -701,8 +679,7 @@ public void onFailure(@NonNull Exception e) { { Map arguments = call.arguments(); DocumentReference documentReference = getDocumentReference(arguments); - @SuppressWarnings("unchecked") - Map data = (Map) arguments.get("data"); + Map data = call.argument("data"); Task task = documentReference.update(data); addDefaultListeners("updateData", task, result); break; @@ -751,42 +728,43 @@ public void onFailure(@NonNull Exception e) { } case "Firestore#enablePersistence": { - Map arguments = call.arguments(); - boolean enable = (boolean) arguments.get("enable"); + Boolean enable = call.argument("enable"); FirebaseFirestoreSettings.Builder builder = new FirebaseFirestoreSettings.Builder(); builder.setPersistenceEnabled(enable); FirebaseFirestoreSettings settings = builder.build(); + Map arguments = call.arguments(); getFirestore(arguments).setFirestoreSettings(settings); result.success(null); break; } case "Firestore#settings": { - final Map arguments = call.arguments(); final FirebaseFirestoreSettings.Builder builder = new FirebaseFirestoreSettings.Builder(); - if (arguments.get("persistenceEnabled") != null) { - builder.setPersistenceEnabled((boolean) arguments.get("persistenceEnabled")); + Boolean persistenceEnabled = call.argument("persistenceEnabled"); + if (persistenceEnabled != null) { + builder.setPersistenceEnabled(persistenceEnabled); } - - if (arguments.get("host") != null) { - builder.setHost((String) arguments.get("host")); + final String host = call.argument("host"); + if (host != null) { + builder.setHost(host); } - - if (arguments.get("sslEnabled") != null) { - builder.setSslEnabled((boolean) arguments.get("sslEnabled")); + final Boolean sslEnabled = call.argument("sslEnabled"); + if (sslEnabled != null) { + builder.setSslEnabled(sslEnabled); } - - if (arguments.get("timestampsInSnapshotsEnabled") != null) { - builder.setTimestampsInSnapshotsEnabled( - (boolean) arguments.get("timestampsInSnapshotsEnabled")); + final Boolean timestampsInSnapshotsEnabled = + call.argument("timestampsInSnapshotsEnabled"); + if (timestampsInSnapshotsEnabled != null) { + builder.setTimestampsInSnapshotsEnabled(timestampsInSnapshotsEnabled); } - - if (arguments.get("cacheSizeBytes") != null) { - builder.setCacheSizeBytes(((Integer) arguments.get("cacheSizeBytes")).longValue()); + final Integer cacheSizeBytes = call.argument("cacheSizeBytes"); + if (cacheSizeBytes != null) { + builder.setCacheSizeBytes(cacheSizeBytes.longValue()); } FirebaseFirestoreSettings settings = builder.build(); + final Map arguments = call.arguments(); getFirestore(arguments).setFirestoreSettings(settings); result.success(null); break; diff --git a/packages/cloud_firestore/example/lib/main.dart b/packages/cloud_firestore/example/lib/main.dart index 30c1e2ce3036..05ee916c281c 100755 --- a/packages/cloud_firestore/example/lib/main.dart +++ b/packages/cloud_firestore/example/lib/main.dart @@ -63,9 +63,11 @@ class MyHomePage extends StatelessWidget { CollectionReference get messages => firestore.collection('messages'); Future _addMessage() async { - await messages.add({ - 'message': 'Hello world!', - 'created_at': FieldValue.serverTimestamp(), + firestore.runTransaction((Transaction tx) async { + await tx.set(messages.document(), { + 'message': 'Hello world!', + 'created_at': FieldValue.serverTimestamp(), + }); }); } From 45145b7c05b32339510dcc54255af117e7a12e82 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=BAlio=20Cotta?= Date: Sun, 25 Aug 2019 22:36:40 -0300 Subject: [PATCH 3/9] Updated CHANGELOG.md and pubspec.yaml --- packages/cloud_firestore/CHANGELOG.md | 4 ++++ packages/cloud_firestore/pubspec.yaml | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/cloud_firestore/CHANGELOG.md b/packages/cloud_firestore/CHANGELOG.md index 2dee1a9bb4ff..2e4fef0fcb33 100644 --- a/packages/cloud_firestore/CHANGELOG.md +++ b/packages/cloud_firestore/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.12.9+2 + +* Removed Activity reference to avoid possible NullPointerException. + ## 0.12.9+1 * Update documentation to reflect new repository location. diff --git a/packages/cloud_firestore/pubspec.yaml b/packages/cloud_firestore/pubspec.yaml index 69d41a2dea6d..b3a2adc19547 100755 --- a/packages/cloud_firestore/pubspec.yaml +++ b/packages/cloud_firestore/pubspec.yaml @@ -3,7 +3,7 @@ description: Flutter plugin for Cloud Firestore, a cloud-hosted, noSQL database live synchronization and offline support on Android and iOS. author: Flutter Team homepage: https://github.com/FirebaseExtended/flutterfire/tree/master/packages/cloud_firestore -version: 0.12.9+1 +version: 0.12.9+2 flutter: plugin: From a8ef374ff7c2d3a09c22cc0d17919ad6599b84cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=BAlio=20Cotta?= Date: Thu, 29 Aug 2019 20:04:05 -0300 Subject: [PATCH 4/9] fixed example initialization --- .../cloud_firestore/example/lib/main.dart | 51 +++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/packages/cloud_firestore/example/lib/main.dart b/packages/cloud_firestore/example/lib/main.dart index 05ee916c281c..eb00cbb36f28 100755 --- a/packages/cloud_firestore/example/lib/main.dart +++ b/packages/cloud_firestore/example/lib/main.dart @@ -9,6 +9,7 @@ import 'package:firebase_core/firebase_core.dart'; import 'package:cloud_firestore/cloud_firestore.dart'; Future main() async { + WidgetsFlutterBinding.ensureInitialized(); final FirebaseApp app = await FirebaseApp.configure( name: 'test', options: const FirebaseOptions( @@ -30,6 +31,29 @@ class MessageList extends StatelessWidget { final Firestore firestore; + CollectionReference get messages => firestore.collection('messages'); + + Future _updateMessage(DocumentSnapshot document) async { + firestore.runTransaction((Transaction tx) async { + await tx.update(document.reference, { + 'message': 'Message updated at' + DateTime.now().toIso8601String(), + 'created_at': FieldValue.serverTimestamp(), + }); + }); + } + Future _transactionWithMultipleOperations(DocumentSnapshot document) async { + firestore.runTransaction((Transaction tx) async { + // these operations make no particular sense. + // They are here just to test this case in the plugin. + await tx.update(document.reference, { + 'message': 'Message updated at' + DateTime.now().toIso8601String(), + 'created_at': FieldValue.serverTimestamp(), + }); + await tx.get(document.reference); + await tx.delete(document.reference); + }); + } + @override Widget build(BuildContext context) { return StreamBuilder( @@ -43,6 +67,33 @@ class MessageList extends StatelessWidget { final DocumentSnapshot document = snapshot.data.documents[index]; final dynamic message = document['message']; return ListTile( + trailing: PopupMenuButton( + itemBuilder: (_) { + return >[ + PopupMenuItem( + value: 'UPDATE', + child: const Text('Update with local timestamp'), + ), + PopupMenuItem( + value: 'DELETE', + child: const Text('Delete'), + ), + PopupMenuItem( + value: 'BATCH', + child: const Text('Get, update and delete in a single transaction'), + ), + ]; + }, + onSelected: (String entry) async { + if (entry == 'UPDATE') { + await _updateMessage(document); + } else if (entry == 'DELETE') { + await messages.document(document.documentID).delete(); + } else if (entry == 'BATCH') { + _transactionWithMultipleOperations(document); + } + }, + ), title: Text( message != null ? message.toString() : '', ), From fdc6131f83ea390d0bd0c0a879f9a852ab5402d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=BAlio=20Cotta?= Date: Thu, 29 Aug 2019 20:05:04 -0300 Subject: [PATCH 5/9] fixed Integer to Long conversion crash. --- .../firebase/cloudfirestore/CloudFirestorePlugin.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/cloud_firestore/android/src/main/java/io/flutter/plugins/firebase/cloudfirestore/CloudFirestorePlugin.java b/packages/cloud_firestore/android/src/main/java/io/flutter/plugins/firebase/cloudfirestore/CloudFirestorePlugin.java index 28548d3fc6ff..2694c8a08a3c 100644 --- a/packages/cloud_firestore/android/src/main/java/io/flutter/plugins/firebase/cloudfirestore/CloudFirestorePlugin.java +++ b/packages/cloud_firestore/android/src/main/java/io/flutter/plugins/firebase/cloudfirestore/CloudFirestorePlugin.java @@ -422,8 +422,9 @@ public void notImplemented() { // Wait till transaction is complete. try { - String timeoutKey = "transactionTimeout"; - Long timeout = call.argument(timeoutKey); + final String timeoutKey = "transactionTimeout"; + final Integer timeout = call.argument(timeoutKey); + final Map transactionResult = Tasks.await(transactionTCSTask, timeout, TimeUnit.MILLISECONDS); From ce771fa5fb1f493aa121ecded67d0ab9ca1b4753 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=BAlio=20Cotta?= Date: Thu, 29 Aug 2019 20:09:12 -0300 Subject: [PATCH 6/9] reverted removal of AsyncTasks. --- .../cloudfirestore/CloudFirestorePlugin.java | 36 +++++++++++++++---- 1 file changed, 29 insertions(+), 7 deletions(-) diff --git a/packages/cloud_firestore/android/src/main/java/io/flutter/plugins/firebase/cloudfirestore/CloudFirestorePlugin.java b/packages/cloud_firestore/android/src/main/java/io/flutter/plugins/firebase/cloudfirestore/CloudFirestorePlugin.java index 2694c8a08a3c..750b304ac2cd 100644 --- a/packages/cloud_firestore/android/src/main/java/io/flutter/plugins/firebase/cloudfirestore/CloudFirestorePlugin.java +++ b/packages/cloud_firestore/android/src/main/java/io/flutter/plugins/firebase/cloudfirestore/CloudFirestorePlugin.java @@ -4,6 +4,7 @@ package io.flutter.plugins.firebase.cloudfirestore; +import android.os.AsyncTask; import android.os.Handler; import android.util.Log; import android.util.SparseArray; @@ -455,7 +456,9 @@ public void onComplete(@NonNull Task> task) { { final Map arguments = call.arguments(); final Transaction transaction = getTransaction(arguments); - + new AsyncTask() { + @Override + protected Void doInBackground(Void... voids) { try { DocumentSnapshot documentSnapshot = transaction.get(getDocumentReference(arguments)); final Map snapshotMap = new HashMap<>(); @@ -485,14 +488,20 @@ public void run() { } }); } + return null; + } + }.execute(); break; } case "Transaction#update": { final Map arguments = call.arguments(); final Transaction transaction = getTransaction(arguments); - - Map data = call.argument("data"); + new AsyncTask() { + @SuppressWarnings("unchecked") + @Override + protected Void doInBackground(Void... voids) { + Map data = (Map) arguments.get("data"); try { transaction.update(getDocumentReference(arguments), data); handler.post( @@ -511,14 +520,20 @@ public void run() { } }); } + return null; + } + }.execute(); break; } case "Transaction#set": { final Map arguments = call.arguments(); final Transaction transaction = getTransaction(arguments); - - Map data = call.argument("data"); + new AsyncTask() { + @SuppressWarnings("unchecked") + @Override + protected Void doInBackground(Void... voids) { + Map data = (Map) arguments.get("data"); transaction.set(getDocumentReference(arguments), data); handler.post( new Runnable() { @@ -527,13 +542,18 @@ public void run() { result.success(null); } }); + return null; + } + }.execute(); break; } case "Transaction#delete": { final Map arguments = call.arguments(); final Transaction transaction = getTransaction(arguments); - + new AsyncTask() { + @Override + protected Void doInBackground(Void... voids) { transaction.delete(getDocumentReference(arguments)); handler.post( new Runnable() { @@ -542,7 +562,9 @@ public void run() { result.success(null); } }); - + return null; + } + }.execute(); break; } case "WriteBatch#create": From c5e31f6560088b0f79595c59d1d8af6192ff8a35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=BAlio=20Cotta?= Date: Thu, 29 Aug 2019 20:14:41 -0300 Subject: [PATCH 7/9] fixes possible errors while communicating with dart. --- .../cloudfirestore/CloudFirestorePlugin.java | 159 ++++++++++-------- 1 file changed, 87 insertions(+), 72 deletions(-) diff --git a/packages/cloud_firestore/android/src/main/java/io/flutter/plugins/firebase/cloudfirestore/CloudFirestorePlugin.java b/packages/cloud_firestore/android/src/main/java/io/flutter/plugins/firebase/cloudfirestore/CloudFirestorePlugin.java index 750b304ac2cd..f121667eb224 100644 --- a/packages/cloud_firestore/android/src/main/java/io/flutter/plugins/firebase/cloudfirestore/CloudFirestorePlugin.java +++ b/packages/cloud_firestore/android/src/main/java/io/flutter/plugins/firebase/cloudfirestore/CloudFirestorePlugin.java @@ -431,9 +431,15 @@ public void notImplemented() { // Once transaction completes return the result to the Dart side. return transactionResult; - } catch (Exception e) { + } catch (final Exception e) { Log.e(TAG, e.getMessage(), e); - result.error("Error performing transaction", e.getMessage(), null); + handler.post( + new Runnable() { + @Override + public void run() { + result.error("Error performing transaction", e.getMessage(), null); + } + }); } return null; } @@ -441,13 +447,21 @@ public void notImplemented() { .addOnCompleteListener( new OnCompleteListener>() { @Override - public void onComplete(@NonNull Task> task) { - if (task.isSuccessful()) { - result.success(task.getResult()); - } else { - result.error( - "Error performing transaction", task.getException().getMessage(), null); - } + public void onComplete(@NonNull final Task> task) { + handler.post( + new Runnable() { + @Override + public void run() { + if (task.isSuccessful()) { + result.success(task.getResult()); + } else { + result.error( + "Error performing transaction", + task.getException().getMessage(), + null); + } + } + }); } }); break; @@ -459,35 +473,36 @@ public void onComplete(@NonNull Task> task) { new AsyncTask() { @Override protected Void doInBackground(Void... voids) { - try { - DocumentSnapshot documentSnapshot = transaction.get(getDocumentReference(arguments)); - final Map snapshotMap = new HashMap<>(); - snapshotMap.put("path", documentSnapshot.getReference().getPath()); - if (documentSnapshot.exists()) { - snapshotMap.put("data", documentSnapshot.getData()); - } else { - snapshotMap.put("data", null); - } - Map metadata = new HashMap<>(); - metadata.put("hasPendingWrites", documentSnapshot.getMetadata().hasPendingWrites()); - metadata.put("isFromCache", documentSnapshot.getMetadata().isFromCache()); - snapshotMap.put("metadata", metadata); - handler.post( - new Runnable() { - @Override - public void run() { - result.success(snapshotMap); - } - }); - } catch (final FirebaseFirestoreException e) { - handler.post( - new Runnable() { - @Override - public void run() { - result.error("Error performing Transaction#get", e.getMessage(), null); - } - }); - } + try { + DocumentSnapshot documentSnapshot = + transaction.get(getDocumentReference(arguments)); + final Map snapshotMap = new HashMap<>(); + snapshotMap.put("path", documentSnapshot.getReference().getPath()); + if (documentSnapshot.exists()) { + snapshotMap.put("data", documentSnapshot.getData()); + } else { + snapshotMap.put("data", null); + } + Map metadata = new HashMap<>(); + metadata.put("hasPendingWrites", documentSnapshot.getMetadata().hasPendingWrites()); + metadata.put("isFromCache", documentSnapshot.getMetadata().isFromCache()); + snapshotMap.put("metadata", metadata); + handler.post( + new Runnable() { + @Override + public void run() { + result.success(snapshotMap); + } + }); + } catch (final FirebaseFirestoreException e) { + handler.post( + new Runnable() { + @Override + public void run() { + result.error("Error performing Transaction#get", e.getMessage(), null); + } + }); + } return null; } }.execute(); @@ -502,24 +517,24 @@ public void run() { @Override protected Void doInBackground(Void... voids) { Map data = (Map) arguments.get("data"); - try { - transaction.update(getDocumentReference(arguments), data); - handler.post( - new Runnable() { - @Override - public void run() { - result.success(null); - } - }); - } catch (final IllegalStateException e) { - handler.post( - new Runnable() { - @Override - public void run() { - result.error("Error performing Transaction#update", e.getMessage(), null); - } - }); - } + try { + transaction.update(getDocumentReference(arguments), data); + handler.post( + new Runnable() { + @Override + public void run() { + result.success(null); + } + }); + } catch (final IllegalStateException e) { + handler.post( + new Runnable() { + @Override + public void run() { + result.error("Error performing Transaction#update", e.getMessage(), null); + } + }); + } return null; } }.execute(); @@ -534,14 +549,14 @@ public void run() { @Override protected Void doInBackground(Void... voids) { Map data = (Map) arguments.get("data"); - transaction.set(getDocumentReference(arguments), data); - handler.post( - new Runnable() { - @Override - public void run() { - result.success(null); - } - }); + transaction.set(getDocumentReference(arguments), data); + handler.post( + new Runnable() { + @Override + public void run() { + result.success(null); + } + }); return null; } }.execute(); @@ -554,14 +569,14 @@ public void run() { new AsyncTask() { @Override protected Void doInBackground(Void... voids) { - transaction.delete(getDocumentReference(arguments)); - handler.post( - new Runnable() { - @Override - public void run() { - result.success(null); - } - }); + transaction.delete(getDocumentReference(arguments)); + handler.post( + new Runnable() { + @Override + public void run() { + result.success(null); + } + }); return null; } }.execute(); From 943d59e69a1d9de3a31fe67e14c3b625f623d706 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=BAlio=20Cotta?= Date: Thu, 29 Aug 2019 20:16:11 -0300 Subject: [PATCH 8/9] format example --- packages/cloud_firestore/example/lib/main.dart | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/packages/cloud_firestore/example/lib/main.dart b/packages/cloud_firestore/example/lib/main.dart index eb00cbb36f28..7ae12093157a 100755 --- a/packages/cloud_firestore/example/lib/main.dart +++ b/packages/cloud_firestore/example/lib/main.dart @@ -41,9 +41,11 @@ class MessageList extends StatelessWidget { }); }); } - Future _transactionWithMultipleOperations(DocumentSnapshot document) async { + + Future _transactionWithMultipleOperations( + DocumentSnapshot document) async { firestore.runTransaction((Transaction tx) async { - // these operations make no particular sense. + // these operations make no particular sense. // They are here just to test this case in the plugin. await tx.update(document.reference, { 'message': 'Message updated at' + DateTime.now().toIso8601String(), @@ -80,7 +82,8 @@ class MessageList extends StatelessWidget { ), PopupMenuItem( value: 'BATCH', - child: const Text('Get, update and delete in a single transaction'), + child: const Text( + 'Get, update and delete in a single transaction'), ), ]; }, From 2c366e506c0de3883ffd8a974a13cbdd92f9245f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=BAlio=20Cotta?= Date: Fri, 20 Sep 2019 09:37:37 -0300 Subject: [PATCH 9/9] remove const call to constructor. --- packages/cloud_firestore/example/lib/main.dart | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/cloud_firestore/example/lib/main.dart b/packages/cloud_firestore/example/lib/main.dart index 7ae12093157a..dfc7946c7146 100755 --- a/packages/cloud_firestore/example/lib/main.dart +++ b/packages/cloud_firestore/example/lib/main.dart @@ -74,15 +74,15 @@ class MessageList extends StatelessWidget { return >[ PopupMenuItem( value: 'UPDATE', - child: const Text('Update with local timestamp'), + child: Text('Update with local timestamp'), ), PopupMenuItem( value: 'DELETE', - child: const Text('Delete'), + child: Text('Delete'), ), PopupMenuItem( value: 'BATCH', - child: const Text( + child: Text( 'Get, update and delete in a single transaction'), ), ];