ViewModel object with list and nested objects - android

I am working on a new Android project and am using the new Architecture components but could use some help in some scenarios, as I do not understand the best solution.
I have an object such as below
public class Team {
String name;
String location;
List<User> users;
}
public class User {
String firstName;
String lastName;
}
For the ViewModel should the mutableLiveData be the Team object or each individual property, the same for the users, I will be updating and users and wonder if how I should observe those changes

Related

How to access model class of another app in a different app both having a common existing database?

There are two different apps that are connected to the same database. One is sort of an admin app that updates and deletes data in the database and the other is sort for the user app which only receives the data in the app. I have used the model class in the admin app to update and delete the data. I want to show this data in the user's app using firebase recycler but for which I require model class that was used how can I achieve that??
MY MODEL CLASS
package com.parth.iitktimes;
import java.io.Serializable;
public class Creator implements Serializable {
private String name,design,email,phone,downloadUrl,uniquekey;
public String getDownloadUrl() {
return downloadUrl;
}
public void setDownloadUrl(String downloadUrl) {
this.downloadUrl = downloadUrl;
}
public String getUniquekey() {
return uniquekey;
}
public void setUniquekey(String uniquekey) {
this.uniquekey = uniquekey;
}
public Creator(String name, String design, String email, String phone, String downloadUrl, String uniquekey) {
this.name = name;
this.design = design;
this.email = email;
this.phone = phone;
this.downloadUrl = downloadUrl;
this.uniquekey = uniquekey;
}
//empty constructor
public Creator() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDesign() {
return design;
}
public void setDesign(String design) {
this.design = design;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
}
MY FIREBASE CONSOLE
images of firebase console
Architecture
enter image description here
Your question is not clear enough to answer correctly, but i think you are trying to access common classes of your app (like data model) from another.
You should consider using module for your project, generally speaking the code you write for your one app can't directly or indirectly access your other app's data and class even if both app is build by you.
(Technically it can access using reflection and other methods but you want to use same codebase)
There are many benefits of building modular app check out this 2019 IO talk
okay, so how you can access your common classes in both client and admin app?
create a new project (in android studio), create a new library module in same project, again create a new app module in same project.
what you got is two app and one library in one project, you can use that library as a dependency for both of your apps and write common classes in that library.
If I Right with the question,
In Firebase Project Overview......where you used firebase for Admin App and choose Add App...you can add User App to connect two app in single Firebase

Is it possible to hide some fields from our model?

I decided to use Room for caching data and now because of the situation of the library that I developed, I need to hide some fields of my model and then give them to the client that use my library.
The model below had orderId and I added this because I need that but when I don't want to give this filled model with orderId. i know how to ignore fields in JSON. But how can i hide this one from my model and then give it to the client.
Do I make a mistake in using Room in the first place?
public class Participant {
#PrimaryKey
private long id;
#ColumnInfo(name = "order_id")
private long orderId;
private long threadId;
private String name;
private String firstName;
private String lastName;
For example :
i have a listener that is like the below
listener.add(participant);
i want to hide orderId first and then pass it to the listener.
Then in another class override this:
#Override
public void onAdd(Paticipant participant) {
super.onAdd(participant);
//here
}
One way to hide orderId from classes which use Participant, is to provide a getter for this variable and return null:
public Long getOrderId() {
return null;
}
We must change orderId to a Long in order for it to be set as null.
Additionally, you can override the toString() method to ignore orderId in any string representations of the class.
Use GSON library and create a new class for JSON model, without orderId:
class ParticipantJson {
final long id;
final long threadId;
final String name;
final String firstName;
final String lastName;
// Constructor
}
Then you can create JSON representation with:
ParticipantJson participant = new ParticipantJson(/* fields from Room model */);
Gson gson = new Gson();
String json = gson.toJson(participant);
USE A DIFFERENT MODEL FOR PRESENTATION!
Sorry for the caps but I cannot emphasize how important it is to use a different model for presentation.
Although you can hide fields from libraries like GSON or ROOM using keywords like transient or annotation like ignore you cannot hide a model attribute from class itself. Also remember that you cannot enforce a rule on a model that is not designed for the purpose.
TLDR; Create a new model and using a mapper map the Room model to this new presentation model.

Inform ViewModel of Model update?

I am currently working on an app that uses Firebase's real-time database and data binding for displaying. To keep it simple, here's a simple version of the problem:
Given a model class:
public class User {
private String name;
private Date date;
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public Date getDate() { return date; }
public void setDate(Date date) { this.date = date; }
}
And a ViewModel class for the users:
public class UserViewModel {
private User user;
public void setUser(User user) {
this.user = user;
}
public String getName() { return user.getName() }
public void setName(String name) { user.setName(name); }
public String getDateAsString() { // ... }
}
Now, in the activity/fragment I have a RecyclerView rendering a list of users. So within the adapter's onCreateViewHolder() I inflate a layout using DataBindingUtils, create a new ViewHolder and a new UserViewModel instance which accesses the UI. In onBindViewHolder() the UserViewModel gets assigned with the according User instance.
So far, so good: Given a list of users, its items get rendered into the RecyclerView through the UserViewModel.
For the app, I also use Firebase to read and write to the Realtime database. So when I now get a callback that a User entry has been updated, I directly modify the infos in the according instance.
So now to the question: How do I inform the UserViewModel that the data has changed and that it needs to redraw the according views in the UI?
I know one step I need to do is to have UserViewModel extend BaseObservable, mark the methods with #Bindable and add calls to notifyPropertyChanged(int) in the setters of the ViewModel. But this doesn't solve the problem of how to inform the UserViewModel of an update to the model data.
Any help and example code is appreciated! Thx! :)
You don't need to extend UserViewModel with BaseObservable, but you can. I'll show another way how you can achieve this.
Personally, I prefer to create a ObservableField<User> in my UserViewModel, create getters and setters like:
private final ObservableField<User> userField = new ObservableField<User>();
public UserViewModel(User user){
userField.set(user);
}
public ObservableField<User> getUser(){
return userField;
}
pass it to the layout and reference the properties like this:
<variable
name="userViewModel"
type="your.package.UserViewModel" />
<EditText
android:text"#={userViewModel.user.name}" />
Whenever your user changes his Name in your EditText, the changes are also updated in your model. (Using two-way databinding with #={})
Updated to use the ObservableField, thanks for the heads up, #tynn. Correct me, if I'm still wrong.
If I understand you correctly, you can take a look at using RxJava/RxAndroid to subscribe your viewModel to changes in the model class or the firebase instance (they should be observable). So for example, as you want to let the viewModel know that the firebase has a new user and that a user entry has been updated, you can call the viewModels onNext method from that callback, which will notify the viewModel subscribed to it, and run the method you want to run (like fetching the data), then with base observable you can then notify your list.

Android Realm.io - Removing sub-objects

Let's say I have a structure of realm-objects that looks like this -
public class Person extends RealmObject {
#PrimaryKey
private int id;
private String name;
private List<Pet> pets
// Setters, getters...
}
public class Pet extends RealmObject {
private String name;
private MedicalRecord record;
// Setters, getters...
}
public class MedicalRecord extends RealmObject {
private String something;
private String somethingElse;
// Setters, getters...
}
Now I received a new Person object with an existing id (primary-key) and I want to update this person.
So I do something like this -
realm.beginTransaction();
realm.copyToRealmOrUpdate(person);
realm.commitTransaction();
The trouble is that this person's pet list (and the pets' medical records), are still out there in the db. not linked anymore to this person, but still there.
I tried to do this -
Person existingPerson = realm.where(Person .class).equalTo("id", ID).findFirst();
existingPerson.getPets().clear();
But no success there. How can I remove subobjects of realmObjects?
Also, is there a way to define a policy for a realm-object so that it will remove itself once there is no reference to it (it's not linked to any parent-object)?
Now you can, and method was renamed from last commit to realmList.deleteAllFromRealm()

Practical use of #Ignore in Realm?

I've been trying to add Realm in my Android app. Their docs are pretty well explained & easy to follow. But it fails to explain this one particular area. I'm unable to figure out the practical use for the #Ignore annotation. I know that fields under this annotation are not persisted.
Can someone please share a few use cases. Also I wanted to know the scope of such fields. I mean, if I set an #Ignore field to some value, would that value be available to the other classes in my app for that particular launch session. If yes, then how do we access it? If no (which I guess is the case), then why do we need such a field anyway?
I've searched here and on web but couldn't find the relevant information. If out of my ignorance, I've missed upon some resource, please guide me to it.
Thanks.
Accordingly to the official documentation (see https://realm.io/docs/java/latest/) #Ignore is useful in two cases:
When you use GSON integration and your JSON contains more data than you want to store, but you still would like to parse it, and use right after.
You can't create custom getters and setter in classes extending RealmObject, since they are going to be overridden. But in case you want to have some custom logic anyway, ignored fields can be used as a hack to do that, because Realm doesn't override their getter & setters. Example:
package io.realm.entities;
import io.realm.RealmObject;
import io.realm.annotations.Ignore;
public class StringOnly extends RealmObject {
private String name;
#Ignore
private String kingName;
// custom setter
public void setKingName(String kingName) { setName("King " + kingName); }
// custom getter
public String getKingName() { return getName(); }
// setter and getter for 'name'
}
Ignored fields are accessible only from the object they were set in (same as with regular objects in Java).
UPDATE: As the #The-null-Pointer- pointed out in the comments the second point is out of date. Realm now allows having custom getters and setters in Realm models.
Here's a couple of real-world use cases:
1 - Get user's fullname:
public class User extends RealmObject {
private String first;
private String last;
#Ignore
private String fullName;
public String getFullName() {
return getFirst() + " " + getLast();
}
Get JSON representation of object:
public class User extends RealmObject {
private String first;
private String last;
#Ignore
private JSONObject Json;
public JSONObject getJson() {
try {
JSONObject dict = new JSONObject();
dict.put("first", getFirst());
dict.put("last", getLast());
return dict;
} catch (JSONException e) {
// log the exception
}
return null;
}
I've found it useful to define field names for when I am querying. For example
User.java
public class User extends RealmObject {
#Index
public String name;
#Ignore
public static final String NAME = "name";
}
And then later on I can do something like:
realm.where(User.class).equalTo(User.NAME, "John").findFirst();
This way if the schema changes from say name to id I don't have to hunt down every occurrence of "name".
Please see the the official documentation about #Ignore annotation:
The annotation #Ignore implies that a field should not be persisted to disk. Ignored fields are useful if your input contains more fields than your model, and you don’t wish to have many special cases for handling these unused data fields.

Categories

Resources