ArrayList inside ArrayList - android adapter? - java

So, I have Client class, which stores Category ArrayList (Client can have a couple of categories). Each category stores Expense ArrayList. So, every category can have a couple of expenses.
Here is the issue: I want to set adapter for one listView, in which we would print out all of the expenses. I know how to create adapter for one ArrayList, but if we have ArrayList inside ArrayList - then I am lost.
Any tips or tricks you might be able to share with me?

Use ExpandableListView with ExpandableListAdapter

You can use an adapter inside another adapter. I have used this approach in a dummy project. I put the following code as a starting point.
class Category{ List<Expense> expenseList; }
//this adapter will be used in Activity
class CategoryAdapter extends ArrayAdapter<Category>{
//your other adapter code here
ArrayAdapter<Expense> expenseAdtr =new ExpenseAdapter(context, category.getExpenseList());
expenseListView.setAdapter(expenseAdtr );
expenseListView.setOnClickListner(....);
}
//this adapter will be used inside CategoryAdapter
class ExpenseAdapter extends ArrayAdapter<Expense>{
//your adapter code here, should have no issue here
}
class MyActivity extends Activity{
//somewhere onCreate or .....
List<Category> categoryList;
ArrayAdapter<Category> categoryAdtr =new CategoryAdapter(context, categoryList);
expenseListView.setAdapter(categoryAdtr);
}

Related

Android adapter best practice when using attributes from activity

