All you need to do is move the setting of OnClickListener
on holder.textview
.
The problem here is:
: Since you set the OnClickListener in the if (convertView == null)
block, it isn't changed
when convertView is not null. So, the position
used in AlertDialog
is the one you set
when convertView
was null.
: Solution is to set the OnClickListener every time a position is processed - we don't care if
the view is recycled or not!!! We need to reset the OnClickListener to reflect the
correct/current position.
: Although, we never set an OnClickListener on holder.textview when item is TYPE_SEPARATOR
, its
safe to remove the OnClickListener using holder.textview.setOnClickListener(null)
.
Try the updated code below. I hope the logic here is quite clear.
//Adapter Class
private class MyCustomAdapter extends BaseAdapter {
....
....
public View getView(final int position, View convertView, ViewGroup parent) {
ViewHolder holder = null;
int type = getItemViewType(position);
System.out.println("getView " + position + " " + convertView + " type = " + type);
if (convertView == null) {
holder = new ViewHolder();
switch (type) {
case TYPE_ITEM:
convertView = mInflater.inflate(R.layout.activity_main1, null);
holder.textView = (TextView)convertView.findViewById(R.id.text);
break;
case TYPE_SEPARATOR:
convertView = mInflater.inflate(R.layout.activity_main2, null);
holder.textView = (TextView)convertView.findViewById(R.id.textSeparator);
break;
}
convertView.setTag(holder);
} else {
holder = (ViewHolder)convertView.getTag();
}
holder.textView.setText(mData.get(position));
// We set the OnClickListener here because it is unique to every
// item. Although views can be recycled & reused, an OnClickListener cannot be.
if (type == TYPE_ITEM) {
holder.textView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
AlertDialog.Builder x = new AlertDialog.Builder(
temp);
Log.v("position",""+position);
x.setIcon(R.drawable.ic_launcher)
.setTitle(q.get(position-1).getAS_name())
.setMessage(q.get(position-1).getDesc_art())
.setCancelable(true)
.setPositiveButton("OK",
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface arg,
int arg1) {
}
});
AlertDialog a = x.create();
a.show();
}
});
} else {
holder.textview.setOnClickListener(null);
}
return convertView;
}
....
....
}
Edit:
Wrapper class (can be implemented as an inner class of MainActivity1
or independently):
public class ContentWrapper {
private String mItem, mItemDescription;
public ContentWrapper(String item, String itemDescription) {
mItem = item;
mItemDescription = itemDescription;
}
public String getItem() {
return mItem;
}
public String getItemDescription() {
return mItemDescription;
}
}
Your data-setup will also change:
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
DBAdapter db = DBAdapter.getDBAdapter(getApplicationContext());
if (!db.checkDatabase())
{
db.createDatabase(getApplicationContext());
}
db.openDatabase();
q = db.getData();
mAdapter = new MyCustomAdapter();
// mAdapter.addSeparatorItem(q.get(0).getA_name());
// First separator item
// No description
mAdapter.addSeparatorItem(new ContentWrapper(q.get(0).getA_name(), null));
// mAdapter.addItem(q.get(0).getAS_name());
// First TYPE_ITEM
// Pass the description
mAdapter.addItem(new ContentWrapper(q.get(0).getAS_name(), q.get(0).getDesc_art()));
for (int i = 1; i < 460; i++) {
if (!(q.get(i).getA_name().trim().equals(q.get(i-1).getA_name().trim()))) {
// mAdapter.addSeparatorItem(q.get(i).getA_name());
mAdapter.addSeparatorItem(new ContentWrapper(q.get(i).getA_name(), null));
c++;
}
// mAdapter.addItem(q.get(i).getAS_name());
mAdapter.addItem(new ContentWrapper(q.get(i).getAS_name(), q.get(i).getDesc_art()));
}
setListAdapter(mAdapter);
}
Next, we make changes to the adapter:
// private ArrayList<String> mData = new ArrayList<String>();
private ArrayList<ContentWrapper> mData = new ArrayList<ContentWrapper>();
The add*
methods
public void addItem(ContentWrapper value) {
mData.add(value);
notifyDataSetChanged();
}
public void addSeparatorItem(ContentWrapper value) {
mData.add(value);
// save separator position
mSeparatorsSet.add(mData.size() - 1);
notifyDataSetChanged();
}
public ContentWrapper getItem(int position) {
return mData.get(position);
}
The getView(...)
method:
@Override
public View getView(final int position, View convertView, ViewGroup parent) {
....
....
holder.textView.setText(mData.get(position).getItem());
if (type == TYPE_ITEM) {
holder.textView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
AlertDialog.Builder x = new AlertDialog.Builder(temp);
Log.v("position",""+position);
x.setIcon(R.drawable.ic_launcher)
// .setTitle(q.get(position-count).getAS_name())
.setTitle(mData.get(position).getItem())
// .setMessage(q.get(position-count).getDesc_art())
.setMessage(mData.get(position).getItemDescription())
.setCancelable(true)
.setPositiveButton("OK",
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface arg,
int arg1) {
}
});
AlertDialog a = x.create();
a.show();
}
});
} else {
holder.textView.setOnClickListener(null);
}
}
And that's about it.
[I] think we should implement notifyDataSetChanged or onScroll,
onScrollStateChanged methods.
notifyDataSetChanged()
is used to tell the adapter that the underlying data has changed and thus a refresh is required. For example, if description for an item changes, you would update that item in mData
and call notifyDataSetChanged()
. But in your case (and from what your code tells me), your data is initialized before you set the adapter using - setListAdapter(mAdapter)
. So, calls to notifyDataSetChanged()
inside the add*
methods are not even required. Calling notifyDataSetChanged()
before attaching an adapter to a listview does nothing.
onScroll
and onScrollChanged
are meant for a different purpose. For example, say that you show a Go To Top of the List
button when the user scroll past the 50th item - and hide it when they scroll up the 50th position. In your case, the problem was that you were trying to get data from two different sources(mData, q) and there were issues with synchronization. Nothing else.