How to improve Flowable<Object> data reading from Firebase db using RxJava 2? - firebase

I have Recycler Viewer that displays data from Fire Base db however initial List contains around 4k elements. I am trying to show only first 15 elements instead of waiting for full list to be loaded however not sure how to do it.
I am trying to take(x) elements via Subscriber however it does not improve reading performance (it still waits for 4k elements from Firebase DB). How to speed up this?
Subscriber - Presenter
#Override
public void onBindViewHolder(final ListContentFragment.ViewHolder holder, int position) {
modelInterface.getDataFromFireBase("FinalSymbols")
.take(15)
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Consumer<DataSnapshot>() {
#Override
public void accept(DataSnapshot dataFromDb) throws Exception {
//update TextView inside Recycler Viewer
holder.name.setText(dataFromDb.child(String.valueOf(holder.getAdapterPosition())).child("description").getValue().toString());
holder.description.setText(dataFromDb.child(String.valueOf(holder.getAdapterPosition())).child("categoryName").getValue().toString());
}
}
);
}
Publisher - source of Data (FireBase db)
#Override
public Flowable<DataSnapshot> getDataFromFireBase(final String childName) {
return Flowable.create(new FlowableOnSubscribe<DataSnapshot>() {
#Override
public void subscribe(final FlowableEmitter<DataSnapshot> e) throws Exception {
databaseReference.child(childName).addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
e.onNext(dataSnapshot);
e.onComplete();
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
}, BackpressureStrategy.BUFFER);

I believe you need to use the method limitToFirst().
Something like this:
#Override
public Flowable<DataSnapshot> getDataFromFireBase(final String childName) {
return Flowable.create(new FlowableOnSubscribe<DataSnapshot>() {
#Override
public void subscribe(final FlowableEmitter<DataSnapshot> e) throws Exception {
databaseReference.child(childName).limitToFirst(15).addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
e.onNext(dataSnapshot);
e.onComplete();
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
}, BackpressureStrategy.BUFFER);

Related

How to rewrite the following code since the FirebaseInstanceId() is deprecated?

The code was found from a Youtube tutorial called realtime location firebase and it's important for my Final Year Project. I appreciate all the help that i could get. Thanks in advance.
private void updateToken(FirebaseUser firebaseUser) {
DatabaseReference tokens = FirebaseDatabase.getInstance().getReference(Common.TOKENS);
//Get Token
FirebaseInstanceId.getInstance().getInstanceId().addOnSuccessListener(new OnSuccessListener<InstanceIdResult>() {
#Override
public void onSuccess(InstanceIdResult instanceIdResult) {
tokens.child(firebaseUser.getUid()).setValue(instanceIdResult.getToken());
}
}).addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
Toast.makeText(MainActivity.this, ""+e.getMessage(), Toast.LENGTH_SHORT).show();
}
});
}
private void updateToken(FirebaseUser firebaseUser) {
DatabaseReference tokens = FirebaseDatabase.getInstance()
.getReference(Common.TOKENS);
FirebaseInstallations.getInstance().getId()
.addOnCompleteListener(new OnCompleteListener<String>() {
#Override
public void onComplete(#NonNull Task<String> task) {
tokens.child(firebaseUser.getUid())
.setValue(task.getResult());
}
}).addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
Toast.makeText(MainActivity.this, "" + e.getMessage(),Toast.LENGTH_SHORT).show();
}
});
}
also try some dependencies in build.gradle(:app)
implementation platform('com.google.firebase:firebase-bom:26.8.0')
implementation 'com.google.firebase:firebase-database'

Multiple class in Firebase, and when I get it by Recycler Adapter, the "adapter" declare in different if else statement. onStart and onStop not works

