Now I read the Firebase documentation for android. I saw all the events onDataChange etc. But I didn't get 1 thing. Let's say I want to initialize my activity with some information from the database. No data has changed, no nothing. So it seems this event onDataChange won't help me. How can I explicitly say something like "go and fetch the data from firebase".
When you attach a ValueEventListener, its onDataChange method is called "immediately" with a snapshot of the current data.
If you attach the listener with addValueEventListener it will (in addition) be called upon any subsequent change to the data.
You could create a method that when the activity is initialized, so is a data structure with info from the database.
Retrieving data is pretty explicit here: https://firebase.google.com/docs/database/admin/retrieve-data
Also, you should be really careful because you should be using callbacks. If the activity needs to populate its views depending on that data, you should be aware of having that data before creating the views or trying to instantiate with null objects.
You can read the data only once, see:
https://firebase.google.com/docs/database/android/read-and-write#read_data_once
You "use the addListenerForSingleValueEvent() method to simplify this scenario: it triggers once and then does not trigger again."
Related
I have a question that is more related to proper design and architecture of MVVM than to coding itself. In my project I have a situation that on ViewModel is suplying data, that are later used in RecyclerView.Adapter to create a proper view.
However I wonder if this would be also correct (from proper 'way of doing things' POV) if some of the data would be supplied in form of id's to be further fetched from Room or external server? For instance during onBindViewHolder use some LiveData with observe() to update certain fields on succesfull load.
Doing data fetch in the views is a no-go. It defeats the very purpose of MVVM and in particular the Android Jetpack efforts. One of the big reason is the data needs to survive configurations. Putting "data fetching" mechanism in the view defeats that as the view can be destroyed and recreated anytime when need be.
So I would suggest you make sure all calls to the network or any other source of data for that matter revolve around the ViewModel and never a view. Let the VM feed the data to the View through observer.
Exception to what I have just said is such use case as loading images with Picasso or Glide where by you feed them URL and they load image. But that's a different thing as they are designed to handle that.
UPDATE with followup Questions
it's ok to put observe() still inside Adapter, during the binding process?
No! Data sent to the adapter must be complete in the purpose it is supposed to serve. For example, if you have to do list app and your Top-Level Activity displays all Todos, then you must feed adapter will complete data (Title, Created time, et al).
The data that are not going to be displayed (like descriptions or sub-to-do-lists) and aren't necessary to identify specific to do should not be fetched (unless you want to store them for sole purpose of avoiding a second network call and pass them to the next activity as serialized data).
When user clicks specific To-Do, then launch new activity with its own ViewModel that will fetch details for that activity (assuming you passed some ID with intent).
If the first, then I understand that observe() should not only update data, but also populate it later to Observer and call notifyDataSetChanged(), right?
Observe is a way to post data to the view when either it have changed or the old view was destroyed and so the new view is being given the same old data that survived the "view death". So it is in the same method where updating data of the Adapter should be done and hence call to notifyDataSetChanged() or similar methods.
I hope that makes it clear.
I think it's best to keep the ViewModel separate from the Adapter. From what I'm gathering you want to basically have each list item load it's own data from Room by having each list item observe on a particular ID for that item. This sounds rather inefficient as you're basically having each item execute a query on the database (or network call) to retrieve just one item for all items that are going to be displayed, think about how it will scale if you were displaying a 100 items. I think it's best that you just execute one query to get the list of data and set the data to the list items in the adapter, keep it simple. Note that onBindViewHolder() doesn't just get called once but multiple times when you're scrolling the screen, so it could get quite ugly if you're trying to lazily load every list item.
I want to refresh my HomeScreenActivity so you can see your balance when you have paid (it works with NFC/HCE).
When you scanned your phone you go back to the HomeScreenActivity. The problem is that when you go back, your balance button is not updated so you have your old balance. You get your new balance when you go back to the login activity and then login again.
I tried a lot to fix this but nothing seems to work. Maybe the problem is that the communication with your balance goes from a database/API.
I hope someone can explain me or fix the problem!!
P.S. I do not have a adapter for balance!
Please use onActivityResult method for the actvity where you want to refresh the amount. And in onActivityResult method reset the adapter and call notifyDataSetChanged().
You have many way to do this. You can research about onActivity result, it will help you solve this problem. EventBus, observer is the same solution.
You have a lot of ways to make your data always up-to-date:
I will list some of them:
Use Realm for your local DataBase. It have own classes extending recyclerviewAdapter and other to notify you when data in tables was changed.
Use new Android Room library it also can do the same thing using LiveData
Use RxJava to subscribe to some changes in you app. When changes will happen Rx will emit new item to all subscribers.
User Observer OOP pattern
NotifyDataSetChanged doing the same thing. When you expect your container data to be changed you call this method and RecyclerView.Adapter will rebind all existed ViewHolders to new data.
These are not all possible variants to organize notifications. You can also use EventBus or kind of timer to refresh data with specified delay(this isn't the best one).
I am new to android development and I want to perform a network call of calling firebase database to fill array list with records. I want to create different fragment based on the object properties present in arraylist. Network calls take too much time, so what is the proper way to perform such task.
Here is the steps you should do:
In first time:
In your Activity just run a background service that will fetch the list of Objects. After fetching list you store the list item's in local storage like shared preferences or database. After saving data you open your fragment.
After First Time:
Check is there you have saved list item? if list contains data then directly open your desired fragment. At the same time you update the list items using service call.
Here is some related links:
https://www.tutorialspoint.com/android/android_services.htm
https://www.tutorialspoint.com/android/android_shared_preferences.htm
Hope this will help you.
We are using Retrofit and Activeandroid for my project.
Currently we are facing an issue.
The pattern which we follow in our project is, We get data from server and save it into local database and after data saved we call routine which fetches data from database and populate UI this all happens in single Activity..
Now we have an activity which makes 3 server request, and due to which the amount of code in activity increased.
We are trying to reduce Activity code by creating fragment for the activity and giving responsibility of fetching data and displaying data to Fragment. Rest call will be made by activity. Now once the data is loaded from all the 3 request we need to inform fragment about data is loaded, what is the best way for this.
And is it even possible to send data to fragment once it is loaded.. or the approach we are following is not correct..
Please guide us on this..
Edit1
I read about EventBus. Can event bus solve this problem or it will effect the efficiency.
If you are storing those Fragment instances in your Activity then it will be much easier.
1) Create loadNewdata(DataType data) method in your Fragment.
2) Pass the data into the Fragment after getting response from server in your Activity
((YourFragment)fragment).loadNewdata(yourData);
I would suggest to use Otto.
By this you do not need to store your data in local db(if you don't want it).Just simply post your responce whenever you received from rest API. As Otto also provides the functionality of sharing custom objects between fragments/Activity. It also helps you to make your code modular.
You will find a working example here & here.
You can use Interfaces for this and send data to activity.when response come back pass reference of to show which fragment data needs to be populate the UI.
I have a List of items that I want in a ListView, and I can make it work with setting a custom adapter every time the List grows, but the program flow is kind of weird and I have problems with persistence. (If I switch tabs, the UI gets rebuilt with an empty ListView.)
Now, in my day job I'm a C# developer, so when I look at this problem I see a WPF ListView bound to an ObservableCollection. Does Android/Java have something like that, a "fire and forget" connection between a UI element and a data structure?
You don't need to replace the adapter every time you change the data. The adapter "adapts" between data and view. There is no need to change the adapter as long as the way it adapts does not change.
Activity / Fragment lifecycle is not necessarily the lifecycle of your data collection. You can for example make a singleton data collection somewhere and use an adapter to display that collection all the time. Call .notifyDataSetChanged() on the adapter if you changed the data.
A persistent data collection in Android is probably best backed by a database. Take a look at LoaderManager & ContentProvider to provide and load data then displayed via CursorAdapter.
There is no automatic way of keeping a bunch of data available outside of your Activity / Fragment / .. lifecycle and it can get quite complicated but that's basically what you have to do if you want to keep data for longer than a given lifecycle. Singletons, Activity#onSaveInstanceState(), Activity#getLastNonConfigurationInstance(), Fragment#setRetainInstance(), ... are useful utilities to keep data in memory, databases are good for persistent data.
You have to do a little bit work yourself but it's possible. Use a ContentProvider as your DataSource. How the data is stored is up to you. I would prefer a SQLite-DB. A content provider has the possibility to add ContentObservers. (See this related question.)
You can write a CourserAdapter to fetch the Data from your content provider. And your ContentObserver should call notifyDataSetChanged() on your adapter. This closes the circle and your UI refreshes itself.
In Addition to zapls answer:
You can also write an adapter which contains a BroadcastReceiver. When your DataSource changes you can send a LocalBroadcast. The broadcast handler just calls notifyDataSetChanged() of your adapter. I think this would work around most of the lifecycle problems because only active elements will get the broadcast.
The google documentation has an example for such a solution.