I have below database structure in firebase. I am trying to get the key value "Std IX" inside onBindViewHolder and set it in class_key. I am able to get the key value "science" using below code in post_key field but, not able to get it's child key "Std IX" in class_key using String class_key = getRef(position).child(post_key).getKey();
Query query = FirebaseDatabase.getInstance()
.getReference()
.child(user_id).child("List_of_subjects");
FirebaseRecyclerOptions<Subject_list_GetSet> options =
new FirebaseRecyclerOptions.Builder<Subject_list_GetSet>()
.setQuery(query, Subject_list_GetSet.class)
.build();
adapter = new FirebaseRecyclerAdapter<Subject_list_GetSet, Subject_list_viewHolder>(options) {
#Override
protected void onBindViewHolder(#NonNull final Subject_list_viewHolder holder, int position, #NonNull Subject_list_GetSet model) {
final String post_key = getRef(position).getKey();
String class_key = getRef(position).child(post_key).getKey();
holder.setSubject_name(post_key);
holder.setClass(class_key);
holder.setBk1(model.getBk1());
holder.setBk2(model.getBk2());
holder.setBk3(model.getBk3());
Subject_list_GetSet.java
public class Subject_list_GetSet {
private String Subject_name,Recom_bk,bk1,bk2,bk3;
public Subject_list_GetSet(){}
public Subject_list_GetSet(String Subject_name,String bk1,String bk2,String bk3){
this.Subject_name=Subject_name;
this.bk1=bk1;
this.bk2=bk2;
this.bk3=bk3;
}
public String getSubject_name() {
return Subject_name;
}
public void setSubject_name(String Subject_name) {
this.Subject_name = Subject_name;
}
public String getBk1() {
return bk1;
}
public void setBk1(String bk1) {
this.bk1 = bk1;
}
public String getBk2() {
return bk2;
}
public void setBk2(String bk2) {
this.bk2 = bk2;
}
public String getBk3() {
return bk3;
}
public void setBk3(String bk3) {
this.bk3 = bk3;
}
}
Since you create an adapter on List_of_subjects, the adapter will try to show the direct child nodes under that level in the JSON. So from the screenshot, Firebase will try to create a Subject_list_GetSet for the science node, mapping the properties directly under that in the JSON to those in your Java class.
To match the JSON structure you'd need a field/property like this in the class:
#PropertyName("Std IX")
public String stdIX;
Since I expect that this key may be dynamically generated, this may not be possible. In that case the only way to get the right data in your adapter is to use a custom SnapshotParser as shown in the documentation.
Related
Basically my problem is that I had stored in firebase db a list of users with multiple attributes, some of them were private informations so I wanted to deny access to them. Rules aren't the answer because they can't be used as filters.
My solution was to create two new attributes for "users": "pvt" (private) and "pb" (public) and to store inside of them the correct attributes.
To create new users I used first:
mDatabase.child("users").child(prefs.getString("id firebase", " ")).child("public").setValue(newUserPublic);
mDatabase.child("users").child(prefs.getString("id firebase", " ")).child("private").setValue(newUserPrivate);
where newUserPublic and newUserPrivate are objects of simple custom classes that offers getters and setters for user's attributes (one for public and the other for private informations).
My final goal was to create a leaderboard that uses only public attributes of each user but I wadn't able to create a proper ListAdapter with this configuration.
My final try was to create a new class called User
public class User {
public UserDataPrivate getPvt() {
return pvt;
}
public void setPvt(UserDataPrivate pvt) {
this.pvt = pvt;
}
public UserDataPublic getPb() {
return pb;
}
public void setPb(UserDataPublic pb) {
this.pb = pb;
}
private UserDataPrivate pvt;
private UserDataPublic pb;
public void setId(String id) {
this.id = id;
}
private String id;
public User(String id, UserDataPublic pb, UserDataPrivate pvt){
this.pvt=pvt;
this.pb=pb;
this.id=id;
}
}
to create new user with:
User user = new User(newUserPublic, newUserPrivate);
mDatabase.child("users").child(prefs.getString("id firebase", " ")).setValue(user);
and the current adapter is
DatabaseReference mDatabase = FirebaseDatabase.getInstance().getReference("users");
Query query = mDatabase.child("pb").orderByChild("points");
ListAdapter adapter = new CustomFirebaseAdapter<User>(this, User.class, R.layout.list_item, query) {
#Override
protected void populateView(View v, User model, int position) {
//code that uses model.getPb()
}
};
but it doesn't work (//code is never executed).
Do you have any idea how I can solve this?
This is a test user in Firebase:
EDIT:
Tried to user pb/score inside the query but it crashes.
I think the problem is that firebase can't handle complex objects or I'm missing something. I have other code portions wich retrive single user data so I use
final DatabaseReference userDatabase = mDatabase.child("users").child(prefs.getString("id firebase", " "));
userDatabase.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
User user = dataSnapshot.getValue(User.class);
//...
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
and it crashes when setting user. I thought that if I save users in my db using user objects I could retrive them in the same way but I'm probably wrong.
When you call orderByChild() on a location, Firebase takes each node directly under that location and orders it on the child you specify. Since you call orderByChild("points") on /users, it takes the nodes under /users and orders them on their (non-existing) points property.
To order each user on their pb/points property, use that path in the call to orderByChild(). So:
DatabaseReference mDatabase = FirebaseDatabase.getInstance().getReference("users");
Query query = mDatabase.orderByChild("pb/points");
ListAdapter adapter = new CustomFirebaseAdapter<User>(this, User.class, R.layout.list_item, query) {
#Override
protected void populateView(View v, User model, int position) {
//code that uses model.getPb()
}
};
This code:
DatabaseReference mDatabase = FirebaseDatabase.getInstance().getReference("users");
Query query = mDatabase.child("pb").orderByChild("points");
will point to /users/pb and order by users/pb/??/points. If you seek for query that point to /users/?? order by users/??/pb/points, then I think Firebase can't do that for now. Check this post
You can use a firebase listview adapter and that does a lot of the work for you. But you might want to change your user objects.
Query query = FirebaseDatabase.getInstance().getReference("users").orderByChild("pb/points");
FirebaseListAdapter adapter = new FirebaseListAdapter(activity, User.class, R.id.modelLayout, query) {
#Override
protected void populateView(View view, User user, int i) {
//view is current view
//user is current user
//i is position
TextView points = view.findViewById(R.id.pointsTextView);
String userPoints = user.getPb().getPoints();
points.setText(userPoints);
}
};
Then apply the adapter on a view
listview.setAdapter(adapter);
i am trying to get session stored variable in to a class. please see my actual code for class
public class GetDataAdapter {
public String ImageServerUrl;
public String ImageTitleName;
public String ImageUrlName;
public String getImageServerUrl() {
return ImageServerUrl;
}
public void setImageServerUrl(String imageServerUrl) {
this.ImageServerUrl = imageServerUrl;
}
public String getImageTitleName() {
return ImageTitleName;
}
public void setImageTitleNamee(String Imagetitlename) {
this.ImageTitleName = Imagetitlename;
}
public String getImageUrlName() {
return ImageUrlName;
}
public void setImageUrlNamee(String Imageurlname) {
this.ImageUrlName = Imageurlname;
}
}
now i stored a value in session and i want to use in above code. Imageurlname is a url fetching from database. i want to add extra to the url. for example
this is my URl Getting form database http://example.com?id=
i stored user id in session so combining both url should be http://example.com?id=5
please see my modified code
public class GetDataAdapter extends AppCompatActivity {
public String ImageServerUrl;
public String ImageTitleName;
public String ImageUrlName;
private Session session;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
session = new Session(GetDataAdapter.this);
HashMap<String, String> user = session.getUserDetails();
final String Uid = user.get(session.KEY_UID);
}
public String getImageServerUrl() {
return ImageServerUrl;
}
public void setImageServerUrl(String imageServerUrl) {
this.ImageServerUrl = imageServerUrl;
}
public String getImageTitleName() {
return ImageTitleName;
}
public void setImageTitleNamee(String Imagetitlename) {
this.ImageTitleName = Imagetitlename;
}
public String getImageUrlName() {
return ImageUrlName;
}
public void setImageUrlNamee(String Imageurlname) {
this.ImageUrlName = Imageurlname + Uid;
}
}
Uid is getting error. i hope you understand.
Looks like the problem is with persisting the userid in your case it is because of this.
Using instance variable to store user id which you can get only if you are getting the same object
Here are the solution(s):
Solution 1:
Using Static Variables
public class Example {
//this is the default value which will there stored before we are setting our actual userId
public static String USER_ID="DefaultId";
}
You can set and access the values this way.
Log.d("Default Value",Example.USER_ID);
//setting user id here
Example.USER_ID = "Manikanta Garikipati";
Log.d("Updated value",Example.USER_ID);
Solution 2: Using Shared preferences.
As you already know about this i would explain anyway.
Comment below if your problem is still not solved.
Here is the brief summary of the problem
The problem is not in shared preferences neither any storage.
Instead of creating a bean alone and setting the values to it , bean is extended with Activity etc.. which made things haywire..
Those who want the complete solution can go through the conversation in question.
Application class is there for you. use it and save your application level data, like this:
public class WhatEverApp extends Application
{
String mApplicationLevelVar = "Hello";
}
WhatEverApp will be the name of your app used in manifest.xml
Look here for detailed discussion on Application class.
I have data in my firebase DB, everything works fine until I try to De-serialize the data.
Error: argument 1 has type io.realm.RealmList, got java.util.ArrayList
Here's my code:
DatabaseReference root = FirebaseDatabase.getInstance().
getReferenceFromUrl("https://swing-8792d.firebaseio.com/playlist");
Query playlistQuery = root.orderByKey().equalTo(key);
playlistQuery.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for (DataSnapshot child : dataSnapshot.getChildren()) {
Log.d("Child", child + "");
Playlist receivedPlaylist = child.getValue(Playlist.class);
Playlist playlist = new Playlist();
playlist.setCreatedBy(receivedPlaylist.getCreatedBy());
playlist.setName(receivedPlaylist.getName());
playlist.setMyMap(receivedPlaylist.getMyMap());
playlist.setQrKey(receivedPlaylist.getQrKey());
playlist.setCount(receivedPlaylist.getCount());
playlist.setId(receivedPlaylist.getId());
playlist.setTracks(receivedPlaylist.getTracks());
mPlaylist.add(playlist);
}
This is my POJO class:
#RealmClass
public class Playlist extends RealmObject {
String name;
Long id;
RealmList<Track> tracks;
Integer count;
String createdBy;
RealmList<UserMap> myMap;
String qrKey;
public RealmList<UserMap> getMyMap() {
return myMap;
}
public void setMyMap(RealmList<UserMap> myMap) {
this.myMap = myMap;
}
public Playlist(){}
public String getQrKey() {
return qrKey;
}
public void setQrKey(String qrKey) {
this.qrKey = qrKey;
}
public String getCreatedBy() {
return createdBy;
}
public void setCreatedBy(String createdBy) {
this.createdBy = createdBy;
}
public RealmList<Track> getTracks() {
return tracks;
}
public void setTracks(RealmList<Track> tracks) {
this.tracks = tracks;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Integer getCount() {
return count;
}
public void setCount(Integer count) {
this.count = count;
}
}
If I try to de-serialize with Normal POJO class (i.e Removing Realm) it works fine.
Firebase won't work with classes that do not have default constructor or private variables i.e no public getter/setter.
A easier solution in your case would be to make a middleware class that is the same pojo just not extending RealmObject. Next initialise your RealmObject subclass using the values of the pojo.
Pseudo code
class SimplePojoPlaylist {
public String variable;
}
class Playlist extends RealmObject {
public String variable;
}
Then first cast into SimplePojoPlaylist
for (DataSnapshot child : dataSnapshot.getChildren()) {
SimplePojoPlaylist receivedPlaylist = child.getValue(SimplePojoPlaylist.class);
Playlist playList = new Playlist();
playList.variable = receivedPlaylist.variable;
}
RealmList is not a supported type for deserialization. Your database checks its structure and deduces that tracks should be an ArrayList. Then, when it tries to convert it, it finds that the types do not match.
Check this link from the docs:
Also, it is a good practice to make your objects immutable to avoid unwanted access and/or modifications.
Creating an empty object from scratch and then calling setter methods to define its state is not a very good pattern, because it can create a situation where an object is accessed before when its state is "broken".
If you need to create an object that is flexible, has a few mandatory fields and some optional, consider using the Builder pattern, although to do it you'd have to redesign your model.
wikipedia - Builder
If you don't need/want to use a builder, my advice is:
1) Make the empty constructor private and create another public one that requires all the fields.
2) Change your tracks field to be of type "List". Then, if you need the object to return a RealmList create another getter method such as tracksAsRealmList() that makes a RealmList out of the member list and returns it.
3) Make sure that the "Track" model has an empty private constructor, a public one with all of its parameters and that all of its fields are supported by firebase deserialization.
4) Unless strictly necessary, make your object fields private and set its value through a setter method.
I hope this helps you.
I am having trouble retrieving a List from the Firebase. I have no trouble storing it, but as soon as I try to cast dataSnapshot.getValue() to ArrayList my app crashes, giving an exception:
HashMap cannot be casted to ArrayList
But when I tried to cast it to a HashMap, it also crashes, giving exception:
ArrayList can't be casted to hashmap
Need help please! Here is the code that is creating the problem:
Fire.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
List<TaskDes> td = (ArrayList<TaskDes>) dataSnapshot.getValue()
notifyDataSetChanged();
}
#Override
public void onCancelled(FirebaseError firebaseError) {
}
});
I want to retrieve all the data in the Firebase as one List. The class TaskDes contains three fields:
class TaskDes { // definition
boolean done
String taskDescription
String taskTitle
}
You need to create a GenericTypeIndicator object to pass as DataSnapshot.getValue() parameter.
Code:
GenericTypeIndicator<List<String>> t = new GenericTypeIndicator<List<String>>() {};
List<String> yourStringArray = dataSnapshot.getValue(t);
Your Model
public class TaskDes {
private boolean done;
private String taskDescription;
private String taskTitle;
public TaskDes() {
}
public boolean isDone() {
return done;
}
public void setDone(boolean done) {
this.done = done;
}
public String getTaskDescription() {
return taskDescription;
}
public void setTaskDescription(String taskDescription) {
this.taskDescription = taskDescription;
}
public String getTaskTitle() {
return taskTitle;
}
public void setTaskTitle(String taskTitle) {
this.taskTitle = taskTitle;
}
}
You need to create a GenericTypeIndicator object to pass as DataSnapshot.getValue() parameter.
In Activity
private static final String TAG=MainActivity.class.getSimpleName();
private FirebaseDatabase database;
private DatabaseReference myRef=null;
#Override
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
database=FirebaseDatabase.getInstance();
myRef=database.getReference("ADD_YOUR_REFERECE");
myRef.addValueEventListener(new ValueEventListener(){
#Override
public void onDataChange(DataSnapshot dataSnapshot){
/* This method is called once with the initial value and again whenever data at this location is updated.*/
long value=dataSnapshot.getChildrenCount();
Log.d(TAG,"no of children: "+value);
GenericTypeIndicator<List<TaskDes>> genericTypeIndicator =new GenericTypeIndicator<List<TaskDes>>(){};
List<TaskDes> taskDesList=dataSnapshot.getValue(genericTypeIndicator);
for(int i=0;i<taskDesList.size();i++){
Toast.makeText(MainActivity.this,"TaskTitle = "+taskDesList.get(i).getTaskTitle(),Toast.LENGTH_LONG).show();
}
}
#Override
public void onCancelled(DatabaseError error){
// Failed to read value
Log.w(TAG,"Failed to read value.",error.toException());
}
});
}
Make another item that contains a list for your item:
This is your item:
class TaskDes { // definition
boolean done
String taskDescription
String taskTitle
}
This is the list item
class TaskDesList { // definition
private ArreyList<TaskDes> yourlist
}
public TaskDesList(){
}
public ArrayList<TaskDes> getYourlist() {
return yourlist;
}
and when calling an EventListener
ref.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
yourlist.clear();
taskDesList=dataSnapshot.getValue(TaskDesList.class);
if (taskDesList!=null) {
yourlist= taskDesList.getYourlist();
}
}
and now "yourlist" is a list that contains all of your "TaskDes" items
A bit late, but in case any one else needs this.
IF the list is inside another object.
The object
public class Question {
public Date date;
public String questionNumber;
public String questionText;
public QuestionType questionType;
public String multipleSelection1;
public String multipleSelection2;
public String multipleSelection3;
public Question() {
// Default constructor required for calls to DataSnapshot.getValue(User.class)
}
}
Then to get your array of question objects
GenericTypeIndicator<List<Question>> t = new GenericTypeIndicator<List<Question>>() {};
List<Question> questionList = dataSnapshot.getValue(t);
Apparently, the GenericTypeIndicator doesn't work for all List objects particularly when the object contains none primitive types like maps. So, if it didn't work for your use case as it didn't for me, try this alternate solution:
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
List<TaskDes> tDlist = new ArrayList<>();
for (DataSnapshot d: dataSnapshot.getChildren()){
TaskDes tD = d.getValue(TaskDes.class);
tDlist.add(tD);
}
notifyDataSetChanged();
}
As mentioned in the previous answers make sure your class( like TaskDes in this case) has a public constructor which is empty so the getValue method can deserialize correctly to your java class.
I am creating an application in android and I want to store data of places user selected on the google map. I am currently storing all the places by adding them all in an array and then serialize them by Gson library and it works fine and coding is very simple and easy but if i use data base instead of that that then the coding will be more complex and because implantation of data base is more complex then simply string the array of places to shared preferences. below is the class whose objects are i am storing and saving in the shared preferences but if want to store them on the data base then i have to go through more complex I have to create queries for insert, delete update etc. so suggest me that should i use db or shred preference is good for saving list of places.
package com.example.googlemapstext;
import java.util.ArrayList;
import android.location.Address;
public class MyPlace {
private int id;
private String placeName;
private Address placeAddress;
private int ringerState;
private int brightnessState;
private int wifiState;
private int gpsState;
private int bluetoothState;
private int radiusValueIndex;
private ArrayList<Contact> contactArrayList;
private String message;
private double radiusValue;
private boolean notificationCheck;
public MyPlace(int id,String placeName, Address placeAddress, String radiusValue,
int ringerState, int brightnessState, int wifiState, int gpsState,
int bluetoothState, int radiusValueIndex, ArrayList<Contact> contactArrayList,
String message, boolean notificationCheck) {
this.id=id;
this.placeName = placeName;
this.placeAddress = placeAddress;
this.radiusValue = getTrimedRadiusValue(radiusValue);
this.ringerState = ringerState;
this.brightnessState = brightnessState;
this.wifiState = wifiState;
this.gpsState = gpsState;
this.bluetoothState = bluetoothState;
this.contactArrayList = contactArrayList;
this.message = message;
this.radiusValueIndex = radiusValueIndex;
this.notificationCheck = notificationCheck;
}
private double getTrimedRadiusValue(String radiusValue)
{
radiusValue=radiusValue.replace("Radius ", "");
radiusValue=radiusValue.replace(" Meters", "");
return Double.parseDouble(radiusValue);
}
public boolean getNotificationCheck() {
return notificationCheck;
}
public void setNotificationCheck(boolean notificationCheck) {
this.notificationCheck = notificationCheck;
}
public int getRadiusValueIndex() {
return radiusValueIndex;
}
public void setRadiusValueIndex(int radiusValueIndex) {
this.radiusValueIndex = radiusValueIndex;
}
public int getRingerState() {
return ringerState;
}
public void setRingerState(int ringerState) {
this.ringerState = ringerState;
}
public int getBrightnessState() {
return brightnessState;
}
public void setBrightnessState(int brightnessState) {
this.brightnessState = brightnessState;
}
public int getWifiState() {
return wifiState;
}
public void setWifiState(int wifiState) {
this.wifiState = wifiState;
}
public int getGpsState() {
return gpsState;
}
public void setGpsState(int gpsState) {
this.gpsState = gpsState;
}
public int getBluetoothState() {
return bluetoothState;
}
public void setBluetoothState(int bluetoothState) {
this.bluetoothState = bluetoothState;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public double getRadiusValue() {
return radiusValue;
}
public void setRadiusValue(String radiusValue) {
this.radiusValue = getTrimedRadiusValue(radiusValue);
}
public String getPlaceName() {
return placeName;
}
public void setPlaceName(String placeName) {
this.placeName = placeName;
}
public Address getPlaceAddress() {
return placeAddress;
}
public void setPlaceAddress(Address placeAddress) {
this.placeAddress = placeAddress;
}
public ArrayList<Contact> getContactArrayList() {
return contactArrayList;
}
public void setContactArrayList(ArrayList<Contact> contactArrayList) {
this.contactArrayList = contactArrayList;
}
public int getId() {
return id`enter code here`;
}
public void setId(int id) {
this.id = id;
}
}
The main difference between SharedPreferences and DataBase is like you mentioned :
SharedPreferences works on an Key-Value pair basis. you simply provide the Key and get back the Value you stored. that's great.
DataBase creates an SQLite Tables and you need to use queries to pull them out.
I think that if you are good with the JSON mechanism that you built, then storing a string in SharedPreferences is all you need.
But when the Data get more and more complex, and you would like quick access to any part of it, I think DB would be easier than parsing and seaching a JSON string all the time.
Yes, it might make you write more code for handling the DB queries..
I think SQLite will be better for you. I only use SharePreferences for small, simple and "key - value" structured data. (and it should be like that)
You have a lot of data, so SQLite is the way to go.
Read this for more information : Pros and Cons of SQLite and Shared Preferences
I think answer depends on how many places you want to save and what do you plan to do with them but I consider DB as hte best way to go.
With a DB you will be able to create queries to get only places you want and not load all places in a list and search in it.
To simplify DB creation (and use) you can try orm for Android like OrmLite and GreenDao. I think OrmLite is easier to use than GreenDao (but second one seems to have better performance...) and you can find multiple examples there.
In my opinion, SharedPreferences should only be used for saving user preferences data.