This question already has an answer here:
getContactsFromFirebase() method return an empty list
(1 answer)
Closed 4 years ago.
public class ShowBPGraphActivity extends AppCompatActivity {
public GraphView graphView;
public LineGraphSeries <DataPoint>lineGraphSeries;
public String systolicbp;
public String diastolicbp;
public String timebp;
public String datebp;
public DatabaseReference db;
public BPFragmentTable bpFragmentTable = new BPFragmentTable( );
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate( savedInstanceState );
setContentView( R.layout.activity_show_bp_graph );
ButterKnife.bind( this );
db = FirebaseDatabase.getInstance().getReference("bpfragmentTable");
final GraphView graph = (GraphView) findViewById( R.id.graphView );
final List<BPFragmentTable> bpFragmentTableList = new ArrayList<>();
//Get datasnapshot at your "users" root node
DatabaseReference ref = FirebaseDatabase.getInstance().getReference().child("bpfragmentTable");
ref.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
List<BPFragmentTable> bpfragmentTableList = new ArrayList<>();
for(DataSnapshot dataSnapshot1 :dataSnapshot.getChildren()){
BPFragmentTable bpfragmentTable = dataSnapshot1.getValue(BPFragmentTable.class);
systolic = bpfragmentTable.getSystolicbp();
diastolic = bpfragmentTable.getDiastolicbp();
date = bpfragmentTable.getDatebp();
time = bpfragmentTable.getTimebp();
//bpfragmentTable.setSystolicbp(systolic);
//bpfragmentTable.setDiastolicbp(diastolic);
//bpfragmentTable.setDatebp(date);
//bpfragmentTable.setTimebp(time);
bpfragmentTableList.add(bpfragmentTable);
// Toast.makeText(MainActivity.this,""+name,Toast.LENGTH_LONG).show();
}
#Override
public void onCancelled(DatabaseError databaseError) {
//handle databaseError
}
});
// please help me why i get null value in systolic diastolic date and time
System.out.println( "systolicbp" + systolicbp );
System.out.println( "diastolicbp" + diastolicbp );
System.out.println( "datebp" + datebp );
System.out.println( "timebp" + timebp );
try {
#SuppressLint("SimpleDateFormat") SimpleDateFormat formatter = new SimpleDateFormat("hh:mm a\nMMM dd yyyy");
dateValued = formatter.parse(datebp);
dateInMills = dateValued.getTime();
} catch (ParseException e) {
e.printStackTrace();
}
final long xlong = dateInMills;
final int ysystolicInt = Integer.parseInt( systolicbp );
final int ydiastolicInt = Integer.parseInt( diastolicbp );
this is the error in the picture
I want to get bpfragmentTable all values and store all values in the string variable and use that variable to draw a graph in the graph view. I want to get all values from the table-BPFragment table in the picture:
and this is the class of getter and setter of BPFragmentTable.class
public class BPFragmentTable {
public String bpid;
public String systolicbp;
public String diastolicbp;
public String datebp;
public String timebp;
public BPFragmentTable(){}
public BPFragmentTable(String bpid,String systolicbp,String diastolicbp,String datebp,String timebp) {
this.bpid = bpid;
this.systolicbp = systolicbp;
this.diastolicbp = diastolicbp;
this.datebp = datebp;
this.timebp = timebp;
}
public String getBpid() {
return bpid;
}
public void setBpid(String bpid) {
this.bpid = bpid;
}
public String getSystolicbp() {
return systolicbp;
}
public void setSystolicbp(String systolicbp) {
this.systolicbp = systolicbp;
}
public String getDiastolicbp() {
return diastolicbp;
}
public void setDiastolicbp(String diastolicbp) {
this.diastolicbp= diastolicbp;
}
public String getDatebp() {
return datebp;
}
public void setDatebp(String datebp) {
this.datebp= datebp;
}
public String getTimebp() {
return timebp;
}
public void setTimebp(String timebp) {
this.timebp= timebp;
}
}
Why do I get null object reference?
Data is loaded from Firebase asynchronously. By the time you call formatter.parse(datebp) the onDataChange method hasn't run yet, and datebp hasn't been set. You will need to move the parsing of the data into onDataChange:
DatabaseReference ref = FirebaseDatabase.getInstance().getReference().child("bpfragmentTable");
ref.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
List<BPFragmentTable> bpfragmentTableList = new ArrayList<>();
for(DataSnapshot dataSnapshot1 :dataSnapshot.getChildren()){
BPFragmentTable bpfragmentTable = dataSnapshot1.getValue(BPFragmentTable.class);
systolic = bpfragmentTable.getSystolicbp();
diastolic = bpfragmentTable.getDiastolicbp();
date = bpfragmentTable.getDatebp();
time = bpfragmentTable.getTimebp();
bpfragmentTableList.add(bpfragmentTable);
System.out.println( "systolicbp" + systolicbp );
System.out.println( "diastolicbp" + diastolicbp );
System.out.println( "datebp" + datebp );
System.out.println( "timebp" + timebp );
try {
#SuppressLint("SimpleDateFormat") SimpleDateFormat formatter = new SimpleDateFormat("hh:mm a\nMMM dd yyyy");
dateValued = formatter.parse(datebp);
dateInMills = dateValued.getTime();
} catch (ParseException e) {
e.printStackTrace();
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
throw databaseError.toException(); // don't ignore errors
}
});
This asynchronous nature is a common pitfall for developers new to Firebase. Since asynchronous APIs are extremely common in modern programming, I highly recommend you learn about them quickly. For some good introductory material, see:
getContactsFromFirebase() method return an empty list (which also shows how to use an interface to get the values out of onDataChange)
this blog post on asynchronous APIs
Setting Singleton property value in Firebase Listener (where I explained how in some cases you can get synchronous data loading, but usually can't)
Related
I don't remember what I am doing wrong because I have fixed this before.
What I am trying to do is retrieve the job post data from firebase and put it in my listview but when I do that, the job posts have duplicates. Any Idea on how to fix this?
I'll add the logs and code below.
here are the logs, I keep count of the logs with a log in the script "getting jobs count first count"
05-28 20:24:06.391 17592-17592/test.com.jobTestApp D/FindWorkFragment: getPhotos: getting photos
getPhotos: getting jobs count first count = 0
05-28 20:24:06.772 17592-17592/test.com.jobTestApp D/FindWorkFragment: onDataChange: getJOBS {job_headline=Website, date_posted=yesterday, user_country=United States, time_frame= 7 days, job_desc=Hello, fullname=Tom, category=Web Development, budget=30}
onDataChange: jobs count = 1
onDataChange: getJOBS {job_headline=Website, date_posted=today, user_country=United States, user_id=QkGIMPFXDoPfpnwnPileLRtyR243, time_frame=6 days, job_desc=stuff, fullname=Odi Ohn, category=Web Development, budget=24}
onDataChange: jobs count = 2
05-28 20:24:06.773 17592-17592/test.com.jobTestApp D/FindWorkFragment: onDataChange: getJOBS {job_headline=Website, date_posted=yesterday, user_country=United States, time_frame= 7 days, job_desc=Hello, fullname=Tom, category=Web Development, budget=30}
onDataChange: jobs count = 3
onDataChange: getJOBS {job_headline=Website, date_posted=today, user_country=United States, user_id=QkGIMPFXDoPfpnwnPileLRtyR243, time_frame=6 days, job_desc=stuff, fullname=Odi Ohn, category=Web Development, budget=24}
onDataChange: jobs count = 4
05-28 20:24:06.776 17592-17592/test.com.jobTestApp D/FindWorkFragment: onDataChange: jobs count = 4
Here is the code :
public class FindWorkFragment extends Fragment implements AdapterView.OnItemSelectedListener{
private static final String TAG = "FindWorkFragment";
private ImageView btnBack;
private FirebaseAuth mAuth;
private FirebaseAuth.AuthStateListener mAuthListener;
private FirebaseDatabase mFirebaseDatabase;
private DatabaseReference myRef;
private ArrayList<PostJob> mJobs;
private ArrayList<PostJob> mPaginatedPhotos;
private ArrayList<String> mJobsinCat;
private ListView mListView;
private JobFeedListAdapter mAdapter;
private int mResults;
private Spinner mSearchCat;
private String searchCat;
private ArrayAdapter<CharSequence> mSearchCategoryAdapter;
public static FindWorkFragment newInstance(int instance) {
Bundle args = new Bundle();
args.putInt("argsInstance", instance);
FindWorkFragment thirdFragment = new FindWorkFragment();
thirdFragment.setArguments(args);
return thirdFragment;
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_findwork, container, false);
final Fragment fragment = new FindWorkFragment();
mFirebaseDatabase = FirebaseDatabase.getInstance();
myRef = mFirebaseDatabase.getReference();
btnBack = (ImageView) view.findViewById(R.id.iv_back);
mSearchCat = (Spinner) view.findViewById(R.id.spSearchCat);
mSearchCategoryAdapter = ArrayAdapter.createFromResource(getActivity(), R.array.job_categories, android.R.layout.simple_spinner_item);
mSearchCategoryAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
mSearchCat.setAdapter(mSearchCategoryAdapter);
mSearchCat.setOnItemSelectedListener(this);
mListView = (ListView) view.findViewById(R.id.joblistview);
mJobsinCat = new ArrayList<>();
mJobs = new ArrayList<>();
getJobsinCat();
btnBack.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
FragmentTransaction ft = getActivity().getSupportFragmentManager().beginTransaction();
ft.replace(R.id.main_frag_container, new HomeDashboardFragment());
ft.commit();
}
});
return view;
}
private void getJobsinCat(){
Log.d(TAG, "getFollowing: searching for following");
String key = myRef.child("Web Development").push().getKey();
DatabaseReference reference = FirebaseDatabase.getInstance().getReference();
Query query = reference
.child(getString(R.string.dbname_jobs))
.child("United States")
.child("Web Development");
query.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for(DataSnapshot singleSnapshot : dataSnapshot.getChildren()){
Log.d(TAG, "onDataChange: found user: " +
singleSnapshot.getKey());
mJobsinCat.add(singleSnapshot.getKey().toString());
}
//mJobsinCat.add(FirebaseAuth.getInstance().getCurrentUser().getUid());
//get the photos
getPhotos();
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
private void getPhotos(){
Log.d(TAG, "getPhotos: getting photos");
Log.d(TAG, "getPhotos: getting jobs count first count = " + mJobs.size() );
DatabaseReference reference = FirebaseDatabase.getInstance().getReference();
for(int i = 0; i < mJobsinCat.size(); i++){
final int count = i;
Query query = reference
.child(getString(R.string.dbname_jobs))
.child("United States")
.child("Web Development")
.orderByKey();
query.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for(DataSnapshot singleSnapshot : dataSnapshot.getChildren()){
PostJob job = new PostJob();
Log.d(TAG, "onDataChange: getJOBS " + singleSnapshot.getValue());
Map<String, Object> objectMap = (HashMap<String, Object>) singleSnapshot.getValue();
//job.setUser_country(objectMap.get("user_country").toString());
job.setJob_headline(objectMap.get("job_headline").toString());
job.setJob_desc(objectMap.get("job_desc").toString());
job.setBudget(objectMap.get("budget").toString());
job.setTime_frame(objectMap.get("time_frame").toString());
//job.setTags(objectMap.get(getString(R.string.field_tags)).toString());
//job.setPhoto_id(objectMap.get(getString(R.string.field_photo_id)).toString());
//job.setUser_id(objectMap.get(getString(R.string.field_user_id)).toString());
//job.setDate_posted(objectMap.get("date_posted").toString());
//job.setImage_path(objectMap.get(getString(R.string.field_image_path)).toString());
/*
// soon going to be the proposals
ArrayList<Comment> comments = new ArrayList<Comment>();
for (DataSnapshot dSnapshot : singleSnapshot
.child(getString(R.string.field_comments)).getChildren()){
Comment comment = new Comment();
comment.setUser_id(dSnapshot.getValue(Comment.class).getUser_id());
comment.setComment(dSnapshot.getValue(Comment.class).getComment());
comment.setDate_created(dSnapshot.getValue(Comment.class).getDate_created());
comments.add(comment);
}
photo.setComments(comments);*/
mJobs.add(job);
}
if(count >= mJobsinCat.size() -1){
//display our photos
displayPhotos();
Log.d(TAG, "onDataChange: jobs count = " + mJobs.size());
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
}
private void displayPhotos(){
mPaginatedPhotos = new ArrayList<>();
if(mJobs != null){
try{
/*
Collections.sort(mJobs, new Comparator<PostJob>() {
#Override
public int compare(PostJob o1, PostJob o2) {
return o2.getDate_posted().compareTo(o1.getDate_posted());
}
});*/
int iterations = mJobs.size();
if(iterations > 10){
iterations = 10;
}
mResults = 10;
for(int i = 0; i < iterations; i++){
mPaginatedPhotos.add(mJobs.get(i));
}
mAdapter = new JobFeedListAdapter(getActivity(), R.layout.layout_jobfeed_listitem, mPaginatedPhotos);
mListView.setAdapter(mAdapter);
}catch (NullPointerException e){
Log.e(TAG, "displayPhotos: NullPointerException: " + e.getMessage() );
}catch (IndexOutOfBoundsException e){
Log.e(TAG, "displayPhotos: IndexOutOfBoundsException: " + e.getMessage() );
}
}
}
public void displayMorePhotos(){
Log.d(TAG, "displayMorePhotos: displaying more photos");
try{
if(mJobs.size() > mResults && mJobs.size() > 0){
int iterations;
if(mJobs.size() > (mResults + 10)){
Log.d(TAG, "displayMorePhotos: there are greater than 10 more photos");
iterations = 10;
}else{
Log.d(TAG, "displayMorePhotos: there is less than 10 more photos");
iterations = mJobs.size() - mResults;
}
//add the new photos to the paginated results
for(int i = mResults; i < mResults + iterations; i++){
mPaginatedPhotos.add(mJobs.get(i));
}
mResults = mResults + iterations;
mAdapter.notifyDataSetChanged();
}
}catch (NullPointerException e){
Log.e(TAG, "displayPhotos: NullPointerException: " + e.getMessage() );
}catch (IndexOutOfBoundsException e){
Log.e(TAG, "displayPhotos: IndexOutOfBoundsException: " + e.getMessage() );
}
}
#Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
searchCat = parent.getItemAtPosition(position).toString();
}
#Override
public void onNothingSelected(AdapterView<?> parent) {
}
}
See the getPhotos() you have added query.addListenerForSingleValueEvent in for loop so it will executed multiple time based on mJobsinCat.size(),pull it out from loop for call it single time
private void getPhotos(){
Log.d(TAG, "getPhotos: getting photos");
Log.d(TAG, "getPhotos: getting jobs count first count = " + mJobs.size() );
DatabaseReference reference = FirebaseDatabase.getInstance().getReference();
Query query = reference
.child(getString(R.string.dbname_jobs))
.child("United States")
.child("Web Development")
.orderByKey();
query.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for(DataSnapshot singleSnapshot : dataSnapshot.getChildren()){
PostJob job = new PostJob();
Log.d(TAG, "onDataChange: getJOBS " + singleSnapshot.getValue());
Map<String, Object> objectMap = (HashMap<String, Object>) singleSnapshot.getValue();
//job.setUser_country(objectMap.get("user_country").toString());
job.setJob_headline(objectMap.get("job_headline").toString());
job.setJob_desc(objectMap.get("job_desc").toString());
job.setBudget(objectMap.get("budget").toString());
job.setTime_frame(objectMap.get("time_frame").toString());
//job.setTags(objectMap.get(getString(R.string.field_tags)).toString());
//job.setPhoto_id(objectMap.get(getString(R.string.field_photo_id)).toString());
//job.setUser_id(objectMap.get(getString(R.string.field_user_id)).toString());
//job.setDate_posted(objectMap.get("date_posted").toString());
//job.setImage_path(objectMap.get(getString(R.string.field_image_path)).toString());
/*
// soon going to be the proposals
ArrayList<Comment> comments = new ArrayList<Comment>();
for (DataSnapshot dSnapshot : singleSnapshot
.child(getString(R.string.field_comments)).getChildren()){
Comment comment = new Comment();
comment.setUser_id(dSnapshot.getValue(Comment.class).getUser_id());
comment.setComment(dSnapshot.getValue(Comment.class).getComment());
comment.setDate_created(dSnapshot.getValue(Comment.class).getDate_created());
comments.add(comment);
}
photo.setComments(comments);*/
mJobs.add(job);
}
Log.d(TAG, "onDataChange: jobs count = " + mJobs.size());
if( mJobs.size()>0){
//display our photos
displayPhotos();
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
I'm new to Android and Firebase environment but I'm working on it !
I'm working on an Android app and I need to read some values related to a child within a Firebase database. After this initial read, I need to modify / update these values and write them to the same child.
public class MainActivity extends Activity {
public static class Shoe extends JSONObject {
private String name;
private int size;
Shoe(){
// Default constructor required for calls to
// DataSnapshot.getValue(Shoe.class)
}
Shoe( String nm, int sz) { this.name = nm; this.size = sz; }
public int getSize() { return this.size; }
public void setSize(int sz) { this.size = sz; }
public String getName() { return this.name;}
public void setName(String nm) {this.name = nm; }
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.d(TAG, "onCreate");
// Write a message to the database
FirebaseDatabase database = FirebaseDatabase.getInstance();
database.setPersistenceEnabled(true);
DatabaseReference myRefTarget = database.getReference("target");
Shoe obj1 = new Shoe("item ID 1", 99);
Shoe obj2 = new Shoe("item ID 2", 1000);
final Shoe obj_old = new Shoe();
Shoe obj_new = new Shoe();
DatabaseReference myRefDeviceA = myRefTarget.child("deviceA").getRef();
myRefDeviceA.keepSynced(true);
myRefDeviceA.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot)
{
obj_old.setName( dataSnapshot.getValue(Shoe.class).getName());
obj_old.setSize( dataSnapshot.getValue(Shoe.class).getSize());
Log.d(TAG_CLOUD, "from onDataChange: deviceA = " + obj_old.getName() + ", " + obj_old.getSize());
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
// HERE
Log.d(TAG_CLOUD, "Name = " + obj_old.getName() + ", Size = " + obj_old.getSize());
}
the issue I got is that the read operation is asynchronously done..
D/FROM CLOUD: Name = null, Size = 0
D/FROM CLOUD: from onDataChange: deviceA = item ID 1, 99
how can adapt / modify the source code in such way that first "read" to give me values different than null and '0' ? "HERE" line
eg.
Name = item ID 1 Size = 99
Thank you.
You don't suppose to perform networking operations on the UI thread.
If you want to display the data in the activity, you should show a loading dialog in the onCreate method, and then after fetching the data close the dialog and update the activity view
I have this structure in Firebase
"shared_items" : {
"-KgGHdgE3L_m6ppVgn99" : {
"_id" : 14,
"added_date" : "08/Mar/2017",
"shared_with_emails" : "{\"abc#abc*com\":{\"name\":\"Customer Care\"},\"xyz#xyz*com\":{\"name\":\"Customercare\"}}",
"user_display_name" : "Logged in user",
"users_email" : "loggedinUser#gmail.com"
}
}
My questions:
When I am saving JSON data in "shared_with_emails" key then my data is automatically appended with "\" slash. Is this normal or I am doing something wrong here?
How can I get entire node based on email Ids present in this JSON object.
Function to create JSON objects from provided contacts..
public class JsonUtils {
final private static String TAG = JsonUtils.class.getSimpleName();
public String ContactsToJson() {
ArrayList<ContactsModel> listOfContacts = new ArrayList<>();
listOfContacts.add(new ContactsModel("abc#gmail.com", "abc"));
listOfContacts.add(new ContactsModel("xyz#gmail.com", "xyz"));
listOfContacts.add(new ContactsModel("mnop#yahoo.com", "mnop"));
JSONObject jsonObjectChild;
JSONObject jsonObjectRoot = new JSONObject();
for (int i = 0; i < listOfContacts.size(); i++) {
ContactsModel model = (ContactsModel) listOfContacts.get(i);
try {
jsonObjectChild = new JSONObject();
jsonObjectChild.put("name", model.getContactName());
jsonObjectRoot.put(model.getContactMail(), jsonObjectChild);
} catch (JSONException e){
e.printStackTrace();
}
}
System.out.println(jsonObjectRoot.toString());
return jsonObjectRoot.toString();
}
public class ContactsModel {
private int id;
private String mContactName;
private String mContactMail;
public ContactsModel(String contactMail, String contactName) {
this.mContactName = contactName;
this.mContactMail = contactMail;
}
public String getContactName() {
return mContactName;
}
public String getContactMail() {
return mContactMail;
}
}
}
Json data on Firebase
You can use ArrayList<String> to have multiple emails saved under shared_with_email. When you retrieve your data, save it inside an object and search whether the object contains the email.
ArrayList<String> keys = new ArrayList<>;
rootRef.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for(Datasnapshot snap:datasnapshot.getChildren()){
ArrayList<yourObject> current = snap.getValue();
if (current.shared_with_email.contains(someEmail)){
keys.add = snap.getKey(); //Check this, all we need is the key of our object. kd47qjB.... in this case
}
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
Once you have all the keys. Add listeners.
for(String key: keys){
rootRef.child(key).addValueEventListener(new ValueEventListener(){
#override
public void onDataChange(Datasnapshot datasnapshot){
//You successfully added listener to the key where user has its email.
//Do your work here.
}
});
}
You will have to create a class yourObject which resembles the data in your firebase database.
in my android application I create an activity which contains a ListView which is populated with data from Firebase Database.
The JSON Tree of the structure of the database is the following:
{
"companies" : {
"companyX" : {
"address" : "50th avenue, NY",
"name" : "Spare-Tools Ltd."
},
"companyZ" : {
"address" : "50th Broadway, NY",
"name" : "Burgers and Burgers"
}
},
"company-requests" : {
"companyX" : {
"req1" : true
"req2" : true
}
},
"requests" : {
"req1" : {
"destination" : "Upper Tooting 122, Bronx",
"origin" : "Philadelphia",
"time" : "1473593287",
...
}
"req2" : {
...
}
}
}
I want to populate the ListView with the list of requests from the requests node. But I first need to know all requests that belong to a specific company so I first go to the company-requests node and retrieve all the request-keys belonging to the specific company.
The problem I am facing is that the ListView is created before the final data from the database arrived:
public class RequestsListActivity extends AppCompatActivity {
private ListView rListView;
DatabaseReference rootNode = FirebaseDatabase.getInstance().getReference();
#Override
protected void onCreate(Bundle savedInstanceState) {
...
rListView = (ListView) findViewById(R.id.result_list_view);
//First I retrieve all the requests of a specific company
DatabaseReference companyRequests = rootNode.child("company-requests/companyX");
companyRequests.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
//Then I retrieve all the keys of these requests
...
while (iterator.hasNext()) {
String key = iterator.next().getKey();
//For each key I retrieve its details from the requests node
DatabaseReference currRequest = rootNode.child("requests/" + key);
currRequest.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
String time;
time = (String) dataSnapshot.child("time").getValue();
Request request = new Request(time);
allRequests.add(request);
}
...onCancelled...
});
}
//THIS CODE IS EXECUTED TO EARLY: BEFORE WE HAVE ANY DATA FROM FIREBASE
RequestAdapter adapter = new RequestAdapter(RequestsListActivity.this, allRequests);
rListView.setAdapter(adapter);
}
...onCancelled...
});
}
}
How can I insert a wait (spinner?) that waits until the values are loaded from Firebase?
You can use a simple counter to keep track of the number of pending loads:
companyRequests.addValueEventListener(new ValueEventListener() {
public void onDataChange(DataSnapshot dataSnapshot) {
// at the start we need to still load all children
final long[] pendingLoadCount = { dataSnapshot.getChildrenCount() };
for (DataSnapshot childSnapshot: dataSnapshot.getChildren()) {
//For each key I retrieve its details from the requests node
DatabaseReference currRequest = rootNode.child("requests/" + childSnapshot.getKey());
currRequest.addListenerForSingleValueEvent(new ValueEventListener() {
public void onDataChange(DataSnapshot dataSnapshot) {
String time;
time = (String) dataSnapshot.child("time").getValue();
Request request = new Request(time);
allRequests.add(request);
// we loaded a child, check if we're done
pendingLoadCount[0] = pendingLoadCount[0] - 1;
if (pendingLoadCount[0] == 0) {
RequestAdapter adapter = new RequestAdapter(RequestsListActivity.this, allRequests);
rListView.setAdapter(adapter);
}
}
...onCancelled...
});
}
}
});
I solved this using a java.util.concurrent.CountDownLatch:
In this example, replace EquityTotalListener with your implementation of ValueEventListener.
private void recalculate() {
final AtomicLong sumUpAll = new AtomicLong();
final CountDownLatch cnt = new CountDownLatch(mapUid2GeoLocation.keySet().size());
for (final String uid : mapUid2GeoLocation.keySet()) {
EquityTotalListener el = mapUid2EquityListener.get(uid);
if (el != null) {
if (logger.isDebugEnabled()) {
logger.debug("Listener for " + uid + " already set up");
cnt.countDown();
}
} else {
el = new EquityTotalListener(database.getDatabase(), uid) {
#Override
public void onCancelled(final DatabaseError databaseError) {
super.onCancelled(databaseError);
cnt.countDown();
}
#Override
protected void valueChanged(final String key, final Object value) {
if (value != null) {
sumUpAll.getAndAdd(Long.parseLong(value.toString()));
cnt.countDown();
}
};
}.attach();
mapUid2EquityListener.put(uid, el);
}
}
if (logger.isDebugEnabled()) {
logger.debug("Waitung for countdown..");
}
try {
final boolean allGood = cnt.await(10, TimeUnit.SECONDS);
if (allGood) {
if (logger.isDebugEnabled()) {
logger.debug("Done waiting, " + uid + " owns " + sumUpAll.get() + " equity");
}
} else {
if (logger.isWarnEnabled()) {
logger.warn("Waiting for read operations ran into timeout");
}
}
} catch (final InterruptedException e) {
if (logger.isErrorEnabled()) {
logger.error(e.getLocalizedMessage(), e);
}
}
}
I have a RideList class that is called from an Activity class that retrieves data from a Firebase database. However, when I debug my program the code within my addValueEventListener is never being reached.
public class RideList {
private ArrayList<Ride> listofRides;
public Firebase myFirebase = new Firebase("https://luminous-torch-1510.firebaseio.com/rides");
Context context;
public RideList(Context context) {
this.context = context;
this.listofRides = new ArrayList <Ride>();
}
public ArrayList<Ride> getRides() {
Firebase.setAndroidContext(context);
// Attach an listener to read the data at our rides reference
Query queryRef = myFirebase.orderByChild("timePosted");
try {
queryRef.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot snapshot) {
System.out.println("There are " + snapshot.getChildrenCount() + " rides");
for (DataSnapshot postSnapshot : snapshot.getChildren()) {
String rideString = postSnapshot.getValue().toString();
String[] rideA = rideString.split(" ");
String value;
for (int i = 0; i < rideA.length - 1; i++) {
rideA[i] = rideA[i].substring(rideA[i].indexOf("=") + 1);
rideA[i] = rideA[i].substring(0, rideA[i].indexOf(","));
}
rideA[rideA.length - 1] = rideA[rideA.length - 1].substring(rideA[rideA.length - 1].indexOf("=") + 1);
rideA[rideA.length - 1] = rideA[rideA.length - 1].substring(0, rideA[rideA.length - 1].indexOf("}"));
double numOfPassengers = Double.valueOf(rideA[6]);
double fare = Double.valueOf(rideA[4]);
double distance = Double.valueOf(rideA[3]);
String origin = rideA[7];
String destination = rideA[2];
double maxPassengers = Double.valueOf(rideA[5]);
String departTime = rideA[1];
String arrivalTime = rideA[0];
String timePosted = rideA[8];
String title = rideA[9];
String type1 = rideA[10];
boolean type;
if (type1.equals("offer"))
type = false;
else
type = true;
Ride ride = new Ride(numOfPassengers, fare, distance, origin, destination, maxPassengers, departTime, arrivalTime,
timePosted, title, type);
listofRides.add(ride);
}
}
#Override
public void onCancelled(FirebaseError firebaseError) {
System.out.println("The read failed: " + firebaseError.getMessage());
}
});
Thread.sleep(2000);
} catch (InterruptedException e) {
return null;
}
return listofRides;
}
}
This code is being called from an OnCreate function of an Activity class. Any idea on why the listener code is never being entered/executed?
Edit: Here is the code on how this function is being called in the activity class.
list = (ListView) findViewById(R.id.showrides_listView);
Firebase.setAndroidContext(this);
RideList rl = new RideList(this);
ArrayList arrayList = rl.getRides();
// Adapter: You need three parameters 'the context, id of the layout (it will be where the data is shown),
// and the array that contains the data
ArrayAdapter adapter = new ArrayAdapter<Ride>(getApplicationContext(), android.R.layout.simple_spinner_item, arrayList){
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View view = super.getView(position, convertView, parent);
TextView text = (TextView) view.findViewById(android.R.id.text1);
text.setTextColor(Color.BLACK);
return view;
}
};
// Here, you set the data in your ListView
list.setAdapter(adapter);
adapter.notifyDataSetChanged();
FloatingActionButton myFab = (FloatingActionButton) findViewById(R.id.showrides_fab);
myFab.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
startCreateRideActivity();
}
});
Your data is being loaded asynchronously (and after that continuously synchronized) from Firebase. Putting a Thread.sleep() in there is not going to change that fact.
You can easily see what happens if you add a few log statements:
public ArrayList<Ride> getRides() {
Query queryRef = myFirebase.orderByChild("timePosted");
try {
System.out.println("Adding listener");
queryRef.addValueEventListener(new ValueEventListener() {
public void onDataChange(DataSnapshot snapshot) {
// THIS CODE IS CALLED ASYNCHRONOUSLY
System.out.println("Got data from Firebase");
}
public void onCancelled(FirebaseError firebaseError) {
}
});
System.out.println("Starting sleep");
Thread.sleep(2000);
} catch (InterruptedException e) {
return null;
}
System.out.println("Returning rides");
return listofRides;
}
The output is likely:
Adding listener
Starting sleep
Returning rides
Got data from Firebase
You're trying to make an asynchronous process synchronous, which is a recipe for headaches and a bad user experience. Instead of writing up a solution here, I'll link to an answer I wrote 15 minutes ago to the same problem: Retrieving ArrayList<Object> from FireBase inner class