My Adapter requires a context in order to apply resources to views, therefore when instantiating it, I might do the following within my Activity:
myAdapter = new MyAdapter(this);
As my adapter also needs data from an activity, I might do this:
myAdapter = new MyAdapter(myItemsArrayList,this);
As my adapter might also need to know which items in the ArrayList are selected, I might pass it that list too:
myAdapter = new MyAdapter(myArrayItemsList,mySelectedItemsArrayList,this);
And as there may be other states (e.g. whether to display photos in a list of people, the constructor call is starting to get quite lengthy:
myAdapter = new MyAdapter(myArrayItemsList,mySelectedItemsArrayList,myPreference1,myPreference2,this);
Given that the only place this adapter will be used is from a particular activity, how bad would it be to just make those attributes in the activity public, so that I can access them via the activity that has been passed (e.g myActivity.myArrayItemsList)?
Many thanks in advance for any advice!
Given that the only place this adapter will be used is from a particular activity, how bad would it be to just make those attributes in the activity public, so that I can access them via the activity that has been passed (e.g myActivity.myArrayItemsList)?
That's a bad code and bad behavior. You're code will be tightly coupled. And usually, you will borrow the same behavior to your next project.
Instead of passing each state to your constructor, you can simplify it by passing a State object to your adapter. Create the State class something like this:
public class State {
List<String> selectedItems;
boolean displayPeople;
}
then you can create a simple constructor like this:
State state = new State();
state.selectedItems = mSelectedItems;
state.displayPeople = true;
myAdapter = new MyAdapter(items, state, this);
So, whenever you need to update a new state, you just need to add it the State class and update the Adapter according to it.
Considering you are using the Item object for myArrayItemsList.
So your list should look like this:
ArrayList<Item> myArrayItemsList = new ArrayList();
and then you want to add the selected items in the list you could add a boolean to the Item object ex:
public class Item {
private String itemName;
private boolean selected = false;
public Item(){}
public String getItemName() {
return itemName;
}
public void setItemName(String itemName) {
this.itemName= itemName;
}
public boolean isSelected () {
return selected;
}
public void setSelected(boolean selected) {
this.selected= selected;
}
}
and just check your item list in the adapter if the item is selected.
So your adapter would only pass two parameters:
MyAdapter myAdapter = new MyAdapter(myArrayItemsList, this);
But then again you want to pass only one parameter in adapter, you can set your ArrayList to static
public static ArrayList<Item> myArrayItemsList = new ArrayList();
and pass only this your adapter
MyAdapter myAdapter = new MyAdapter(this);
used the static ArrayList in your adapter but it is not advisable using those static data because the data could be Garbage Collected in the memory.

After clearing the Recyclerview's Data(ArrayList), onLoadMore event of EndlessRecyclerOnScrollListener is not firing

I need to clear the data of recyclerview because I want to show the fresh data from the server, I dont know how to clear the recyclerview without affecting the infinite scrolling
Just clear your list your list in Adapter and call notifyDataSetChanged method.
public class RecyclerViewAdapter extends RecyclerView.Adapter<RelativeAdapter.ViewHolder> {
private List<model> mArrayList = new ArrayList<>();
public void clearList(){
mArrayList.clear();
notifyDataSetChanged();
}
}
just call the clearList() method when you want to clear list.
I got a solution, the issue was I did not reset EndlessRecyclerOnScrollListener counter variable which was basically calculating the logic for reaching last cardview of recyclerview.
There is another plugin which basically gives you method to reset counter variable
https://github.com/codepath/android_guides/wiki/Endless-Scrolling-with-AdapterViews-and-RecyclerView

Android Array Adapter with ArrayList and ListView not updating when the arraylist is changed

I have an android app with a screen that comprises of a ListView, which I am using to display a list of devices. These devices are held in an array.
I am trying to use the ArrayAdapter to display what is in the array on the screen in a list.
It works when I first load the SetupActivity class, however, there is the facility to add a new device in the addDevice() method, which means the array holding the devices is updated.
I am using notifyDataSetChanged() which is supposed to update the list but it doesn't seem to work.
public class SetupActivity extends Activity
{
private ArrayList<Device> deviceList;
private ArrayAdapter<Device> arrayAdapter;
private ListView listView;
private DevicesAdapter devicesAdapter;
private Context context;
public void onCreate(Bundle savedInstanceState) //Method run when the activity is created
{
super.onCreate(savedInstanceState);
setContentView(R.layout.setup); //Set the layout
context = getApplicationContext(); //Get the screen
listView = (ListView)findViewById(R.id.listView);
deviceList = new ArrayList<Device>();
deviceList = populateDeviceList(); //Get all the devices into the list
arrayAdapter = new ArrayAdapter<Device>(this, android.R.layout.simple_list_item_1, deviceList);
listView.setAdapter(arrayAdapter);
}
protected void addDevice() //Add device Method (Simplified)
{
deviceList = createNewDeviceList(); //Add device to the list and returns an updated list
arrayAdapter.notifyDataSetChanged(); //Update the list
}
}
Can anyone see where I am going wrong?
For an ArrayAdapter, notifyDataSetChanged only works if you use the add, insert, remove, and clear functions on the Adapter.
Use clear to clear the adapter - arrayAdapter.clear()
Use Adapter.addAll and add the newly formed list - arrayAdapter.addAll(deviceList)
Call notifyDataSetChanged
Alternatives:
Repeat this step after new devicelist is formed - but this is
redundant
arrayAdapter = new ArrayAdapter<Device>(this, android.R.layout.simple_list_item_1, deviceList);
Create your own class derived from BaseAdapter and ListAdapter that
gives you more flexibility. This is most recommended.
While the accepted answer solves the problem, the explanation of why is incorrect, and since this is an important concept I thought I'd attempt to clarify.
Slartibartfast's explanation that notifyDataSetChanged() only works when add, insert,remove, or clear is called on the adapter is incorrect.
That explanation is true of the setNotifyOnChange() method, which if set to true (as it is by default) will automatically call notifyDataSetChanged() when any of those four actions occur.
I think the poster confused the two methods. notifyDatasetChanged() itself does not have those restrictions. It just tells the adapter that the list it is looking at has changed, and it does not matter how the change to the list actually happened.
While I can't see the source code for your createNewDeviceList(), I would guess your problem came from the fact that you had the adapter referencing the original list you created, and then you created a new list in createNewDeviceList(), and since the adapter was still pointing to the old list it could not see the changes.
The solution slartibartfast mentioned works because it clears the adapter and specifically adds the updated list to that adapter. Thus you don't have the problem of your adapter pointing to the wrong place.
Hope this helps someone!
your method addDevice is causing an endless loop. Dont call a method from itself like you are doing here :
deviceList = addDevice();

java android load items to listview from database?

Okay so i have a database, and i want it so you can favorite items.
Would i make it so you can save items then it will load it into a list view?
this is my load thing
//Calls the database, gets a list of names.
// if listofnames.size()==0 keep name, otherwise
// change name to first name.
ArrayList<String> nameList = new ArrayList<String>();
favList = db.getName();
if(favList.size()>0){
name.setText(favList.get(0));
But that just sets a text i want it to add items..
You may use ArrayAdapter or SimpleAdapter or BaseAdapter - through which you may bind dataSource (List<T>) to the ListView.
You can do this as follows
public class MyClass extends ListActivity{
public void onCreate(Bundle bundle){
//get the names from database
setListAdapter(new ArrayAdapter<E>(this,R.layout.xml_filename,your_list);
}
}
Remember in this case your xml file should be the TextView (I.e the items what list view should contain). You cannot pass an xml file with a ListView directly.
If you have still some problem, then post your code which can be solved.
You can follow the given link for more clarification.
http://developer.android.com/resources/tutorials/views/hello-listview.html

Best way to refill data in ListAdapter (ListView)

I do use this code for refill ListView with data after they change
// ListView lv;
// MyListAdapter la;
// DataClass dc;
dc.remove(object_id);
lv.setAdapter(la);
Is this the best way since we can't use notifyDataSetChanged() which is available only in ArrayAdapter ?
Solution
//MyListAdapter.java
private ArrayList<DataSetObserver> observers = new ArrayList<DataSetObserver>();
public void registerDataSetObserver(DataSetObserver arg0) {
observers.add(arg0);
}
public void unregisterDataSetObserver(DataSetObserver arg0) {
observers.remove(arg0);
}
public void notifyDataSetChange() {
for (DataSetObserver d : observers) {
d.onChanged();
}
}
public void remove(int position) {
[DataClass object].remove(position);
notifyDataSetChange();
}
For a CursorAdapter I use the following code:
mAdapter.getCursor().requery();
If you are using custom adapter or as you commented: only want ListAdapter as member variable. Instead of using private CustomAdapter mAdapter; (which i would recommended to avoid creating unnecessary objects).
You can use DataSetObserver part and ListAdapter.registerDataSetObserver(DataSetObserver observer). DataSetObserver.onChanged() will be called by the BaseAdapter implementation, so it should work for all adapter.
BaseAdapter.notifyDataSetChanged():
public void notifyDataSetChanged() {
mDataSetObservable.notifyChanged();
}
You can use ArrayAdapter, which accepts Lists instead of Arrays. This way you can use notifyDataSetChanged() on it.
It seems that you think something wrong as I was did.
As you know, ListAdapter hasn't notifyDataSetChanged.
It seems that Cursor is the best match with a ListView. Doc. says that "Frequently that data comes from a Cursor, but that is not required. The ListView can display any data provided that it is wrapped in a ListAdapter."
If you check both links registerDataSetObserver ([DataSetObserver]2 observer), you can notice something. ListAdapter go well with a cursor. So why don't you try to use other adapters.
I think the best way to refresh adapter is using or extending BaseAdapter(with ListView). And use notifyDataSetChanged after change your dataset. In my case it works well and softly(invalidating list view and items, and scroll position is just there! Not going to first position).

Categories