I am a newbie in Android Studio and I having some problem in Firebase Recycler Adapter. I got different database in Firebase and it follow to the user ID which is eBay(Example) and Kog. I want to work like if eBay having item, it will shows and else if Kog having item, it shows too. But in the code, I only declare adapter in if...else statement. This make onStart and onStop could not listening. Here is the code. Thanks all of you...
public RecyclerView recyclerView;
public RecyclerView.LayoutManager layoutManager;
FirebaseDatabase database;
DatabaseReference requests;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_order_history);
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
database = FirebaseDatabase.getInstance();
requests = database.getReference("Users");
recyclerView = (RecyclerView)findViewById(R.id.order_history);
layoutManager = new LinearLayoutManager(this);
recyclerView.setLayoutManager(layoutManager);
recyclerView.setHasFixedSize(true);
loadOrders(common.currentUser.getUid());
}
private void loadOrders(String uid) {
DatabaseReference historyRef = FirebaseDatabase.getInstance().getReference("Users/orderHistory");
historyRef.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot snapshot) {
if (snapshot.hasChild("eBay")) {
FirebaseRecyclerAdapter<ebay_Order, orderViewHolder> adapter;
FirebaseRecyclerOptions<ebay_Order> options = new FirebaseRecyclerOptions.Builder<ebay_Order>()
.setQuery(requests.child(uid).child("eBay"), ebay_Order.class).build();
adapter = new FirebaseRecyclerAdapter<ebay_Order, orderViewHolder>(options) {
#Override
protected void onBindViewHolder(#NonNull orderViewHolder holder, int position, #NonNull ebay_Order model) {
holder.txtOrderName.setText(model.getEbayId());
holder.txtOrderAmount.setText(model.getEbayAmount());
holder.txtOrderServices.setText(model.getOrderChoice());
}
#NonNull
#Override
public orderViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.order_history, parent, false);
return new orderViewHolder(view);
}
};
recyclerView.setAdapter(adapter);
}
if (snapshot.hasChild("KOG")){
FirebaseRecyclerAdapter<kog_Order, orderViewHolder> adapter;
FirebaseRecyclerOptions<kog_Order> options = new FirebaseRecyclerOptions.Builder<kog_Order>()
.setQuery(requests.child(uid).child("KOG"), kog_Order.class).build();
adapter = new FirebaseRecyclerAdapter<kog_Order, orderViewHolder>(options) {
#Override
protected void onBindViewHolder(#NonNull orderViewHolder holder, int position, #NonNull kog_Order model) {
holder.txtOrderName.setText(model.getKogUsername());
holder.txtOrderAmount.setText(model.getKogAmounts());
holder.txtOrderServices.setText(model.getOrderChoice());
}
#NonNull
#Override
public orderViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.order_history, parent, false);
return new orderViewHolder(view);
}
};
recyclerView.setAdapter(adapter);
}
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
}
});
}
#Override
protected void onStart() {
super.onStart();
adapter.startListening();
}
#Override
protected void onStop() {
super.onStop();
adapter.stopListening();
}
#Override
public void onBackPressed(){
Intent intent = new Intent(this, InterPayMain.class);
orderHistory.this.finish();
startActivity(intent);
}
And the code for order View Holder
public class orderViewHolder extends RecyclerView.ViewHolder {
public TextView txtOrderName, txtOrderAmount, txtOrderServices;
public LinearLayout root;
public orderViewHolder(#NonNull View itemView) {
super(itemView);
root = itemView.findViewById(R.id.list_root);
txtOrderName = itemView.findViewById(R.id.order_id);
txtOrderAmount = itemView.findViewById(R.id.order_amount);
txtOrderServices = itemView.findViewById(R.id.order_choice);
}
And the error is
error: cannot find symbol adapter.startListening();
Is that got anyway to declare adapter in begining and able to work for different class.
As mentioned in the answer to this question: How to set two adapters to one RecyclerView?, a single RecyclerView can have only one adapter. You can create an adapter that has two different ViewHolders and chooses between them via overriding getItemViewType - see the question I linked for more information on implementing that solution.
An alternative is to have two separate RecyclerViews: one for each of your lists (eBay and Kog).

Firebase data deleted when you delete different data with same key?

When I delete the first node "List" in Firebase, the second node "List 2" is automatically deleted. I think this is happening due to same key of child of both nodes. Is there any way to stop another node from being deleting?
Here's my code which I'm using to copy data from "List" to "List 2" and then delete the node "List". When I delete the one node the other also get deletd.
ref.child("List").child(cardTitle).addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
ref.child("SHOP_ITEM").child("List 2).setValue(dataSnapshot.getValue());
ref.child("SHOP_ITEM").child("List").removeValue();
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
I had the same problem, so I used a work around; I simply added a cancel value to it. Something like cancel:"true".
In your case DATABASEREF1 = List1 and DATABASEREF2 = List2..
This was what worked for me. Here is the code:
DATABASEREF1.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
HashMap<String,String> hMdataSnapshot = (HashMap<String, String>) dataSnapshot.getValue();
hMdataSnapshot.put("canceled","true");
DATABASEREF2.setValue(hMdataSnapshot).addOnSuccessListener(new OnSuccessListener<Void>() {
#Override
public void onSuccess(Void aVoid) {
DATABASEREF1.removeValue().addOnCompleteListener(new OnCompleteListener<Void>() {
#Override
public void onComplete(#NonNull Task<Void> task) {
if (task.isSuccessful()) {
//DO SOMETHING
} else {
//DO SOMETHING
}
}
});
}
}).addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
//DO SOMETHING
}
});
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});

