Reputation: 23
I am having a problem within an activity that returns a ListView or a combination of several ListViews together merged with MergeAdapter from Commonsware. It is a search activity that based on the search query would return results from 1 or several different categories. When the categories are more than 1, I insert a header, which is another ListView with only one row - the name of the category.
Some code:
public class FirstAdapter extends ArrayAdapter<Address> {
public FirstAdapter (Context context, int resource,
int textViewResourceId, List<Address> objects) {
super(context, resource, textViewResourceId, objects);
}
public View getView (int position, View convertView, ViewGroup parent) {
View view = super.getView(position, convertView, parent);
Address location = this.getItem(position);
TextView textView = (TextView) view.findViewById(R.id.SearchResultTextAddress);
textView.setText(location.address);
return view;
}
}
Then I have a header adapter:
public class HeaderAdapter extends ArrayAdapter<String> {
private String header;
public HeaderAdapter(Context context, int resource,
int textViewResourceId, String header) {
super(context, resource, textViewResourceId, new ArrayList<String>());
this.header = header;
}
public void setVisible(boolean visible) {
if (visible) show();
else hide();
}
public void show() {
clear();
add(this.header);
}
public void hide() {
clear();
}
public View getView (int position, View convertView, ViewGroup parent) {
return super.getView(position, convertView, parent);
}
public String getHeader() {
return header;
}
public void setHeader(String header) {
this.header = header;
}
@Override
public boolean isEnabled(int position) {
return false;
}
}
Which as you can see will show only if necessary. And in my very activity I have a onListItemClick overridden:
@Override
protected void onListItemClick(ListView listview, View view, int position, long id) {
super.onListItemClick(listview, view, position, id);
if (this.firstAdapter.getCount() > 0) {
position--;
if (position < this.firstAdapter.getCount()) onRepClick(this.firstAdapter.getItem(position));
position = position - this.firstAdapter.getCount();
}
if (this.secondAdapter.getCount() > 0) {
position--;
if (position < this.secondAdapter.getCount()) onAusschussClick(this.secondHeader.getItem(position));
position = position - this.secondAdapter.getCount();
}
So everything works ok when I have only one category from one Adapter. The moment when I have results from two of them, I get an ArrayIndexOutOfBoundsException. I assume that my logic with getting the positions is not correct. Any thoughts would be appreciated, thanks.
Here is the stack trace:
06-28 12:56:54.291: E/AndroidRuntime(3963): FATAL EXCEPTION: main
06-28 12:56:54.291: E/AndroidRuntime(3963): java.lang.ArrayIndexOutOfBoundsException
06-28 12:56:54.291: E/AndroidRuntime(3963): at java.util.ArrayList.get(ArrayList.java:313)
06-28 12:56:54.291: E/AndroidRuntime(3963): at android.widget.ArrayAdapter.getItem(ArrayAdapter.java:298)
06-28 12:56:54.291: E/AndroidRuntime(3963): at com.jasamer.callarep.SearchActivity.onListItemClick(SearchActivity.java:136)
06-28 12:56:54.291: E/AndroidRuntime(3963): at android.app.ListActivity$2.onItemClick(ListActivity.java:319)
06-28 12:56:54.291: E/AndroidRuntime(3963): at android.widget.AdapterView.performItemClick(AdapterView.java:284)
06-28 12:56:54.291: E/AndroidRuntime(3963): at android.widget.ListView.performItemClick(ListView.java:3513)
06-28 12:56:54.291: E/AndroidRuntime(3963): at android.widget.AbsListView$PerformClick.run(AbsListView.java:1849)
06-28 12:56:54.291: E/AndroidRuntime(3963): at android.os.Handler.handleCallback(Handler.java:587)
06-28 12:56:54.291: E/AndroidRuntime(3963): at android.os.Handler.dispatchMessage(Handler.java:92)
06-28 12:56:54.291: E/AndroidRuntime(3963): at android.os.Looper.loop(Looper.java:130)
06-28 12:56:54.291: E/AndroidRuntime(3963): at android.app.ActivityThread.main(ActivityThread.java:3835)
06-28 12:56:54.291: E/AndroidRuntime(3963): at java.lang.reflect.Method.invokeNative(Native Method)
06-28 12:56:54.291: E/AndroidRuntime(3963): at java.lang.reflect.Method.invoke(Method.java:507)
06-28 12:56:54.291: E/AndroidRuntime(3963): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:847)
06-28 12:56:54.291: E/AndroidRuntime(3963): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:605)
06-28 12:56:54.291: E/AndroidRuntime(3963): at dalvik.system.NativeStart.main(Native Method)
Upvotes: 1
Views: 933
Reputation: 23
Well, solution came out to be different and much simpler. In the if statement I had to change: if (position < this.firstAdapter.getCount())
to the follwing:
if ((position < this.firstAdapter.getCount() && position >= 0))
In this way I would ensure that no negative numbers would be possible and index would be always correct no matter how many headers I have.
Upvotes: 1
Reputation: 1006869
I think you need some else
or return
logic in onListItemClick()
.
Let's say that position
is 1
, firstAdapter.getCount()
returns 383
, and secondAdapter.getCount()
returns 27
. You will go through the first if
block (383
is greater than 0
), where you subtract one from position
(which is now 0
) and process it. You will then go through the second block (27
is greater than 0
), where you subtract one from position
(which is now -1
), and you will crash trying to get at the -1
element. Since there is only one row identified by position
, it can only be in one of the adapters, and your existing code does not handle that case.
Upvotes: 0