I have DAO method returned LiveData<List<Category>>:
LiveData<List<Category>> listLiveData = categoryDao.getAll();
After that I need set this data to my Adapter:
listLiveData.observe(this, categories -> {
if (categories == null || categories.isEmpty()) {
price.setVisibility(View.VISIBLE);
recyclerView.setVisibility(View.INVISIBLE);
} else {
categoryAdapter = new CategoryAdapter(categories);
categoryAdapter.setOnItemClickListener(new ClickHandler());
recyclerView.setAdapter(categoryAdapter);
}
});
if I have not data in DB I show button for update(get data from server and insert to DB).
if I have data I create adapter and set data to it.
After that if I insert some Category to DB I get this:
triggered observe method and get all categories
create new adapter with this data
I think it is very bad practice(create a new adapter for update each item) and I can some way:
Change my adapter and add method addData(List<Category> categories);
in onCreateView I create adapter: categoryAdapter = new CategoryAdapter(new ArrayList());
then when I get data in observe method I add it to adapter:
adapter.addData(categories);
and into addData method in loop check each item and if not exist add to list and notify data.
change method
LiveData> listLiveData = categoryDao.getAll();
to
LiveData<Category> category = categoryDao.getLast();
and add this item to observe method. But I have 2 problems: 1 - How can I add firstly all data? I must implement 2 methods getAll(call wen create adapter) and getLast(call for each insert in DB). 2. How can I write this getLast method?
correct way that you will advise me :)
Your first step is right, you should create adapter only once in a lifecycle of Fragment or Activity and set the value(list) to adapter whenever you need to change dataset.
You should use getAll() method and it is best practice because you have data in local database and that doesn't take longer. If you have long data set then you should use pagination where only limited no. of items are fetched at a time. That can be achieved using LIMIT clause queries in sqlite.
And then use notifyDatasetChanged() method. If you want to show a smooth animation for newly inserted items use DiffUtil class to compare list and notify adapter accordingly.
To know how to use DiffUtil, check this out https://medium.com/#iammert/using-diffutil-in-android-recyclerview-bdca8e4fbb00
Hope this helps.
Related
In Base adapter, I have used some imageview, can I change the image src in activity?
You should not access the adapter views directly in activity. Write a method in adapter instead. Call adapter.change image from your activity.
public void changeImage(int imgResId) {
likeButton.setImageResource(imgResId);
}
If Image src is provided from activity then you can call notifyDataSetChanged() after changing data.
Eg.
adapter = new MYAdapter(data);
list.setAdapter(adapter);
//change data here
adapter.notifyDataSetChanged();
You need to update the model data which is associated with ViewHolder after that just notify the adapter and adapter will update your item with new model data.
Take example if you have Array of 10 objects and you want to update ImageView on 5th position then update your 5th model in ArrayList and call adapter.notifyDataSetChange() it will update desired image view.
I got a recylcerview, which has another recylcerview as an element of it. However, i am confused how to update data of the inside recylcerview. How should I do it?
I don't know if this will work for you because i don't have your code, but you can create a updateAdapter , inside of it you must refresh everything.
For example we have 2 arrayList:
private void updateAdapter() {
this.mItems = c.getArray();
this.mItemsNr = c.getNr();
//and call notifyDataSetChanged
notifyDataSetChanged();
}
mItems and MItemsNr are 2 arrayList and c is an object where i have the 2 new arrayList.So i update the 2 arrayList and hten i call notifyDataSetChenged(); to update my adapter.
Hope this could help you.
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()
}
Is there anyway to continuously load data on one list view? I tried doing this but the second setadapter overrides the first one. Here is my code:
ArrayAdapter<Display> adapter = new DisplayAdapter(getActivity(), R.layout.display_list_item, response.container.InactiveDisplay);
existingItemsListView.setAdapter(adapter);
ArrayAdapter<Display> adapter1 = new DisplayAdapter(getActivity(), R.layout.display_list_item, response.container.ActiveDisplay);
existingItemsListView.setAdapter(adapter1);
An alternative solution:
List<MyAdapterItems> myItems =
((MyAdapter)myListView.getAdapter()).getMyAdapterItems;
/*
*You can use myitems.add(Object o) method to add items then you can call
*/
myListView.setAdapter(myItems);
add data to first adapters array and then call adapter.notifyDatasetChanged(); to notify listview that there is new data to load
In my OncreateView() set the adapter which is working when i am first loading the page. When i go to another page and make changes then come back to this fragment it is not working adapter.notifyDatasetchanged().
#Override
public void onStart() {
super.onStart();
groupItem.clear();
childItem.clear();
List<String> child_Category;child_Category=new ArrayList<String>();
groupItem = obj_Listdatabase.fetchcategory();
childItem.clear();
ListIterator<String> iterator = groupItem
.listIterator();
while (iterator.hasNext()) {
String categoryname = iterator.next();
child_Category = new ArrayList<String>();
child_Category = obj_Listdatabase
.fetchchildlist(categoryname);
childItem.add(child_Category);
}
adapter.notifyDataSetChanged();
}
Hai I got output for this one:
groupItem.addAll(obj_Listdatabase.fetchcategory());
Instead of This
//groupItem = obj_Listdatabase.fetchcategory();
Because i change the reference in assignment statement(=) for that adapter.So i use addAll() method to store the values only instead of reference.
You should reaaaally indent your code more cleanly, never use several ";" on the same line for example.
And you can definitely use BaseExpandableListAdapter the issu is somewhere else..
You should also notice that onCreate view is more suitable for "creating view" so all the adapter stuff should be somewhere else like onViewCreated, or onActivityCreated as you need (it's just some advices)
I assume your adapter is in a Fragment since you use GetActivity() and in the constructor of your adapter you pass a reference to the activity (context), the group list and the child list.. ok
we ll assume that you are using the fragment onStart. From the official doc :
Called when the Fragment is visible to the user. This is generally tied to Activity.onStart of the containing Activity's lifecycle.
So normally this method is called after onViewCreate, onViewCreated .. etc at least the first time you code is running. So this is ok
Did you try using adapter.notifyDataSetInvalidate() and then do adapter.notidyDataSetChanged ?
One last thing, since you actually pass the data to your adapter by the constructor, when you update your lists how can the adapter be aware of the changes ? Are your lists global (static) ?
If not, before doing adapter.notifyDataSetChanged() you should pass the lists (group and child) to the adapter with some setter..
good luck