Changing JavaFX nodes in Firebase onDataChange not working - firebase

I'm working on a JavaFX admin application that works with Firebase Realtime Database. I've created a ValueEventListener that acquires the data I need in onDataChange. With this data I want to call a call a method that does something with this data. The problem I ran into is that changing JavaFX elements from inside this onDataChange method isn't working at all.
I've tried narrowing the problem down by putting everything in one class and put all the functionality in the onDataChange method, but that wouldn't work either.
What's confusing me the most about this is that reading these elements is working just fine, while changing them doesn't result in anything. It does work when I execute this code from outside onDataChange.
Code in database helper class:
public void startDropsListener() {
dropsRef.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
OverviewController.getInstance().changeNodes();
}
#Override
public void onCancelled(DatabaseError databaseError) {
System.out.println("Reading from database failed: " + databaseError.getCode());
}
});
}
Method for changing nodes:
public void changeNodes() {
System.out.println(title.getText()); // This does return the node's text.
title.setText("New title"); // Does not update the node's text.
}
UPDATE:
Printing the title after changing seems to be working, so the value appears to update despite it not showing. Here's the instance related code in case that might be the issue:
private static OverviewController instance;
public OverviewController() {
instance = this;
}
public static OverviewController getInstance() {
if(instance == null){
instance = new OverviewController();
}
return instance;
}

Don't make the controller a singleton.
and do like this...
public class OverviewController implements Initializable{
#FXML
public Label label;
#Override
public void initialize(URL location, ResourceBundle bundle){
DatabaseReference dropsRef = FirbaseDatabase.DatabaseReference("Node");
dropsRef.addValueEventListener(valueEventListener);
}
ValueEventListener valueEventListener = new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
Plateform.runLater(()->label.setText(dataSnashot.getValue(SomeClass.class).getLabel());
}
#Override
public void onCancelled(DatabaseError databaseError) {
System.out.println("Reading from database failed: " + databaseError.getCode());
}
});
}

Related

How do I retrieve a list of all children in a Firebase realtime database?

The structure of my Firebase database is shown below. I want to make a list of all the Rooms in Android Studio. In other words, I need an array of [Room1, Room2, ...] for use in a spinner. How can I do this?
What you can do is loop over all the children of your database and add them to an ArrayList and then use an array adapter to display the list.
What I am saying, looks something like this in code:
rootRef.child("Rooms").addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
for (DataSnapshot ds : dataSnapshot.getChildren()) {
array.add(ds.child("Users").child("UserID").getValue(String.class));
}
ArrayAdapter adapter = new ArrayAdapter(YourActivity.this, android.R.layout.simple_list_item_1, array);
listView.setAdapter(adapter);
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
// Do something for errors too
}
});

Subscriber only called once in Rx android and Firebase Realtime-Database Implementation

I am new to android development.
Currently I am implementing Firebase Realtime-Database with Rx android.
Here the Rx Android is used to listen to any changes happened in a particular child node inside the Realtime-Database, retrieve a List of Java class object in it and then return the List so that it can be used by another class.
Below are my code snippets.
1) Here is a class that do basic Database operation such as read, write, update and delete, right now I'm only showing the read operation.
public class FirebaseDatabaseLayer {
private DatabaseReference databaseReference = FirebaseDatabase
.getInstance().getReference();
private List<TodoComponentFirebase> todoComponentFirebases = new ArrayList<>();
private FirebaseUser user;
public Observable<List<TodoComponentFirebase>> readModelFirebase() {
return Observable.create(new Observable.OnSubscribe<List<TodoComponentFirebase>>() {
#Override
public void call(final Subscriber<? super List<TodoComponentFirebase>> subscriber) {
user = FirebaseAuth.getInstance().getCurrentUser();
databaseReference.child(user.getUid())
.addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
for (DataSnapshot todoComponentSnapshot: dataSnapshot.getChildren()) {
TodoComponentFirebase todoComponentFirebase = todoComponentSnapshot.getValue(TodoComponentFirebase.class);
todoComponentFirebases.add(todoComponentFirebase);
}
subscriber.onNext(todoComponentFirebases);
subscriber.onCompleted();
}
#Override
public void onChildChanged(DataSnapshot dataSnapshot, String s) {
for (DataSnapshot todoComponentSnapshot: dataSnapshot.getChildren()) {
TodoComponentFirebase todoComponentFirebase = todoComponentSnapshot.getValue(TodoComponentFirebase.class);
todoComponentFirebases.add(todoComponentFirebase);
}
subscriber.onNext(todoComponentFirebases);
subscriber.onCompleted();
}
#Override
public void onChildRemoved(DataSnapshot dataSnapshot) {
}
#Override
public void onChildMoved(DataSnapshot dataSnapshot, String s) {
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
});
}
2) Here is class which has a subscriber that listening to the Observable defined in the class in number 1) inside readModelFirebase method
public class Presenter {
private FirebaseDatabaseLayer firebaseDatabaseLayer;
private Subscription readSubscriber = null;
public void readFirebaseModel() {
readSubscriber = firebaseDatabaseLayer
.readModelFirebase()
.observeOn(AndroidSchedulers.mainThread())
.subscribeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<List<TodoComponentFirebase>>() {
#Override
public void onCompleted() {
}
#Override
public void onError(Throwable e) {
}
#Override
public void onNext (List<TodoComponentFirebase> todoComponentFirebases) {
mainView.getFirebaseData(todoComponentFirebases);
}
});
}
}
Here the 2) class pass the List of TodoComponentFirebase to the parameter of mainView.getFirebaseData method (I'm not showing concrete implementation of this method here). The idea here is that the mainView.getFirebaseData method will get a List of TodoComponentObject saved in Firebase Database everytime there's change happened in the respective child node.
MainView class is an AppCompatActivity class, the readFirebaseMethod() inside Presenter class is being called in onCreate method of the MainView class, this serve as subscription initialisation.
At the first time initialization of MainView class, the onNext inside readFirebaseModel() is executed, the data being retrieved seamlessly.
However after that there's no execution on that onNext method even though there's changes occur in Child Node which is defined in the 1) class.
I don't understand why the subscription is not working even though there's changes happen in the child node, it only worked the time it is being initialised. Is there anything missed in my Rx usage ?
Thanks
try remove the
subscriber.onCompleted();
I think when you call the onCompleted() subscriber will end up and not called again after any child event on firebase.

