I am looking at this ListView Tutorial:
ListView Tutorial
and I was wondering how much better is to create my own ArrayAdapter, rather than just using and ArrayAdapter.
In the Tutorial it defines a "StableArrayAdapter", what exactly does this means? If I use a regular ArrayAdapter, could it be dangerous for some reason?
The two previous answers are absolutely right, but just to address more directly your question and in case someone else has the same doubt than you; a regular ArrayAdapter is not dangerous at all, the only "problem" is that it might not fulfill your needs, in which case you will have to create your own adapter, as the author of the tutorial did by creating what he called StableArrayAdapter in the end of the ListViewExampleActivity class.
Don't get lost by the name, which I guess comes from the fact that the overwritten method "hasStableIds" always returns true, it doesn't mean that the regular ArrayAdapter creates problems.
ArrayAdapter: It is merely a way to provide data to a ListView. It is also a BaseAdapter that is backed by an array of objects.
CustomAdapter: If if your ListView is a normal and simple ListView (wherein you are having one TextView per item in the list), then the use of ArrayAdapter would be apt.
But it is recommended you to create your own CustomAdapter which extends an ArrayAdapter that you can use for providing data to your ListView. This way you can easily extend your ListView to include more that one TextView or even ImageView (to show images).
CursorAdapter: Cursor Adapter is used when you have Data in a Cursor (typically when you are retrieving data from a database. The Cursor must include a column named "_id" or this class will not work.
If you are using a simple ListView, like merely a TextView per item, then just use the standard ArrayAdapter, on the other hand, if you want a custom item in the list, as in a combinations of views within each item in the ListView, then extend the ArrayAdapter and implement it to your needs.
StableArrayAdapter is merely an extended version of ArrayAdapter, but in StableArrayAdapter they have overridden the method hasStableIds() of BaseAdapter to return true.
You can check this in the following links:
StableArrayAdapter -
Override hasStableIds to return true
ArrayAdapter -
Has not Override hasStableIds but extended BaseAdapter
BaseAdapter -
Has hasStableIds but returning false
Now Question is What is the use of StableIds
This Indicates whether the item ids are stable across changes to the underlying data. If True then same id always refers to the same object. for more info
Related
So, I am running up against a limitation of the Parse SDK here, and I don't know how to proceed.
I have a ListView that I am setting the adapter to from a subclass of the ParseQueryAdapter, which itself extends the BaseAdapter class.
Normally with an adapter, I pass the list along to the Adapter constructor in order to get access to the list I am dealing with, so that I can call getCount, getItem, etc. by accessing the size/index of that ArrayList.
I can't do that with the ParseQueryAdapter because it takes a ParseQueryFactory as part of the constructor, and it doesn't resolve it's items until they are fetched from the Parse app online...
Now the ParseQueryAdapter does have a List of Objects, which is exactly what I need, expect that it is Private... so even though the getItem() and getCount() methods exist, there is no way - AFAIK - to use them, as I have no access to the dataset that is fuelling my adapter...
Further to this, I would normally use getView(), which returns a position alongside my View, and everything would be snappy. Except Parse overrides that and provides a getItemView() method which resolves the Parse Object that is fetched from the cloud and passes it instead of the integer for position...
So, two questions here:
1) Is there another way in which I can access the list that is feeding an adapter ? I can hack a way to pass the resolved query into a list and pass that into the adapter later, by listening to addOnQueryLoadListener(), but that seems bad design and might take a while, handcuffing my UI.
2) Am I being naive in my understanding of how to use get getItem() and getCount() methods ?
I am working on android app in which I am using adapters to populate the data in a listview. I am confused where we should use BaseAdapter. I read many questions where it is written that we should use ArrayAdapter for arrays and arraylist that is ok and CursorAdapter in case of cursor.
I know BaseAdapter is the super class of ArrayAdapter and CursorAdapter. I have checked already this question What is the difference between ArrayAdapter , BaseAdapter and ListAdapter but it don't explain when we should use BaseAdapter.
When should I use BaseAdapter ?
You should use it:
if your model data is not already in a data structure for which there is a concrete ListAdapter class, and
if you determine that creating a custom adapter will be better for the user, or perhaps less development work for you, than would be reorganizing your data structure
For example, suppose that you use JSONArray to parse a snippet of JSON. JSONArray does not implement the List interface, and therefore you cannot use it with ArrayAdapter. None of the other adapters match. Yet, you want to show this JSONArray in an AdapterView. In that case, your choices are:
roll through the data and convert it into an ArrayList, so you can use ArrayAdapter, or
create a custom subclass of BaseAdapter that can adapt a JSONArray (a JSONArrayAdapter)
stop using JSONArray and instead use something else for parsing your JSON, like Gson, which can populate a List directly, allowing you to use ArrayAdapter
If your data is available in a Collection you can go with an ArrayAdapter. (use the addAll method to put your data in the adapter)
If your data is not in a Collection: then you can't and you must find another adapter that suits your needs. (typically: use a CursorAdapter when data comes from a database)
If you can't find any existing adapter working fine with your data structure/data source : you can write a subclass of BaseAdapter to support your own data structure.
If you plan to display your data in a ListView (this is a common use-case): then you must ensure that your adpter also implements ListAdapter (because the ListView needs a ListAdapter).
Note that ArrayAdapter and CursorAdapter implements ListAdapter.
When we use ArrayAdapter we pass something like a list to the super class. But base adapter constructor doesn't have any parameters. How does this class find the data set? I have seen in some examples they just define an array and override the functions without specifying the list as the Dataset. So how does the class understand this is the dataset? What if we define more than one list in the derived class?
Edit:
I think I should clarify my question. When we use ArrayAdapter the dataset is specified and the program knows what to iterate and calls getView for each of them. But in BaseAdapter we only define a list and override 4 functions and it works! My question is why does it work?! we didn't specify the dataset we just specify the getView body and it returns a view. I don't understand how the program finds the dataset.
As the documentation explains it well :
Common base class of common implementation for an Adapter
Means you have to do the implementation.
http://developer.android.com/reference/android/widget/BaseAdapter.html
How does this class find the data set?
It doesn't. Your subclass of BaseAdapter manages the data set.
What if we define more than one list in the derived class?
So long as you implement the abstract Adapter methods properly (getCount(), getView(), getItem(), getItemId(), ...), how you manage your own data is up to you.
Well after more considerations on the codes I think this is how base adapter works:
It loops the getView() function with 'position' parameter to be from 0 to what is returned by getCount().
we must override getCount() and send the correct index of the last item of dataSet. Each time getView() is called we can work with the views and any list we want according to the current position.
And I think the main difference between ArrayAdapter and BaseAdapter is that ArrayAdapter finds the last index of the list when we pass it to the super class but in base Adapter we should define the last index. Implementation of getView() is the same and we can use any list we want in getView. The trick was only about position parameter.
I have a seperate DatabaseHandler("db") Class which extends SQLiteOpenHelper BUT NOT ACTIVITY which means this is a seperate class file which is not related to any activity. If you ask why i have such a class not in activity because i like keeping my files organized.
So i have listview in a fragment and i have a "DatabaseHandler.getAllRows()" function in that class which returns a "List" Object. Then i want to use this list to populate my listview.
So when this class is a seperate class which is not related to any activity, i can't use simplecursorAdapter since it wants a context in paramteres part when creating with new(i tried to send parameter as context but didnt work) so i need to use something else....
I can change return type, i can use another thing instead of listview.. just give me a good advice for how to populate listview or show table rows NICELY.
If you want a real simple solution, you can store your rows as an array, and use ArrayAdapter to display them. You can override the getView to display the results in your preferred way.
If this solution is not good enough, I think you will have to implement your own Adapter, which might be a good idea anyway.
While writing my own adapter that extends the ArrayAdapter class, I came across the different constructors available and I noticed they all require a textViewResourceId parameter. So initially, I decided that I would feed my custom adapter class android.R.id.text1:
MyAdapter adapter = new MyAdapter(this, R.layout.myRow, android.R.id.text1);
However, later on during my development, I decided to override getView method where I would
TextView label = (TextView) myRow.findViewById(android.R.id.text1);
label.setText("Position #" + position);
Which worked fine. But then this question came to mind: if I'm doing the logic for how to display the row, is it really necessary to provide a textViewResourceId to the constructor when I initiate my custom adapter? Or is it the case that when you override getView, that parameter is no longer necessary? If my thinking is correct, what is the common practice for instantiating the adapter knowing that you will be overriding the display behavior anyways?
If you are overriding getView you do NOT need to specify a proper textViewResourceId.. You can pass in 0. The only time the ArrayAdapter tries to access that ID is within getView.. Since you are overriding getView and providing your own view textViewResourceId is never accessed..
Since the super class expects a view ID.. you still need to pass in a view ID into the super call.. however, it can just be 0 since it will never be used
ArrayAdapter Source confirming all of this
If you do not specify a proper textViewResourceId and do not override getView.. getView in the ArrayAdapter assumes your entire view is a TextView.. If your view is not a TextView.. you will end up with crashes from a ClassCastException..
you don't need to use any kind of build in adapter.
you can extend the BaseAdapter and make your own rules of what to show , what type of data to hold etc...
in fact , i almost never used the built in adapters that android has out of the box , because using the baseAdapter is very easy as it is.