Working with 'Associated' data in Firebase - android

I'm relatively new to Firebase Database, having used MySQL up until now. I know that there's no 'associated' data in Firebase as such, but I think I'm still trying to create it, because that's how my mind works! So, it may be that the problem I'm having is because my data is formatted badly - I'd appreciate any pointers.
In my app (using Android Studio), each user can have a number of Boxes. Each Box uses a single colour Palette (it can be the default one, or a user-defined one). A Palette consists of a number of Colours.
Currently, my data is like this:
Boxes
BoxKey1
name: Test Box
paletteKey: paletteKey1
belongsTo: userKey1
BoxKey2
... etc ...
Colours
ColourKey1
name: Red
hexCode: ff0000
ColourKey2
name: Blue
... etc ...
Palettes
PaletteKey1
name: default
colours
ColourKey1: true
ColourKey7: true
... etc ...
PaletteKey2
... etc ...
Users
UserKey1
name: Joe Bloggs
boxes
BoxKey1: true
BoxKey5: true
... etc ...
So, I can retrieve a list of the User's Boxes easily enough, and list all the names. If the User clicks on a name, then the Box with that name is retrieved and displayed. I also need to display the Palette used (the name and the Colours it contains).
In the Activity, I retrieve the Box as follows:
mBox.setKey(boxKey);
mBox.initialiseBox(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
mBox = dataSnapshot.getValue(Box.class);
boxName.setText(mBox.getName()); // Show Box name
// AT THIS POINT I HAVE THE BOX DETAILS, BUT I NEED THE PALETTE DETAILS TOO
}
});
In the Box class, initialiseBox looks like this:
public void initialiseBox(ValueEventListener listener) {
if(this.key == null) return;
DatabaseReference mBoxReference = FirebaseDatabase.getInstance().getReference()
.child("boxes").child(this.key);
mBoxReference.addListenerForSingleValueEvent(listener);
}
That's working fine, but at this point I've only retrieved the Palette key from the database along with the other Box data. How do I then get the actual Palette, with all its Colours, so I can show those as well?
I've been trying to do a kind of 'nested listener' like this in the Main Activity:
mBox.initialiseBox(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
// Same as before
mBox = dataSnapshot.getValue(Box.class);
boxName.setText(mBox.getName()); // Show Box name
// Now add a new listener for the Palette
mPalette.setKey(mBox.getPaletteKey());
mPalette.initialisePalette(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
mPalette = dataSnapshot.getValue(Palette.class);
paletteName.setText(mPalette.getName());
}
});
}
});
but it seems very unwieldy, and I can't quite get it to work (the Palette isn't getting populated, so at the paletteName.setText bit I'm getting an error).
Is this the correct approach to be taking? If not, what should I be doing? And if it's the right idea, can anyone see where I'm going wrong?

Related data in Firebase (and many other NoSQL databases) are almost as common as in SQL databases. The main differences are:
In Firebase the relation is not managed for you by the DBMS. This means that you need to write your own code (and possibly server-side security rules) to ensure ensure the relationship stay in-tact.
You often will duplicate some of the data in Firebase, which reduces the need for lookups. But this comes at the cost of needing to duplicate data during a write, and you'll need to consider strategies for keeping the duplicated data up to date.
What you're doing is called a client-side join and is indeed one valid way to get data from different top-level nodes into your app.
Whether it is the best approach to do this with a nested listener depends on the data and use-case. Things to consider here:
If the target list is short, you might simply want to preload the entire list and remove the need for nested joins.
What do you need from the joined item? If it's just a single property (e.g. the name of the palette), consider if it's worth it to duplicate that property under the source to remove the need for a nested join.
Nesting the code is going to rapidly become unreadable. Pull out the listener into a utility-class, and invoke it with a simpler interface.
i.e. you'll probably want to centralize the error handling, which you can perfectly do in the helper class. This leaves you with a single callback methods, which can be lambdafied in Java 8 - making it much easier to read.
I often recommend that you model the screens of your app in Firebase. So if your app has a list of user names, model a list of user names in your database. Right now you also nest the box IDs under that list, which means you'll end up loading the box IDs for all users, just to show their names.
I highly recommend reading NoSQL data modeling and watching Firebase for SQL developers.

