NotifyItemRemoved not working properly using firebaserecycleradapter? - android

I'm using firebase-ui to retrieve from firebase and I want to remove from displaying all the status that are equal to unlive I don't want to delete it from firebase database but only removed it from displaying on the recyclerview tried also doing the solution Cannot call this method while RecyclerView is computing a layout or scrolling when try remove item from recyclerview here still encountering the error. Please help I'm stuck here for days. Can't find any solution. Thanks
mAdapter = new FirebaseRecyclerAdapter<Hotels_Model, Adapter_HotelsHolder>(mOptions) {
#Override
protected void onBindViewHolder(Adapter_HotelsHolder holder,int position, Hotels_Model model) {
String status = model.getStatus();
if (status.equals("unlive")) {
mAdapter.notifyItemRemoved(holder.getAdapterPosition());
mAdapter.notifyItemRangeChanged(holder.getAdapterPosition(), getItemCount());
}
}
This is my error if I scroll to the position where the status is unlive
Cannot call this method while RecyclerView is computing a layout or scrolling android.support.v7.widget.RecyclerView

So you can do it easily in that way:
mAdapter = new FirebaseRecyclerAdapter<Hotels_Model, Adapter_HotelsHolder>(mOptions) {
#Override
protected void onBindViewHolder(Adapter_HotelsHolder holder,int position, Hotels_Model model) {
String status = model.getStatus();
if (status.equals("unlive")) {
holder.yourRowView.setVisibility(View.GONE);
}
}
You don't need to remove your items from recyclerview.

Related

RecyclerView ItemTouchHelper doesn't remove item

I'm trying to implement swipe to archive note in RecyclerView.
It was working fine but after I added these codes to refresh the RecyclerView from onResume(), Swiping although does archive the Note, but the item doesn't get removed and stays at a state you can see in image below:
This is what I do in onResume() :
#Override
protected void onResume() {
super.onResume();
notes = noteDAO.getAllNotes();
noteAdapter = new NoteAdapter(notes,this);
recyclerView.setAdapter(noteAdapter);
}
ItemTouchHelper onSwiped():
#Override
public void onSwiped(#NonNull RecyclerView.ViewHolder viewHolder, int direction) {
int position = viewHolder.getAdapterPosition();
noteAdapter.deleteItem(position,rv);
}
deleteItem method in Adapter:
public void deleteItem(int position, RecyclerView rv) {
noteDAO = DBInjector.provideNoteDao(context);
recentlyDeletedNote = notes.get(position);
recentlyDeletedNotePosition = position;
recentlyDeletedNote.setArchive(true);
notes.remove(position);
noteDAO.archiveNote(recentlyDeletedNote);
notifyItemRemoved(position);
}
I have tried a lot of solutions, the only reason why it is not updating the view is that on updating recycler views, views are getting updated especially when ItemTouchHelper is used. As I didn't have much choice I used
recreate()
function for refreshing the whole activity and the error went off.
PS: This is not the ideal solution, it is just workaround fix.

Delete data from firebase recycler view adapter without deleting in the database

That is it, can i remove a view from firebase recycler view adapter, but not deleting in the database?How?
final FirebaseRecyclerAdapter<Game,GameViewHolder> firebaseRecyclerAdapter=new FirebaseRecyclerAdapter<Game, GameViewHolder>(
Game.class,
R.layout.row,
GameViewHolder.class,
mdatabase
) {
#Override
protected void populateViewHolder(GameViewHolder viewHolder, Game model, final int position) {
viewHolder.setTitle(model.getGame_name());
viewHolder.setJugado(model.getJugado());
viewHolder.setCreator(model.getCreator_name());
recyclerView.setAdapter(firebaseRecyclerAdapter);
}
FirebaseRecyclerAdapter doesn't support this. The whole point of FirebaseRecyclerAdapter is that it stays in sync with the contents of the location that you originally gave it. If something deletes data from the database, it will be automatically and unconditionally deleted from your adapter.
If you want this behavior, you will have to implement your own RecyclerView adapter, preferably one that does not use an active listeners to be notified of every change to the location of the data. You would have to listen to the entire contents just once, then send that to an adapter to populate a RecyclerView.
And how about this in ViewHolder?
itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
itemView.setVisibility(View.INVISIBLE);
}
});
Yes you can. You have to add this in your GameViewHolder class:
Create a function and get reference of your cardview
Create a layout params and Create an instance of the parent of your cardview then set the height and the width equals to 0
public void Remove() {
cardView = mView.findViewById(R.id.cardview);
cardView.setLayoutParams(new FrameLayout.LayoutParams(0,0));
}
Use the function
viewHolder.remove();

