Remove all items in custom BaseAdapter and add new ones - android

I'm getting trouble by doing some simple task with my adapter.
I've class that implementing BaseAdapter, associated to a ListView.
After I've created this adapter and showed it to the user, if some event occours, I would remove all elements inside adapter, and adding new ones.
I have implement this method inside my BaseAdapter:
public void clearAndBuild(ArrayList<PictureObject> new_pics, String some_text) {
pics.clear();
pics.addAll(new_pics);
this.hashtag = hashtag;
//do something else
}
(where pics is an ArrayList containing items to put inside ListView). In my activity, fo refresh all i call:
adapter.clearAndBuild(pics, tag);
adapter.notifyDataSetChanged();
but it doesn't work.
After i call that method, old items inside listView are removed, but new ones is not showed (i get an empty listview).
What's wrong?

the only reason could be that you are reusing the same references for pics and new_pics. Make a deep copy of new_pics before calling clear() on pics

you can do this:
public void clearAndBuild(ArrayList<PictureObject> new_pics, String some_text) {
pics. = new ArrayList<PictureObject>(new_pics);
this.hashtag = hashtag;
//do something else
}

Related

How to refresh two listview at one moment in Android?

I have two listview, like listview_1 and listview_2. I wanna refresh the listview_2 while listview_1 is refreshed.
My code like this:
public void updateTwoListView() {
listview_1.getAdapter().notifyDataSetChanged();
listview_2.getAdapter().notifyDataSetChanged();
}
But it don't work, listview_1 can refresh but the listview_2 can't.
And at that moment what I found is that listview_1 was on focus.
And then I tried to set focus to other views before ran the method, both of them didn't refresh. It likes to refresh a listview only if the listview has focus.
What's more I found that when I called the method to refresh, listview_2 didn't, and then I set focus to listview_2, refreshed itself!
So, What all I want to ask is:
How to refresh two listview at one moment in Android?
What's more code:
//init two listview there
public void init() {
listview_1 = (ListView)findViewById(R.id.listView1);
listview_2 = (ListView)findViewById(R.id.listView2);
adapter1 = new MyListViewAdapter(mContext);
adapter2 = new MyListViewAdapter(mContext); //I have tried use different adapter, that also didn't work.
listview_1.setAdapter(adapter1);
listView_2.setAdapter(adapter2);
}
the real code of upside snippet is:
public void updateTwoListView(int currentPosition) {
adapter1.updateCurPos(currentPosition);
adapter2.updateCurPos(currentPosition);
}
and in MyListViewAdapter.java:
public void updateCurPos(int currentPosition) {
mCurrentPos = currentPosition;
notifyDataSetChanged();
}
And I will call method like listViewManager.updateTwoListView(1) outside to refresh.
Any reply is appreciated.
You have called listview_1 twice. Just change one of them to listview_2 as below:
public void updateTwoListView() {
listview_1.getAdapter().notifyDataSetChanged();
listview_2.getAdapter().notifyDataSetChanged();
}
It seems the problem of your code is that you call getAdapter().
Sets the data behind this ListView. The adapter passed to this method may be wrapped by a WrapperListAdapter, depending on the ListView features currently in use. For instance, adding headers and/or footers will cause the adapter to be wrapped.
Source: http://developer.android.com/reference/android/widget/ListView.html#setAdapter(android.widget.ListAdapter)
The solution is save your Adapter as member variable in your activity and call the notifyDataSetChanged()from there.
See more on this question's answer: https://stackoverflow.com/a/31893525/2742759

Android RecyclerView infinity scrolling: how to add more items to dataset

I have implemented my RecyclerView and even added an onscrolllistener to support infinity scrolling and now I'm stuck with a, hopefully, easy problem: How can I add the newly loaded data to the existing dataset?
My current approach: I create a new array with the length of the existing dataset + the length of the newly loaded data. I System.arraycopy my existing dataset and add the new content with a for-loop.
This works but the list is always reset (scrolls back to the top) and I assume my way to add additional content is overly complicated/wrong, though the tutorials I have looked at seem to pass over this "detail".
Update: I'm currently calling "scrollToPosition" on the UI-Thead after the data has been loaded, but I doubt this is the correct way of doing this or am I wrong?
You shouldn't be adding stuff to your dataset, you will sooner or later run out of memory. What you can do is return a big number (I used Short.MAX_VALUE) item in getItemCount inside your adapter and in the method that requests a view for postion you should do position % list.size();
It is not a truly endless RecyclerView this way, but good enough. I will paste some code tomorrow, I don't have it here now :/
I think you have to add items inside your adapter. Let`s say
class Adapter extends Recycler.Adapter<Recycler.ViewHolder>{
List<YourCustomObject> list;
public Adapter(){
list = new ArrayList<>();
}
public void addItem(YourCustomObject item){
list.add(item);
notifyItemDateSetChanged(); //This method for adapter to notice that list size have been changed
}
// Here your views
}
There is implementation of Your fragment or Activity where you retrieve data from internet.Let` say
class MainActivity extends AppCompactActivity{
Adapter adapter = new Adapter();
List<YourCustomObjects> objects;
public void onCreateView(){
//////// Something yours
}
public void onLoadMore(){
///// Your operation to retrieve data and init it to your list objects
for(YourCustomObject object : objects){
adapter.addItem(object);
}
}
}