Refresh recyclerView with new data Retrofit

I am using Retrofit 2.0 to retrieve data from my api and using a recyclerView to display it.
My main activity has a tab layout and one of those tabs has the recyclerView and the fragment class for that tab is being used to retrieve the data and update the layout.
In my main layout I have a fab which makes a post (all posts are being retrieved in fragment class) and this fab has it's function of making the post in main activity.
So how can I refresh the layout when the fab's function is over and the post is successfully saved in my database?
Basically
User clicks fab > Makes his post > Alert dialog closes > recyclerView should be refreshed with new data added.
My Fragment Class :
public class PostsRecentTab extends Fragment {
private static final String TAG = MainActivity.class.getSimpleName();
private RecyclerView feedView;
private ProgressDialog pDialog = MainActivity.pDialog;
LinearLayoutManager layoutManager;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
final View v = inflater.inflate(R.layout.tab_recent_posts, container, false);
pDialog.setCancelable(false);
layoutManager = new LinearLayoutManager(this.getContext());
feedView = (RecyclerView) v.findViewById(R.id.feedView);
requestData();
return v;
}
public void requestData() {
SocialHubAPI apiService = ApiClient.getClient().create(SocialHubAPI.class);
pDialog.setMessage("Refreshing...");
showDialog();
Call<StatusResponse> call = apiService.getStatuses();
call.enqueue(new Callback<StatusResponse>() {
#Override
public void onResponse(Call<StatusResponse> call, Response<StatusResponse> response) {
int statusCode = response.code();
List<Status> statuses = response.body().getStatuses();
Log.d(TAG, "Status Code: " + statusCode);
hideDialog();
updateView(statuses);
}
#Override
public void onFailure(Call<StatusResponse> call, Throwable t) {
Log.e(TAG, t.toString());
}
});
}
private void updateView(List<Status> statuses) {
StatusesAdapter adapter = new StatusesAdapter(statuses, R.layout.feed_item, getContext());
feedView.setLayoutManager(layoutManager);
feedView.setAdapter(adapter);
}
private void showDialog() {
if (!pDialog.isShowing())
pDialog.show();
}
private void hideDialog() {
if (pDialog.isShowing())
pDialog.dismiss();
}
}
My Fab On Click :
FloatingActionButton postStatus = (FloatingActionButton) findViewById(R.id.postStatus);
postStatus.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(final View view) {
AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
builder.setTitle("Post Status");
// Set up the input
final EditText input = new EditText(MainActivity.this);
// Specify the type of input expected; this, for example, sets the input as a password, and will mask the text
input.setInputType(InputType.TYPE_CLASS_TEXT);
builder.setView(input);
// Set up the buttons
builder.setPositiveButton("Post", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
postText = input.getText().toString();
processPost(postText, sessionManager.getToken());
Snackbar.make(view, "Status posted!", Snackbar.LENGTH_LONG).show();
}
});
builder.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
dialog.cancel();
}
});
builder.show();
}
});
Fab onClick calls this method :
protected void processPost(String postText, String token) {
SocialHubAPI apiService = ApiClient.getClient().create(SocialHubAPI.class);
pDialog.setMessage("Posting...");
showDialog();
final PostRequest postRequest = new PostRequest();
postRequest.setStatus(postText);
Call<PostResponse> call = apiService.postStatus(postRequest, token);
call.enqueue(new Callback<PostResponse>() {
#Override
public void onResponse(Call<PostResponse> call, Response<PostResponse> response) {
hideDialog();
Toast.makeText(getApplicationContext(), "Status Posted Successfully!", Toast.LENGTH_LONG).show();
}
#Override
public void onFailure(Call<PostResponse> call, Throwable t) {
Log.e(TAG, t.toString());
}
});
}
You should invalidate your list in updateView(List<Status> statuses) instead of setting the adapter again. Instantiate adapter only in onCreate().
This function should be like this:
adapter.addNewStatutes(statuses)
in Adapter class
public void addNewStatutes(List<Status> statuses)
{
this.statuses.addAll(statuses);
notifyDataSetChanged();
}
Also in onResponse use EventBus or Rx, because your view can be destroyed and this method can crash your app.
Added notifyDataSetChanged as per docs.