RecyclerView scroll in incorrect direction when new element is inserted

I use smoothScrollToPosition to scroll RecyclerView. It does scroll every time a new entry is inserted; but to the top, not to the bottom, which is the direction i want.
list_chat = (RecyclerView) findViewById(R.id.list_chat);
//Set up Layout Manager
linearLayoutManager = new LinearLayoutManager(this);
linearLayoutManager.setStackFromEnd(true);
list_chat.setLayoutManager(linearLayoutManager);
//set adapter
list_chat.setAdapter(adapter);
//set scroll
list_chat.post(new Runnable() {
#Override
public void run() {
list_chat.smoothScrollToPosition(adapter.getItemCount());
}
});
The adapter is from Firebase
adapter = new FirebaseRecyclerAdapter<ChatItem, ChatRecylerViewHolder>(ChatItem.class,R.layout.chat_item
,ChatRecylerViewHolder.class,queryChat ) {
#Override
protected void populateViewHolder(ChatRecylerViewHolder viewHolder, ChatItem model, int position) {
viewHolder.tvAuthorChat.setText(model.chatAuthor);
viewHolder.tvContentChat.setText(model.chatContent);
}
};
You do notice you are using linearLayoutManager.setStackFromEnd(true); this mean you first position is at the bottom. I suggest you a better option.
RecycleView didn't work the way listView work, you can scroll it with your layout manager something like this
linearLayoutManager.scrollToPositionWithOffset(position,offset);
Which position is the position you want to scroll to, offset is the offset within the current position. You could just use with one parameter as well.
linearLayoutManager.scrollToPosition(position);
Ok. I found the answer.
First, the old problem with my question: i thought list_chat.post is called whenever an item is inserted (turn out that is wrong). The reason for it keeps scrolling top is linearLayoutManager.setStackFromEnd(true);
Thus, the question comes down to Where to call the scrolling ?
The answer is : Since adapter manages data, it makes sense to guess that adapter will notify the insertion.
Here is the code
adapter.registerAdapterDataObserver(new RecyclerView.AdapterDataObserver() {
#Override
public void onItemRangeInserted(int positionStart, int itemCount) {
super.onItemRangeInserted(positionStart, itemCount);
list_chat.smoothScrollToPosition(adapter.getItemCount());
}
});

How to auto scroll up the chat messages (using recyclerview instead of listview) above the softkeypad whenever keypad pop ups?

Like in chat applications whenever we want to send messages soft keypad pop ups which also auto scroll the last seen messages to top of the soft keypad provided that nothing is hidden behind the soft keypad. But in my case the keypad hides the conversations. How to fix this issue and I have used to recycler view for displaying the messages. I used android.support.v7.widget.RecyclerView
With RecyclerView you can achieve this as follows:
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);
linearLayoutManager.setReverseLayout(true);
recyclerView.setLayoutManager(linearLayoutManager);
This block of code will tell the RecyclerView to scroll relative to the bottom of the list but also it shows the messages in reverse order so in your code if you are getting the messages from database, read them from the last message like this:
Cursor c = ...;
c.moveToLast();
do{
//your code which gets messages from cursor...
}while(c.moveToPrevoius());
and when you want to add a new message to the list just add them like this:
//ArrayList messages
messages.add(0, message);
How I handle with this is very simple, to achieve one good behaviour, similar to Whatsapp or other popular chats.
At first, set the LinearLayoutManager like this.
new LinearLayoutManager(this.getContext(), LinearLayoutManager.VERTICAL, true);
chatLayoutManager.setStackFromEnd(true);
When messages begin to overflow the RecyclerView at the bottom, needs to set the current position to 0, to achieve this, a simple interface works like a charm, to warning when the RecyclerView.Adapter has rendered the last message.
public interface OnLastItemRendered{
void lastItemRendered();
}
Pass the interface implementation from the activity/fragment to de RecyclerView.Adapter to call scrollToPosition in the RecyclerView.
new ChatMessageListAdapter(
context, user, lastOldMessages,
new OnLastItemRendered() {
#Override
public void lastItemRendered() {
ContainerFragment.this.myRecyclerViewToChat.scrollToPosition(0);
}
});
And finally, if want to perform animations in the RecyclerView, implements one method to add the message in the RecyclerView.Adapter calling at the end to notifyItemInserted method.
public void add(ChatMessage chatMessage) {
if (this.chatMessages == null) {
this.chatMessages = new ArrayList<ChatMessage>();
}
this.chatMessages.add(chatMessage);
Collections.sort(this.chatMessages, this.orderChatMessagesComparator);
this.notifyItemInserted(0);
this.onLastItemRendered.lastItemRendered();
}
And, for the X messages loaded at the beginning, in the onBindViewHolder.
#Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
final ChatMessage currentMessage = this.chatMessages.get(position);
... //Do your stuff.
if (position == 0) this.onLastItemRendered.lastItemRendered();
}
Work done.
You can detect the focus on the edit text, and if your editText has focus,
scroll your recyclerView list to the last element.
private OnFocuseChangeListener focuseListener = new OnFocuseChangeListener(){
public void onFocusChange(View v, boolean hasFocus){
if(hasFocus){
// Scroll down to the last element of the list
recyclerView.scrollToPosition(sizeOfYourList);
} else {
focusedView = null;
}
}
}
Similarly use scrollToPosition () when you click on your send button or where you want to show the last element of the list.

