Swapping elements inside adapter - java

I'm making a file explorer synchronizing a directory in ftp, I would like that when a new item is downloaded it is displayed first in my recyclerview. For that I use sharedpreferences to store the new files and so I display or not a dot next to it to notify that it is new. Then I want to place it first at the begining of my MutableList, everything goes well except when I have to update with notifyItemMoved() which gives me the following error:
java.lang.IllegalStateException: Cannot call this method while RecyclerView is computing a layout or scrolling androidx.recyclerview.widget.RecyclerView{e8a722f VFED..... ......ID 0,60-1536,1098 #7f080104 app:id/main_folder_recycle_view}, adapter:fr.frd.calvezdocs.adapter.DirAdapter#f17203c, layout:androidx.recyclerview.widget.GridLayoutManager#31331c5, context:fr.frd.calvezdocs.MainActivity#5181ba0
Here is the code in my onBindViewHolder() :
val isRead: String? = prefNewDir.getString(currentDir.absolutePath, null)
if (isRead!=null) {
holder.DirIsRead.visibility = View.VISIBLE
println("before : " + items[0])
items.remove(currentDir)
items.add(0,currentDir)
println("after : "+items[0])
// Can't update the recyclerview
notifyDataSetChanged()
} else
holder.DirIsRead.visibility = View.GONE
Does anyone have an idea?
Thanks

onBindViewHolder is the method the adapter calls when it's displaying the list, and it's passing you a ViewHolder so you can update it to display a particular item in the list.
It's not the place to be doing stuff like calculating that the list has changed, and requesting a new layout, which is why you're getting an exception. You also definitely shouldn't be changing the items dataset while the RecyclerView is trying to display part of it!
Really, your adapter should have some kind of setData function, where you pass in updated data, and it can do stuff like working out what's moved, sorting the list for display, keeping a list of what's new and needs a highlight dot, etc. And that function can call notifyDataSetChanged(), or one of the more specific (and better) update functions as appropriate.
When you get new data (e.g. when you're storing a new file in the SharedPreferences) that's when you should be pushing an update to the adapter, so it can do what it needs to do, and refresh if necessary. You can even make it a simple update() call that passes nothing, and the adapter does all the SharedPreferences lookup you're currently doing in onBindViewHolder, if you want. And it'll be a lot more efficient than doing these lookups every time an item in the list is drawn
(I'd really recommend against what you're doing with SharedPreferences too, but maybe it complicates things less than I'm imagining. I'd still recommend trying to make your adapter work with a basic list internally, though - pass one in, so it doesn't need to know how the rest of the app is persisting data)

Related

RecyclerView item deletion not animated properly

I've got a RecyclerView which contains items, obviously. It uses the DefaultAnimator for all its animations.
When deleting an item, the deletion is animated, but not as it should be. The issue is that it seems like the size of the list is reduced by one first, then the clicked item is deleted and afterwards all items below are moved upwards by one. Take a look at this short video to see what I'm talking about.
The code used for the removal of a item is the following:
MainActivity.events.events.remove(listItems.keyAt(0));
notifyItemRemoved(listItems.keyAt(0));
Where MainActivity.events.events contains the data for the items and listItems.keyAt(0) contains the currently selected item.
What I've tried yet (none of this worked):
Made sure there's no other call which interrupts the animation (like notifyDataSetChanged()).
Implemented the above code directly into a onClickListener for the items inside the adapter.
Implemented the data directly into the adapter instead of a different class.
Replaced the position with getAdapterPosition() or a fixed value (i.e. 0)
Used notifyItemRangeRemoved() after notifItemRemoved().
Hint: I've got the animation to work previously, but as of today it doesn't work anymore.
EDIT:
If I remove the actual removal command (i.e. MainActivity.events.events.remove(listItems.keyAt(0));) from the code snippet given above, the animation is played correctly, but the element then isn't actually removed, so this doesn't solve the problem at all.

android gridview change item text

Ive got some gridView and some function which is called when a message arrives from server. In this function I get the values from server and I want to write this value in specific item in the gridView.
The problem is I dont have any idea how can I rewrite text of som Item in the gridView and I couldn find any answer on the internet :/
First you need to to add the received data into arraylist which you used to populate your grid view . You can add the received data into any position of arraylist as you need.
Then update the Arrayadapter using the following command
adapter.notifyDataSetChanged();
I understand up to some point. In my expatiation i think your set by using adapter right. So the simple solution is once you get the new items for a grid. call the setadapter again. Then that will set the new items. Try it once.
Actually i have to comment out but i don't have that much points.

Refreshing android Listview

I am trying to reload the list view when the data has changed. But its not working.Here is the code I am using
localPits.clear();//
this.adapter.clear();
//Fetch new data and update the list
this.localPits.addAll(pl);
this.adapter.notifyDataSetChanged();
this.lst_Pits.invalidate();
Each time I call this portion of code existing values are successfully removed. But new values are not loaded in the list view.
How can I do this in android?
Thanks
It's not terribly clear, but I suspect the new values aren't being loaded because you're clearing the adapter without updating it.
Your 2nd line: this.adapter.clear();
You need to update and add the adapter before you call invalidate(). Or, at least, that's as far as I can gather.
this.adapter.clear(); should not be needed. It must reset the links between adapter and localPits.
If you need to keep this, update list adapter localPits.setAdapter(adapter);. It should fix your problem.

Problems with android-pulltorefresh widget

I am having a bit of difficulty implementing the android-pulltorefresh widget by Johan Nilsson found at https://github.com/johannilsson/android-pulltorefresh
The problem I am having is after putting the custom listview into my application everything is fine it, but it asks to Tap to Refresh the list view but I need it to be set to pull down to refresh.
The code I am using below is pretty much from the github page and a screenshot of the app can be found below do demonstrate my issue:
PullToRefreshListView lv = (PullToRefreshListView)findViewById(R.id.listView);
lv.setOnRefreshListener(new OnRefreshListener() {
public void onRefresh() {
// Do work to refresh the list here.
GetData getData = new GetData();
getData.execute();
}
I need the Tap to refresh header gone and only to be shown once the listview has been dragged down. I get the feeling I just need to change some sort of flag but I can't find where this would be.
Unfortunately there is no way to work around this. The entire control is built around the idea that the "Pull to Refresh" header is a normal listview item that gets hidden by scrolling the list upward. Unfortunately, when you have a very short list, the list cannot be scrolled upward to hide the first item cause there are not enough items in the list -- so the fallback is to show the first item (the header) as well and have it display "Tap to Refresh".
EDIT: One kludge you may be able to do is insert dummy blank items so the list has enough items to hide the top header list item.
use this code
Hope it works for you.

Updating the UI during a after a button push

I have been thinking about adding a button to a View which when pressed adds another view on the bottom. It would resemble the Clock application that comes preinstalled in which you push a view in form of an alarm which is then added to a list.
Does anyone have any experience with how to implement that?
Have a look at the documentation for ListView, particularly the setAdapter() method. You'll want to have some sort of backing collection most likely as the adapter, such as an ArrayAdapter, to which you can add new items, and have them populate into the list.
Use a listview, populate it.
Then when you press the button, add something to your data, then:
public void notifyDataSetChanged ()
Since: API Level 1 Notifies the attached observers that the underlying
data has been changed and any View reflecting the data set should
refresh itself.

Categories