How to put addChildEventListener on multiple child dynamically in Firebase?

I want to add multiple listener on child added dynamically.
A-1,2,3 as child having messages.
B-2,3 as child having messages.
C-1,2 as child having messages.
D-1 as child having messages.
So want to monitor A, B and D for 1 message when they get added and others if they get added with 1.
Please help me i am stuck with this issue.
status.addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
DataProvider chat= dataSnapshot.getValue(DataProvider.class);
if(!chat.getStatus().isEmpty()) {
textView.setText(chat.getStatus());
}
}
#Override
public void onChildChanged(DataSnapshot dataSnapshot, String s) {
}
#Override
public void onChildRemoved(DataSnapshot dataSnapshot) {
}
#Override
public void onChildMoved(DataSnapshot dataSnapshot, String s) {
}
This is the code which helps me to find out A,B,C but i am not able to monitor its children and grand children individually.

Disable ContextMenu with dependency to TreeTableView selection

I have a TreeTableView which allows multiselection. I got a ContextMenu for editing or deleting that selected items.
Delete and edit should only be enabled if there is at least one selection.
final BooleanBinding isTableSelectionEmpty = Bindings.isEmpty(this.table.getSelectionModel().getSelectedItems());
this.menuItemDelete.disableProperty().bind(isTableSelectionEmpty);
That is working as expected.
But now I have dependencies on different values of the selected rows. Like for example that the row is system-mandatory and should not be deleted.
I tried the following but it is not working
final BooleanBinding invalidSelection = Bindings.and(Bindings.isEmpty(tableSelection),
Bindings.isNotEmpty(tableSelection.filtered(item -> {
this.logger.trace("filtering :" + item);
return item.getValue().getSystemProperty().get();
})));
this.menuItemDelete.disableProperty().bind(invalidSelection);
Not even the debug-trace is printed and the value of the binding is always false (thus enabling the menu item). Now I am a bit lost. Where is my mistake?
FilteredList relies on a correct ListIterator, but currently there is a bug in the ListIterator the selectedItems list in MultipleSelectionModelBase. This prevents the filtering to properly work. To fix this you could create a ObservableList implementation delegating everything but the ListIterator creation to a source ObservableList. Most IDEs have a functionality to generate this kind of methods automatically, reducing the amount of work to a minimum (e.g.in NetBeans: Generate -> Delegate Method).
public class ObservableListIteratorFix<T> implements ObservableList<T> {
private final ObservableList<T> list;
public ObservableListIteratorFix(ObservableList<T> list) {
this.list = list;
}
#Override
public void addListener(ListChangeListener<? super T> listener) {
list.addListener(listener);
}
#Override
public void removeListener(ListChangeListener<? super T> listener) {
list.removeListener(listener);
}
#Override
public boolean addAll(T... elements) {
return list.addAll(elements);
}
...
private class CustomListIterator implements ListIterator<T> {
private final ListIterator<T> iterator;
private int index;
public CustomListIterator(int index) {
this.iterator = list.listIterator(index);
this.index = index;
}
#Override
public boolean hasNext() {
return iterator.hasNext();
}
#Override
public T next() {
T t = iterator.next();
index++;
return t;
}
#Override
public boolean hasPrevious() {
return iterator.hasPrevious();
}
#Override
public T previous() {
T t = iterator.previous();
index--;
return t;
}
#Override
public int nextIndex() {
return index;
}
#Override
public int previousIndex() {
return index-1;
}
#Override
public void remove() {
iterator.remove();
}
#Override
public void set(T e) {
iterator.set(e);
}
#Override
public void add(T e) {
iterator.add(e);
}
#Override
public void forEachRemaining(Consumer<? super T> action) {
iterator.forEachRemaining(action);
}
}
#Override
public ListIterator<T> listIterator() {
return listIterator(0);
}
#Override
public ListIterator<T> listIterator(int index) {
return new CustomListIterator(index);
}
#Override
public FilteredList<T> filtered(Predicate<T> predicate) {
return new FilteredList<>(this, predicate);
}
...
This allows you to use the class as wrapper the selectedItems which should fix the filtering...
new ObservableListIteratorFix<>(tableSelection).filtered(...)

Resources