How to update RecyclerView's data dynamiclly?

I have some tables in the database, every table has many rows,I want to show the tables's data in a list, so I use a RecyclerView to show the data, and a spinner to select the table which I want to show.
But now, when I select an item of spinner, the RecyclerView doesn't have any changes ,it can't show the new data only after I reopen the fragment.
My code:
In adapter:
1.removeItem works
the item in the RecyclerView will be removed when removeItem called.
public void removeItem(WordCls wordCls) {
int position = wordsList.indexOf(wordCls);
wordsList.remove(position);
notifyItemRemoved(position);
}
2.updateList doesn't work
But when updateList called,nothing happened in the view
public void updateList(List<WordCls> wordsList) {
//this.wordsList = wordsList;
this.wordsList.clear();
this.wordsList.addAll(wordsList);
notifyDataSetChanged();
}
In fragment:
in onCreateView():
recyclerView = (RecyclerView) view.findViewById(R.id.wordbook_recycler_list);
recyclerView.setLayoutManager(new LinearLayoutManager(activity));
recyclerView.setItemAnimator(new DefaultItemAnimator());
recyclerView.setHasFixedSize(true);
wordsList = WordsManager.getWordsList(tableName);
wordCardAdapter = new WordCardAdapter(activity, tableName, wordsList);
recyclerView.setAdapter(wordCardAdapter);
wordCardAdapter.setOnItemClickListener(new WordCardAdapter.OnRecyclerViewItemClickListener() {
#Override
public void onItemClick(View view, WordCls wordCls) {
Toast.makeText(getActivity(), wordCls.getWord(), Toast.LENGTH_SHORT).show();
wordCardAdapter.removeItem(wordCls);
WordsManager.deleteWord(tableName, wordCls.getWord());
}
});
in SpinnerItemSelectedListener:
#Override
public void onItemSelected(AdapterView<?> parent, View view, int position,long id) {
tableName= parent.getItemAtPosition(position).toString();
prefEditorSettings.putInt(KEY_SPINNER_SELECTED_ITEM, position);
prefEditorSettings.commit();
tableName = getWordbookList().get(spnSelectedPosition);
wordsList = WordsManager.getWordsList(tableName);
wordCardAdapter.updateList(wordsList);
Toast.makeText(activity, tableName, 2000).show();
}
==============================================
update:
the method updateList is right.
just my careless to have passed a wrong param at
tableName = getWordbookList().get(spnSelectedPosition);
it should be
tableName = getWordbookList().get(position);
now, it works.
Actually, I don't know if RecyclerView is the best way to fulfill your purpose.
RecyclerView(s) are to be used when you have to show multiple instances of your List, in a list-y way :)
If you have just one View to update (that contains multiple fields to be updated), I'd choose some data-binding library like RoboBinding or the new beta version of google binding library (MVVM paradigm)
I'm not going into further details as I just want to warn you about MVVM programming paradigm that can be a worthy solution in your case.
instead of wordCardAdapter.updateList(wordsList) , add new data to wordsList and wordCardAdapter.notifyDataSetChanged() inside spinner
hope it works.

Categories

Resources