1

I'm currently switching the way data are stored into my app from sqlite to Firestore for the sake of online support. Even if this is a big leap and will mean a lot of changes into my current architecture. I wanted to know if there is a way to sort of emulate an Adapter class (like the one used for SQlite), so I can keep those changes to bear the minimum by at least resuing my methods names and return types and avoid to write explicitly each document read/write where I need them.

What I tried at first in my so called "Adapter like class" was to load the document's data inside a dedicated object in my "adapter class"'s constructor. But it obviously didn't work because Firebase queries are async like explained here:

Is there a way to write this database call into a function easily?

Is what I want to do possible ? Or am I doomed to redo everything ?

1 Answers1

1

Short answer: yes, but you shouldn't

If you absolutely must:

You can wrap the async calls in the Firebase API by using CountDownLatch to create your own Future implementation. Future is a Java Interface similar to Promises in JavaScript, which allow you to pass around the "future result" of an async computation until you absolutely need it.

Check this StackOverflow answer for a sample implementation.

You would then implement your "Adapter-like class" with this wrapper, which would return a Future, and the methods in your class would return future.get(). This call blocks the thread which executes it and when the Future resolves, the call evaluates to the value contained in the Future ("unwrapping" it).

Here's why you shouldn't:

  • In Android, it's usually a Very Bad Idea to block the UI thread, so if your current Adapter is already a synchronous call, it will keep blocking until the Firebase query finishes.
  • If you are already blocking the UI thread with your SQLite queries, and think you might be fine because of that, consider the possibility that this is not a problem now just because the SQLite queries are too fast for it to matter. When you switch to Firestore, the queries are likely to take much longer on average and have way more variance in their response time due to different network conditions, etc.
  • If it's not very unfeasible to consider refactoring to use the async APIs, seriously consider it. Your queries are going to take longer now and you might need "loading" indicators anyway, so using the async APIs will help with that. You may also see opportunities to run queries in parallel when you need both but they don't depend on each other, and keeping it async allows you to do that.
    • This might not have mattered before if the queries were fast enough that sequential vs. parallel didn't matter much, but now it may.
Rafael Almeida
  • 10,352
  • 6
  • 45
  • 60
  • Thanks for your answer, indeed I'm blocking the UI Thread with SQLite and networking is something I should now think about. I now consider putting different SnapshotListeners (I currently just need to fetch documents with no explicit queries) in a Thread or a Service. Is this a good solution ? – CromSoldier Jun 24 '20 at 09:09
  • That's usually not necessary, as the APIs are asynchronous - you can create the listener in the UI Thread and it won't block, just call the callbacks when there's new data or other relevant events. That's the main benefit of an asynchronous API - it doesn't block while waiting, even with a single thread. – Rafael Almeida Jun 24 '20 at 13:57
  • Also, @CromSoldier, if this or any answer has solved your question please consider [accepting it](https://meta.stackexchange.com/q/5234/179419) by clicking the check-mark. There is no obligation to do this, but it indicates to the wider community that you've found a solution and gives some [reputation](https://meta.stackexchange.com/questions/7237/how-does-reputation-work) to both the answerer and yourself :). – Rafael Almeida Jun 24 '20 at 14:14
  • 1
    Ok then I'll use the async APIs in my code, maybe I wanted to be "too lazy". Thank you for your help. – CromSoldier Jun 24 '20 at 14:19
  • I just want to clarify that SnapshotListener _is_ part of the "async API", so if you're going to use it, using it in another thread is extra work which doesn't usually bring further benefit to just using it in the first place. – Rafael Almeida Jun 24 '20 at 14:22
  • Ok that's what I understood from your answer to my first comment. Maybe a last question, I heard that's a good practice to implement a SnapshotListener in "onStart()" of the activity, do you confirm that ? or it's not that important as long as the listener is destroyed at the end of the life cycle ? – CromSoldier Jun 24 '20 at 14:35
  • Yes, [that's a common approach](https://firebase.googleblog.com/2017/12/using-android-architecture-components.html). It's not so much as destroying the listener along with the activity as much as not wasting resources while the activity is not visible (so, stop on `onStop` and start again on `onStart), so that the OS doesn't shut off your networking. If you'd need to keep listening even with the user outside the app, you could put the listener into a Service, and then this matters less. – Rafael Almeida Jun 25 '20 at 12:20