Update custom listview item attribute

I am using listview in my app.I am adding items to list with this line:
conversationsAdapter.add(user);
and this initializes list
conversationsAdapter=new ArrayAdapter<JsonObject>(this,0) {
#Override
public View getView(int c_position,View c_convertView,ViewGroup c_parent) {
if (c_convertView == null) {
c_convertView=getLayoutInflater().inflate(R.layout.random_bars,null);
}
JsonObject user=getItem(c_position);
String name=user.get("name").getAsString();
String image_url="http://domain.com/photos/profile/thumb/"+user.get("photo").getAsString();
TextView nameView=(TextView)c_convertView.findViewById(R.id.tweet);
nameView.setText(name);
ImageView imageView=(ImageView)c_convertView.findViewById(R.id.image);
Ion.with(imageView)
.placeholder(R.drawable.twitter)
.load(image_url);
return c_convertView;
}
};
ListView conversationsListView = (ListView)findViewById(R.id.conversationList);
conversationsListView.setAdapter(conversationsAdapter);
conversationsListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
startChat(conversationsAdapter.getItem(position));
}
});
My list view is looking like this:
I want to update an item in the list.How can I do this ?
Example:We can write a method like: changeName when this method calls,method sets name "Tolgay Toklar" to "Tolgay Toklar Test" so I want to update custom listview item attributes.
I totally disagree with tyczj. You never want to externally modify an ArrayAdapter's list and yes it's possible to update just an individual item. Lets start with updating an individual item.
You can just invoke getItem() and directly modify the object and call notifyDataSetChanged(). Example:
JSONObject object = conversationAdapter.getItem(position);
object.put("name", data);
conversationAdapter.notifyDataSetChanged();
Why does this work? Because the adapter will feed you the same object reference used internally, allowing you to modify it and update the adapter. No problem. Of course, I'd recommend instead building your own custom adapter to perform this directly on the adapter's internal list. As an alternative, I highly recommend using the ArrayBaseAdapter instead. It already provides that ability for you while fixing some other major bugs with Android's ArrayAdapter.
So why is tyczj wrong about modifying the external list? Simple. There's no guarantee that your external list is the same as the adapters. Once you perform a filter on the ArrayAdapter, your external list and the adapters are no longer the same. You can get into a dangerous scenario where (for example) index 5 no longer represents position 5 in the adapter because you later added an item to the adapter. I suggest reading Problems with ArrayAdapter's Constructors for a little more insight.
Update: How External List Fails
Lets say you create a List of objects to pass into an ArrayAdapter. Eg:
List<Data> mList = new ArrayList<Data>();
//...Load list with data
ArrayAdapter<Data> adapter = new ArrayAdapter<Data>(context, resource, mList);
mListView.setAdapter(adapter);
So far so good. You have your external list, you have an adapter instantiated with it and assigned to listview. Now lets say at some later point, the adapter is filtered and cleared.
adapter.filter("test");
//...later cleared
adapter.filter("");
Now at this point mList is NOT the same as the adapter. So if the adapter is modified:
adapter.add(newDataObject);
You'll find that mList does not contain that new data object. Hence why external lists like this can be dangerous as the filter creates a NEW ArrayList instance. It won't continue to use your mList referenced one. You could even try adding items to mList at this point and it won't be reflected in the adapter.
If you change the data in your list you need to call notifyDatasetCanged on the adapter to notify the list that the underlying data has changed needs to be updated and.
Example
List<MyData> data = new ArrayList<MyData>();
private void changeUserName(String name){
//find the one you need to change from the list here
.
.
.
data.set(myUpdatedData);
notifyDatasetChanged()
}

ViewPager updates listView in fragment B from a fragment A