How can I extend a Retrofit 2.0 Call?

I want to achieve something like this:
MyCall<MyResponse> call = service.login(loginRequest);
call.enqueue(
new Runnable() {
#Override
public void run() {
// onResponse
}
}, new Runnable() {
#Override
public void run() {
// onFailure
}
});
so that when I have to make a call I don't need to parse the response in each callback and the code is a little lighter and reusable.
I tried the code from this snippet but I get the error:
Unable to create call adapter for XXXX.
What am I missing?
I did not extend Call but I extend Callback, it's also help to make the code is a little lighter and reusable.
public abstract class CustomCallback<T> implements Callback<T> {
#Override
public void onResponse(final Response<T> response, Retrofit retrofit) {
Runnable runnable = new Runnable() {
#Override
public void run() {
onRequestSuccess(response);
}
};
runnable.run();
}
#Override
public void onFailure(final Throwable t) {
Runnable runnable = new Runnable() {
#Override
public void run() {
onRequestFail(t);
}
};
runnable.run();
}
public abstract void onRequestSuccess(Response<T> response);
public abstract void onRequestFail(Throwable t);
}
Then when you call enqueue():
call.enqueue(new CustomCallback<YourObject>() {
#Override
public void onRequestSuccess(final Response<YourObject> response)
{
}
#Override
public void onRequestFail(final Throwable t) {
}
});
Hope it helps
If you're referring to the snippet below Jake Wharton's post then the issue should be that you're including a call to RxJavaCallAdapterFactory.create() & your call interface is not an observable. So remove that line.

How cancel network request in retrofit and rxjava

I have a multiple buttons; When I press new button, previous(with another button) running request should be interrupted and new runs. How to realize it?
for (button : Buttons) {
button.setOnClickListener(b -> networkApi.getLongContentFromUrl(url)
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Subscriber<JsonElement>() {
#Override
public void onCompleted() {}
#Override
public void onError(Throwable e) {
}
#Override
public void onNext(JsonElement jsonElement) {
//do with result
}
}));
}
You can have a common SerialSubscription and assign your subscriber to it on button click. It will unsubscribe and thus cancel your previous stream:
SerialSubscription serial = new SerialSubscription();
for (Button btn : buttons) {
btn.setOnClickListener(e -> {
Subscriber<JsonElement> s = new Subscriber<JsonElement>() {
#Override
public void onCompleted() {}
#Override
public void onError(Throwable e) {}
#Override
public void onNext(JsonElement jsonElement) {
//do with result
}
};
serial.set(s);
networkApi.getLongContentFromUrl(url)
.observeOn(AndroidSchedulers.mainThread())
.subscribe(s);
});
}

Resources