Related

RecyclerView getting way too complex

Context
So, I don't know if any of you has ever gone through the same situation but I've recently taken over an app and we have this RecyclerView on the main screen - because of an NDA I'll change a few things - that shows a list of apartments that you can rent - picture the AirBnB app - and if you tap on one of these apartment items you go to the apartment detail, where you have a bit more of functionality and features.
The thing is that we have way too many moving parts on the apartment list. For example, on each apartment ViewHolder you can:
Use a checkmark to specify if you are going to bring any pets with you.
A few UI items to specify how long are you going to stay.
An EditText to set how may people are going to come.
A Rent button that turns itself into a spinner and sends an API call.
A More Options button that expands the ViewHolder, showing a LinearLayout with yet more UI.
Picture something like this
This is actually a simpler example of what I really have. Let me tell you that it looks as if each ViewHolder could be a Fragment because of all the functionality that we have on each.
Now what's the problem here?
Recycling issues. If you scroll off, and scroll back to the same position you are supposed to keep the same state that you had on that ViewHolder, right? If you had checked a CheckButton that's supposed to be check. If you had written something on an EditText, that's supposed to be there. If you had expanded the More Options section, that's supposed to be expanded. You see where I'm going at?
What am I asking here?
Well, about feedback for a possible solution or improvement. I know what most of you would tell me here - because it is the same thing I thought at first - just move all that functionality into the apartment detail, keep that list as simple as possible. But it is not as simple, we have a large user base who is already used to this UI. Changing things so abruptly is not an option.
What do I have right now?
In my RecyclerView adapter I keep a collection of "State" objects which I use to save/restore the ViewHolder states, but it is getting way too big and way too complex. This may sound crazy, but it is there such thing as having a RecyclerList of Fragments? I just don't want to worry/bother about keeping the states of these ViewHolder anymore.
Notes
Sorry I haven't provided any code, but there's not much to show actually, as you may imagine the onBindViewHolder is just a humongous piece of code that sets the views with the data I fetch from the API plus the data that I store in these "State" objects. I save these "State" objects via the onViewDetachedFromWindows() hook from the adapter class that gets triggered when a ViewHolder scrolls off from screen. I wipe out these "State" objects when I fetch a new API response.
Any feedback is appreciated,
Thanks!🙇
Your post is vague in it's high-level description but I'll try to comment in a similar manner that may guide you towards solutions.
First, as was already mentioned Epoxy is a thing. As is adapter delegates. You may find those useful. However, you don't need a library to solve you problem - you need separation of concerns and architecture.
The thing is that we have way too many moving parts on the apartment list.
OK, so first suggestion is to stop having too many moving parts in the list. Each thing you listed could / should be it's own (custom) view that is driven by it's own ViewModel. A recycler view / view holder / adapter should be as stupid as possible. All those things should be doing is filling in boilerplate that Android requires. Actual logic should exist elsewhere.
If you scroll off, and scroll back to the same position you are supposed to keep the same state that you had on that ViewHolder, right?
No. Your ViewHolder should not maintain state. A ViewHolder holds views so Android doesn't have to re-inflate stuff over and over. It should not keep track of its state - it should be told what its current state is.
You should have a list of data objects (view models) that represent the current state of each item in the list. When you scroll off and back to the same position, you are supposed to re-bind the item that should be at that position to the view that represents it. Saving and clearing "state" objects should not be necessary - you should always have the current state on hand because it's the underlying data model driving your whole UI.
In my RecyclerView adapter I keep a collection of "State" objects which I use to save/restore the ViewHolder states, but it is getting way too big and way too complex
If something is too big and complex, break it down. Instead of having one giant-ass state object for each item, use composition. Make this item state have properties that represent pieces of the UI - PetModel, DateRangeModel, etc.
This may sound crazy, but it is there such thing as having a RecyclerList of Fragments? I just don't want to worry/bother about keeping the states of these ViewHolder anymore.
That does sound crazy because not only would this not solve your problem, you would probably actually make it significantly worse. You don't want to manage the state of a bunch of ViewHolders but you want to manage the states of a bunch of Fragments!? Bruh.
as you may imagine the onBindViewHolder is just a humongous piece of code that sets the views with the data I fetch from the API plus the data that I store in these "State" objects.
Again, break that up. You should not be slapping "data I fetched from the API" directly onto views. Invariably you will need to massage and transform raw data from an API before you display it. This should be handled by a dedicated object (again, ViewModel or some other structure). Again, views should be dumb. Tell them their state and that's it - don't do logic at this level.
Please read the Android Architecture Guide.
Also Google around for "Clean Architecture" - that seems to be all the range in Android these days.
And finally - here's some very rough pseudocode of how you could structure this to be more testable and maintainable.
From the bottom up:
ApiClient - responsible for just fetching the raw data from the API
endpoint or reporting an error.
ApiResponseModel - language-specific object representation
of the data you'll get from the API. Has info on the pet, dates,
guest count, etc. May contain submodels.
ItemDomainModel - client side representation of your data after transforming the data you'll get from the API.
Repository - uses the ApiClient to fetch the data as ApiResponseModel and transforms it into a ItemDomainModel object that makes more sense for your app.
ItemViewModel - Represents the UI state of a single item in the RecyclerView. Takes a ItemDomainModel instance and exposes the state of the UI based on the state of that model. This can be broken down if it's too complex (PetStateViewModel, DateRangeViewModel, GuestCountViewModel, etc)
ListViewModel - The top-level Android ViewModel that represents the state of the screen. Uses the Repository to fetch the data then constructs a list of ItemViewModels to feed into the RecyclerViewAdapter.
If you get those pieces in place, your view binding in the adapter should be stupid dumb:
override fun onBindViewHolder(viewHolder: ViewHolder, position: Int) {
// The adapter list should be a list of view models populated by the
// fragment after the ListViewModel returns a list of them from the fetch
val itemViewModel = itemViewModels[position]
// Populating this item view should just be a one-to-one mapping of the view model
// state - NO LOGIC. Dumb. Stupid. Tonto.
viewHolder.bringingPets.isChecked = itemViewModel.isBringingPets
viewHolder.guestCount.text = itemViewModel.guestCount
// ... etc, etc (if you use databinding this is a one-liner and even stupider)
// Set up your event listeners so interacting with this specific item in the list
// updates the state of the underlying data model
viewHolder.bringingPets.setOnCheckChanged { itemViewModel.isBringingPets = it.isChecked }
viewHolder.rentButton.onClickListener { itemViewModel.rentThis() }
// ... etc, etc
}
The goal is to do as little as possible here. Just update the state and wire up your callbacks that just delegate back to the ViewModel. Then, those UI states are driven by the logic in the view model. This is where you do business logic that determines how the UI should look.
class ItemViewModel(private val dataModel: ItemDomainModel) {
var isBringingPets: Boolean
get() = /* some business logic that determines if the checkbox is checked */
set(value) /* update underlying state and notify of changes */
// ... etc, etc, for guest count and other properties
fun rentThis() {
// Fire an event or update live data or invoke a callback that
// the fragment can use to respond
}
// ... etc, etc, for other functions that respond to UI events
}
In Summary
Refactor your code to break down the huge and complex logic into dedicated components that each have a simpler, specific focus, then compose them together to get the behavior you want. Good luck.