I have a ViewPager with two Fragments. On the first one, there are buttons (it is a menu) and they represent different categories. On the second one, it is a listView which display data.
I am looking for a way to change the data to display on the listView when the user click on one of the menu items.
For example : the user click on the menu item 1 (fragment 1), the listView on the fragment 2 have to be updated with the corresponding data.
I read the documentations from Google Android developer about fragments but I couldn't work it out, I didn't find a solution to my problem.
Maybe I'm missing something ?
EDIT : I tried to clear my ListView by clearing the list of data (ArrayList> listItems) with listItems.clear(). I didn't find how to do adapter.clear(), it seems that this method doesn't exist in the class Adapter.
So to summarize : I created an update method in my fragment which contains the ListView (Fragment2). I called it through a callback method in the main activity, that part seems to work (I checked it with debug mode).
In the update method of my Fragment 2, I clear data with listItems.clear() and then the OnActivityCreated() of the fragment is executed. In it, there is the call of my thread which download data and then it create the ListView in OnPostExecute.
Here is a sample of my code (fragment2) :
// After data are ready
lvListe = (ListView) getView().findViewById(R.id.lvListe);
lvListe.setSelected(true);
lvListe.setScrollingCacheEnabled(false);
adapter = new LazyAdapter(getActivity(),
getActivity().getBaseContext(), listItems,
R.layout.affichageitem, new String[] { "image", "title",
"subtitle" }, new int[] { R.id.img_title,
R.id.titre_main, R.id.soustitre_main });
lvListe.setAdapter(adapter);
lvListe.setClickable(true);
lvListe.setOnItemClickListener(onItemClickListener);
// Update method :
public void update(String requete, String type)
{
this.type = type;
this.requete = requete;
listItems.clear();
}
The way that I would probably do it is to create a callback method in the Activity hosting the ViewPager and also a method in the second Fragment to update the data.
Then you would call it like:
class Fragment1...
{
...
callBackUpdate(data);
}
class Activity...
{
...
public void callBackUpdate(String data)
{
Fragment2.update(data);
}
}
class Fragment2...
{
...
public void update(String data)
{
//do whatever
}
}
The developers page shows how to create a callback method to the Activity.
edit: Actually that's how the Developer's page says to do it. They create the interface OnArticleSelectedListener for the callback.
edit: I'm assuming you are using this library for the LazyLoader: https://github.com/thest1/LazyList
If so, then you can just add the method to clear the data yourself. To do so, add a method like this in ListAdapter:
public void clear()
{
data = new String[](); //depends on what data is, if it's a List then just call data.clear() for example
imageLoader=new ImageLoader(activity.getApplicationContext()); //clear the images
notifyDataSetChanged(); //notify the adapter that the data has changed
}
This might not exactly fit how you currently have it, but you should get the idea.
Try using something known as a FragmentTransaction manager at http://developer.android.com/reference/android/app/FragmentTransaction.html
and also the FragmentManager http://developer.android.com/reference/android/app/FragmentManager.html
Check out some of the questions on stackoverflow related to FragmentManager and FragmentTransaction to figure this out. All you need to do is replace the fragment with a new one which is inflated by a particular xml

ListView freaks out when I try to update the ArrayAdapter, is the header?

I have this ListView that is using an array adapter:
//global
ArrayList<Location> locations=new ArrayList<Location>(); //array list of location objects
ArrayAdapter<Location> theLocations;
ListView listView;
then in onCreateView of my Fragment:
theLocations = new ArrayAdapter<Location>(mContext,
R.layout.location_row, locations);
listView.setAdapter(theLocations);
This works pretty well I think, though if I try to update this adapter it freaks out...
//in my fragment, another dialog makes this call here to update the list.
public void onUIUpdate(Location l) { //listener call back when dialog "ok" clicked
locations.add(l); //it is okay with this.
theLocations.notifyDataSetChanged(); //dies
}
It dies with the error:
07-23 08:03:28.655: ERROR/AndroidRuntime(509): java.lang.IllegalStateException: ArrayAdapter requires the resource ID to be a TextView
does that mean it doesn't like the Location in the ArrayAdapter ??? does this mean I have to make my own custom listadapter? If I don't call theLocations.notifyDataSetChanged() everything is okay but then nothing updates... :(
I should note that the toString() in the Location class is override to return a String name;
after a comment I tried this:
public void onUIUpdate(Location l) {
locations.add(l);
//theLocations.notifyDataSetChanged();
WrapperListAdapter wr = (WrapperListAdapter)listView.getAdapter();
ArrayAdapter aa=(ArrayAdapter)wr.getWrappedAdapter();
aa.notifyDataSetChanged();
}
LOL no luck here, was a stab in the dark. Also wandering if its the addHeaderView I used on the ListView? I am not sure if it makes it immutable in the future using addHeaderView?
I won't comment about ListView design, it is very ugly, but I do listView.getAdapter().getWrappedAdapter().notifyDataSetChabged(); and it works.

Categories

Resources