Android ListView with “tabs”

picture from a reddit news feed
(https://i.stack.imgur.com/6YXMK.jpg)
I am creating an app with a list view that is populated from a sqlite database. Each of the data base items can have a status of either “resolved” or “unresolved”.
I want the listview to have 3 “tabs” with the labels “all items”, “resolved items”, and “unresolved items” with correspoding sqlite queries to populate each.
It should behave similarly to the one pictured.
I assumed this would be a tabbed listview and have been watching tutorials for a week based on those search words and it’s taking taking me down a dark rabbit hole of fragments and changing gradles and so on. I’m not sure tabs are what i really want.
Could I do this with three buttons instead where each button would run a different query and populate my listviewcontainer?
Ideally, when the page is opened, the first “tab” would be highlighted and the listview populated with all records. As the other tabs are pressed, they would highlight and a new query would run.
Would another approach work better?
I’m not asking for code, I just want some conceptual direction on where to focus my research.
If I get you right you need to filter your query results in different lists. Making a lot of queries into database is not the thing that is preferable specially if it's going to be a long process and doing it a lot of times is time and memory consuming.
So to make it work you could simple store your full query result in one variable and change the RecyclerView data using custom method setList() and later using notifyDataSetChanged() to apply the changes.
To make it work you need to get understanding of "how RecyclerView works" and then you will be fine.
So after providing the right logic you would be able to simple split your whole query result as it's needed (by element values for example) as it's showed above:
About the code below:
list - is your query result
leftFilterList or rightFilterList - are lists that contain sorted items
adapter.setList(rightFilterList) - sets the RecyclerView data (filtered items in our case)
adapter.notifyDataSetChanged() - is used to notify RecyclerView that list was changed, and he need to rebuild it.
So we have two Buttons and logic that fillter items in differend ways.
public void left(View view) {
ArrayList<ExampleItem> leftFilterList = new ArrayList<>();
for (ExampleItem item : list) {
if (item.getTitle().length() % 2 == 0) {
leftFilterList.add(item);
}
}
adapter.setList(leftFilterList);
adapter.notifyDataSetChanged();
}
public void right(View view) {
ArrayList<ExampleItem> rightFilterList = new ArrayList<>();
for (ExampleItem item : list) {
if (item.getTitle().length() % 2 == 1) {
rightFilterList.add(item);
}
}
adapter.setList(rightFilterList);
adapter.notifyDataSetChanged();
}
And the result of filtering*:
sorry for wrong toast text. It shows the whole list size.

Couchbase lite on Android, retrieve views

This question is about Couchbase lite (no Sync Gateway).
I'm new to Couchbase, I managed to use the demo app, but I don't understand it completely.
It contains this code which (as far as I understand, since I'm not native English speaker) retrieve views to populate a listview with the indexes:
// This code can be found in ListsActivity.java
// in the setupViewAndQuery() method
com.couchbase.lite.View listsView = mDatabase.getView("list/listsByName");
if (listsView.getMap() == null) {
listsView.setMap(new Mapper() {
#Override
public void map(Map<String, Object> document, Emitter emitter) {
String type = (String) document.get("type");
if ("task-list".equals(type)) {
emitter.emit(document.get("name"), null);
}
}
}, "1.0");
}
listsLiveQuery = listsView.createQuery().toLiveQuery();
Could anyone give me a hand with what each part is doing?
In which step is the listview populated
Can I change "list/listsByName" in the code (line 3)? What would happen?
Can I emit more than one element?
The code is a little bit convoluted. Let's answer the easy parts first.
Can I change "list/listsByName" in the code (line 3)?
Yes. That's just the name of the Couchbase View. You choose the View name. Unfortunately the terms used in Couchbase and Android overlap some. A Couchbase View is a kind of static index of your database.
Can I emit more than one element?
Yes. You can emit most anything you want. Take a look at the documentation here
Now, tracing how the Android ListView gets updated:
In ListsActivity.java notice in the onCreate method a ListAdapter instance gets added to the ListView. This ListAdapter is a private inner class that extends LiveQueryAdapter.
LiveQueryAdapter is in the utils subpackage. If you look at its constructor, you'll see it adds a change listener to the query passed in. When triggered, this change listener sets an enumerator equal to the rows passed back by the live query, then calls notifyDataSetChanged to tell the list to refresh itself. That, in turn, causes getView in ListAdapter to get called. That's where the data is pulled from the database and used to populate a list entry.

Adding a Two Way Friend Relation on Parse for Android

I am currently working on an app with a friendship feature similar to Facebook(a request is sent and if accepted they both become friends). The sending user can select multiple users from a list and send them all invites at once. When this happens, the receiving users are added to a relation called "pendingRelation" for the sending user. However, I would also like the sending user to be added as a "pendingRelation" for all the receiving users as soon as the request is sent. I have messed around and haven't been able to find a good solution for this. The code to add the selected users as "pendingRelation" is simple.
private boolean sendFriendRequest() {
//Cycles through list of selected friends and adds as "Pending"
for (int i = 0; i < mPendingFriends.size(); i++) { //Cycles through list
mPendingRelation.add(mPendingFriends.get(i));
}
mCurrentUser.saveInBackground(new SaveCallback() {
#Override
public void done(ParseException e) {
if (e != null) {
Log.e(TAG, e.getMessage());
}
}
});
If anyone can help me add the sender as a "pendingRelation" to the reciever as well to create this two-way relationship that would be great. Thanks!
I've actually thought about making a follow system with Parse which is quite similiar to your problem. Have you thought about making a new ParseObject instead of relation? Then you could add something like ParseUser pendingUser, ParseUser requestUser, boolean isAccepted.
Anywho if you can't find help from here you can try post it to parse.com questions.
I am trying to figure out the same thing for my app (although I am using javascript so I can't give you working code.. sorry.).
To expand on Torsten's answer. One solution would be to create a table(class) in Parse with the fields "pendingFriendRequest" "associatedUserID_requestingUser" "associatedUserID_receivingUser" and "accepted (boolean)".
SIDE NOTE: You could also add a matching function this way by querying
this table(class) and determining whether there are two
"pendingFriendRequests" from each individual user for the other user.
Then, you can present the user the results of querying this table and an option to "accept" (you can also present an option to ignore/delete and just drop the row).
Once the user clicks "accept" link that to a function which then creates the user relation.
In javascript it looks something like this:
likeAUser: function (userId) {
var currentUser = $rootScope.loggedInUser;
var User = Parse.Object.extend("User");
var user = new User();
user.id = userId;
var likes = currentUser.relation("Likes");
//console.log(likes);
likes.add(user);
return currentUser.save();
},
and within the function you are creating the new relation you would then drop(delete) the row from the "pendingRequests" table.
I hope this helps,
I have been racking my brain on how to do this and this is the best way I can figure out pending Parse making it easier to interact with relations elements inside their user class. Sorry I don't know the android version to help more.

How do i make a history calculator in android?

I am making a calculator same as windows calculator. I am stuck at the history feature. which would be the best UI control to implement the history feature as seen in Windows Calculator?
I also want onclick events on the history.
I'm not sure how you represent a calculation, but you could have a simple class like this:
enum Operator {PLUS,MINUS,DIV,MULT};
class Calculation {
float operand1,operand2;
Operator operator;
public Calculation(float op1,float op2,Operator operator){
this.operand1=op1;
this.operand1=op2;
this.operator=operator;
}
}
Then when a calculation is done, create an object of this type and add it to an ArrayList:
List<Calculation> history = new ArrayList<Calculation>();// history
history.add(new Calculation(5,5,Operator.PLUS));// add a new `Calculation` to our list
Then access the list with history.get(some_integer), based on your UI.
Could you just use a List containing a number of previously entered calculations? If you knew the maximum possible history size in advance, you could just stick with a normal array, but a List will give you more flexibility.
You need to store all the operations and results with an index here. Increase the index every time when you perform an operation.To retrieve the past operation, manipulate the index and you can get the values.You can use Collection API for storing the operations.

Categories

Resources