For my android application i'm using the ViewHolder pattern.
Whenever i click on an imageview in my listview the row get updated but other rows are also getting updated.
Whenever i click the "like" button other images also receive the image that the are liked by the user. How is this possible?
Here is my viewholder code:
public class MyAdapter extends ArrayAdapter<MyModel> {
Context context;
int layoutResourceId;
List<MyModel> data = null;
public MyAdapter(Context context, int layoutResourceId,
List<MyModel> data) {
super(context, layoutResourceId, data);
this.layoutResourceId = layoutResourceId;
this.context = context;
this.data = data;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View row = convertView;
final BlockHolder holder;
if (row == null) {
LayoutInflater inflater = ((Activity) context).getLayoutInflater();
row = inflater.inflate(layoutResourceId, parent, false);
holder = new BlockHolder();
holder.imgIcon = (ImageView) row.findViewById(R.id.imgIcon);
holder.totalVotes = (TextView) row.findViewById(R.id.totalVotes);
holder.likeIcon = (ImageView) row.findViewById(R.id.likeIcon);
holder.dislikeIcon = (ImageView) row.findViewById(R.id.dislikeIcon);
holder.saveIcon = (ImageView) row.findViewById(R.id.saveIcon);
row.setTag(holder);
} else {
holder = (BlockHolder) row.getTag();
}
MyModel myBlock = data.get(position);
ImageLoader.getInstance().displayImage(myBlock.getImage(),
holder.imgIcon);
final int totalLikes = myBlock.getLikes() - myBlock.getDislikes();
holder.totalVotes.setText(totalLikes + " likes");
final ImageView like = holder.likeIcon;
holder.likeIcon.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
// ALSO UPDATES OTHER VIEWS...
holder.likeIcon.setBackgroundResource(R.drawable.thumbs_up_mouse);
}
});
return row;
}
private static class BlockHolder{
ImageView imgIcon;
TextView totalVotes;
ImageView dislikeIcon;
ImageView likeIcon;
ImageView saveIcon;
}
Related
I have to click a button to show ListView with image. Unfortunately, the application stops when I click on the button. I have also set the custom adapter too but still the same. Here is the code:
public class R1 extends Activity {
String[] signTitle;
String[] signDescription;
int images[]={R.drawable.a,R.drawable.b,R.drawable.c,R.drawable.d,R.drawable.e,R.drawable. f,R.drawable.g,R.drawable.h};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.r1);
Resources res = getResources();
signTitle = res.getStringArray(R.array.titile);
signDescription = res.getStringArray(R.array.description);
ListView lv = (ListView) findViewById(R.id.listView);
Customlistadapter adapter = new Customlistadapter(this,signTitle,images,signDescription);
lv.setAdapter(adapter);}
customAdpater.java
public class Customlistadapter extends ArrayAdapter<String> {
Context context;
int[] images;
String[] titleArray;
String[] descriptionArray;
public Customlistadapter(Context c, String[] title, int imgs[],String[] desc) {
super(c, R.layout.activity_show,R.id.textView1,title);
this.context = c;
this.images = imgs;
this.titleArray = title;
this.descriptionArray = desc;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
// TODO Auto-generated method stub
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View row = inflater.inflate(R.layout.activity_show, parent,false);
ImageView myImage = (ImageView) row.findViewById(R.id.image);
TextView myTitle = (TextView) row.findViewById(R.id.textView1);
TextView myDescription = (TextView) row.findViewById(R.id.textView2);
myImage.setImageResource(images[position]);
myTitle.setText(titleArray[position]);
myDescription.setText(descriptionArray[position]);
return row;
}
}
If you could post the LogCat or at least point out the line which produces the error, we could help you better.
Also Initializing a ListView like this is highly inefficient.
Implementing a Viewholder Patter helps.
Optimized CustomListAdapter
public class CustomListAdapter extends ArrayAdapter<String>
{
Context context;
int[] images;
String[] titleArray;
String[] descriptionArray;
public CustomListAdapter(Context c, String[] title, int imgs[],String[] desc) {
super(c, R.layout.activity_show,R.id.textView1,title);
this.context = c;
this.images = imgs;
this.titleArray = title;
this.descriptionArray = desc;
// TODO Auto-generated constructor stub
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
// TODO Auto-generated method stub
ViewHolder viewHolder;
if(convertView == null)
{
viewHolder = new ViewHolder();
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(R.layout.activity_show, parent,false);
viewHolder.title = (TextView)convertView.findViewById(R.id.textView1);
viewHolder.description = (TextView)convertView.findViewById(R.id.textView2);
viewHolder.image = (ImageView) convertView.findViewById(R.id.image);
convertView.setTag(viewHolder);
}
else
{
viewHolder = (ViewHolder) convertView.getTag();
if(titleArray[position] != null)
{
viewHolder.image = (ImageView) convertView.findViewById(R.id.image);
viewHolder.title= (TextView) convertView.findViewById(R.id.textView1);
viewHolder.description = (TextView) convertView.findViewById(R.id.textView2);
viewHolder.image.setImageResource(images[position]);
viewHolder.title.setText(titleArray[position]);
viewHolder.description.setText(descriptionArray[position]);
}
}
return convertView;
}
private class ViewHolder
{
TextView title,description;
ImageView image;
}
}
I've been attempting to upgrade an old app I made in college, including adding a listview to show data from Last.FM. The idea is having a main text with subtext under it, but the adapter I put together just isn't working. I've tried a good number of options, and the most recent is giving me a "Attempt to invoke virtual method on a null object reference" error, a previous try got a "Cannot cast Activity to Application" error.
Relevant code sections:
Main Activity adapter section:
ListView lv;
final Dialog dialog = new Dialog(MainActivity.this);
dialog.setContentView(R.layout.summarylayout);
dialog.getWindow().setLayout(WindowManager.LayoutParams.MATCH_PARENT,
WindowManager.LayoutParams.MATCH_PARENT);
lv = (ListView) dialog.findViewById(R.id.itemList); //Listview name
artistAdapter = new itemAdapter(getApplicationContext(), //Changed from ArrayAdapter<Item>
R.layout.custom_listview, //R.layout.custom_listview if itemAdapter works
result.toArray(new Item[] {}));
lv.setAdapter(artistAdapter);
lv.setOnItemClickListener(new MyOIListener());
Button closeButton = (Button) dialog
.findViewById(R.id.closeBtn);
// if button is clicked, close the custom dialog
closeButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
tracks = false;
dialog.dismiss();
}
});
The custom Adapter itself (Commented sections are previous attempts):
public class itemAdapter extends ArrayAdapter<Item>{
Context context;
int layoutResourceId;
Item data[] = null;
public itemAdapter(Context context, int layoutResourceId, Item[] data) {
super(context, layoutResourceId, data);
this.layoutResourceId = layoutResourceId;
this.context = context;
this.data = data;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View row = convertView;
// ItemHolder holder = null;
Item rowIn = new Item();
TextView main;
TextView sub;
if(row == null)
{
//LayoutInflater inflater = ((Application)context).getLayoutInflater();
//row = inflater.inflate(layoutResourceId, parent, false);
//row = LayoutInflater.from(getActivity()).inflate(R.layout.custom_listview, parent, false);
LayoutInflater inflater = LayoutInflater.from(this.getContext());
row = inflater.inflate(layoutResourceId, parent, false);
//holder = new ItemHolder();
//rowIn = new Item();
}
else
{
rowIn = (Item) row.getTag();
}
main = (TextView)row.findViewById(R.id.mainText);
sub = (TextView)row.findViewById(R.id.subText);
row.setTag(rowIn);
Item temp = data[position];
main.setText(temp.getTitle());
sub.setText(temp.getExtra());
return row;
}
/* static class ItemHolder
{
TextView mainText;
TextView subText;
}*/
}
The "Item" class is simply a holder for text/URLs parsed from the Last.FM api request.
I realize this is a question asked often, but 3 days of attempts and searching hasn't helped me out much. Any help would be appreciated
You're passnig the applicationContext to your adapter. Pass your Activity by:
artistAdapter = new itemAdapter(MainActivity.this, //Changed from ArrayAdapter<Item>
R.layout.custom_listview, //R.layout.custom_listview if itemAdapter works
result.toArray(new Item[] {}));
Your getView method was wrong, actually you will face a null variable there when getting the data from the tag.
This one should work for you, it is using ViewHolder Pattern
public class itemAdapter extends ArrayAdapter<Item> {
Context context;
int layoutResourceId;
Item data[] = null;
public itemAdapter(Context context, int layoutResourceId, Item[] data) {
super(context, layoutResourceId, data);
this.layoutResourceId = layoutResourceId;
this.context = context;
this.data = data;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
ItemHolder holder = null;
if (convertView == null) {
//LayoutInflater inflater = ((Application)context).getLayoutInflater();
//row = inflater.inflate(layoutResourceId, parent, false);
//row = LayoutInflater.from(getActivity()).inflate(R.layout.custom_listview, parent, false);
LayoutInflater inflater = ((Activity) this.context).getLayoutInflater();
convertView = inflater.inflate(layoutResourceId, parent, false);
holder = new ItemHolder();
holder.mainText = row.findViewById(R.id.mainText);
holder.subText = row.findViewById(R.id.subText);
convertView.setTag(holder);
} else {
holder = (ItemHolder) convertView.getTag();
}
Item temp = data[position];
if(temp != null) {
holder.mainText.setText(temp.getTitle());
holder.subText.setText(temp.getExtra());
}
return convertView;
}
static class ItemHolder {
TextView mainText;
TextView subText;
}
}
And as #vinitius said, pass your Activity context to the adapter.
I have made a custom adapter for a autocompletetextview, but it's not filtering on the text and inputting weird strings when you select a item. Like this string:
listadapters.LocatieRowItem#BSE433q4e30
I have made this adapter so the first item of the autocompletetextview could have a image and a different color then the rest.
Here is my custom adapter:
public class LocatieAdapter extends ArrayAdapter<LocatieRowItem> {
Context context;
private List<LocatieRowItem> items;
public LocatieAdapter(Context context, int resourceId, List<LocatieRowItem> items) {
super(context, resourceId, items);
this.context = context;
this.items = items;
}
/*private view holder class*/
private class ViewHolder {
ImageView imageView;
TextView txtTitle;
}
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder = null;
LocatieRowItem rowItem = items.get(position);
LayoutInflater mInflater = (LayoutInflater) context
.getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
if (convertView == null) {
convertView = mInflater.inflate(R.layout.locatieitem, null);
holder = new ViewHolder();
holder.txtTitle = (TextView) convertView.findViewById(R.id.text1);
holder.imageView = (ImageView) convertView.findViewById(R.id.logo);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
if(rowItem.getTitle().equals("huidige locatie")) {
if (holder.imageView.getVisibility() != View.VISIBLE) {
holder.imageView.setVisibility(View.VISIBLE);
holder.txtTitle.setTextColor(Color.parseColor("#33B5E5"));
holder.txtTitle.setPadding(40, 10, 5, 5);
}
} else {
holder.imageView.setVisibility(View.GONE);
holder.txtTitle.setTextColor(Color.parseColor("#333333"));
holder.txtTitle.setPadding(10, 10, 10, 10);
}
holder.txtTitle.setText(rowItem.getTitle());
//convertView.setBackgroundColor(position % 2 == 0 ? Color.WHITE : Color.parseColor("#F8F8F8"));
return convertView;
}
}
I am so sorry for my bad English, but here is my problem :
I use a custom ListView like ArrayAdapter and I create my ArrayAdapter as a intern class in my main Activity like that :
/*This is my Main Activity*/
public class KhassaideActivity extends Activity {
ViewHolder holder;
KhassaideAdapterbi listadapter ;
ListView l ;
#Override
protected void onCreate(Bundle savedInstanceState) {
l= (ListView) findViewById(R.id.listDieuzbou);
listadapter = new KhassaideAdapterbi(this, R.layout.affichage_khassaide, rowItems);
l.setAdapter(listadapter);
}
/*This is my intern class ArrayAdapter*/
private class KhassaideAdapterbi extends ArrayAdapter<RowItem>{
Context context;
public KhassaideAdapterbi(Context context, int resourceId,
List<RowItem> items) {
super(context, resourceId, items);
this.context = context;
}
public class ViewHolder {
ImageView imageView;
TextView trad;
TextView trans;
TextView number;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
RowItem rowItem = getItem(position);
LayoutInflater mInflater = (LayoutInflater) context
.getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
if (convertView == null) {
holder = new ViewHolder();
convertView = mInflater.inflate(R.layout.affichage_khassaide, null);
holder.number = (TextView) convertView.findViewById(R.id.number);
holder.trad = (TextView) convertView.findViewById(R.id.traduction);
holder.trans = (TextView) convertView.findViewById(R.id.transcription);
holder.imageView = (ImageView) convertView.findViewById(R.id.arabe);
convertView.setTag(holder);
}
else
holder = (ViewHolder) convertView.getTag();
holder.trad.setText(rowItem.getTitle());
holder.trans.setText(rowItem.getDesc());
holder.imageView.setImageResource(rowItem.getImageId());
holder.number.setText(rowItem.getNumber());
return convertView;
}
}
So in my main Activity I want to access and share the values of the two TextView when the user click on a menu item like that :
case R.id.action_share:
Intent sendIntent = new Intent();
sendIntent.setAction(Intent.ACTION_SEND);
sendIntent.putExtra(Intent.EXTRA_TEXT, listadapter.holder.trad.getText());
sendIntent.setType("text/plain");
startActivity(Intent.createChooser(sendIntent, getResources().getText(R.string.send_to)));
But I get a NullPointerException at this line listadapter.holder.trad.getText()
Is anyone have a solution for that? Thank you in advance. And sorry once again for this bad english
you should change this....
private class KhassaideAdapterbi extends ArrayAdapter<RowItem>{
Context context;
List<RowItem> Rowitems;
public KhassaideAdapterbi(Context context, int resourceId,
List<RowItem> items) {
super(context, resourceId, items);
this.context = context;
this.Rowitems = items;
}
now get data from Rowitems ...
I have a custom ListView with a TextView and a CheckBox. I also have a custom SimpleAdapter in which I override the getView() method and am able to retrieve clicks on the TextView and CheckBox changes. My problem is that I don't know how to get the correct clicked ListItem or CheckBox inside the OnCheckedChanged or OnClick.
UPDATE added whole CustomAdapter class:
public class CustomAdapter extends SimpleAdapter {
private LayoutInflater mInflater;
private List<HashMap<String, String>> mItems = null;
private Context mContext;
private int mPosicion;
public CustomAdapter(Context context, List<HashMap<String, String>> items, int resource, String[] from, int[] to) {
super(context, items, resource, from, to);
mInflater = LayoutInflater.from(context);
mItems = items;
mContext = context;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
mPosicion = position;
if (convertView == null) {
convertView = mInflater.inflate(R.layout.custom_row_view, null);
holder = new ViewHolder();
holder.chkbxEstado = (CheckBox) convertView.findViewById(R.id.chkbxCompletado);
holder.txtTextoAgenda = (TextView) convertView.findViewById(R.id.txtTextoLista);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
holder.txtTextoAgenda.setText(mItems.get(position).get("descripcion"));
convertView.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
Log.i("Posicion",""+mPosicion);//I don't know how to retrieve clicked position
}
});
holder.chkbxEstado.setOnCheckedChangeListener(new OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
Log.i("Posicion",""+mPosicion);//Or checked
}
});
return convertView;
}
private static class ViewHolder {
TextView txtTextoAgenda;
CheckBox chkbxEstado;
}
}
Any help is appreciated.
I found a solution. If anybody knows a better one, please let me know. Working CustomAdapter class:
public class CustomAdapter extends SimpleAdapter {
private LayoutInflater mInflater;
private List<HashMap<String, String>> mItems = null;
private Context mContext;
private OnClickListener mClick;
private OnCheckedChangeListener mChecked;
public CustomAdapter(Context context, List<HashMap<String, String>> items, int resource, String[] from, int[] to) {
super(context, items, resource, from, to);
mInflater = LayoutInflater.from(context);
mItems = items;
mContext = context;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
if (convertView == null) {
convertView = mInflater.inflate(R.layout.custom_row_view, null);
holder = new ViewHolder();
holder.chkbxEstado = (CheckBox) convertView.findViewById(R.id.chkbxCompletado);
holder.txtTextoAgenda = (TextView) convertView.findViewById(R.id.txtTextoLista);
holder.posicion = position; //Add the new position into the holder for each row.
convertView.setTag(holder);
mClick = new OnClickListener() {
#Override
public void onClick(View v) {
ViewHolder viewHolder = getViewHolder(v); //Get the ViewHolder for the clicked row.
Log.i("Posicion",""+v.posicion);
}
};
mChecked = new OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
ViewHolder viewHolder = getViewHolder(buttonView); //Get the ViewHolder for the clicked CheckBox
Log.i("Posicion",""+viewHolder.posicion);
}
};
} else {
holder = (ViewHolder) convertView.getTag();
}
holder.txtTextoAgenda.setText(mItems.get(position).get("descripcion"));
convertView.setOnClickListener(mClick);
holder.chkbxEstado.setOnCheckedChangeListener(mChecked);
return convertView;
}
public ViewHolder getViewHolder(View v){ //This method returns the ViewHolder stored in the tag if available, if not it recursively checks the parent's tag.
if(v.getTag() == null){
return getViewHolder((View)v.getParent());
}
return (ViewHolder)v.getTag();
}
private static class ViewHolder {
TextView txtTextoAgenda;
CheckBox chkbxEstado;
int posicion; //Added position attribute to ViewHolder class.
}
}
Edited to re-use onClickListener() and onCheckedChangedListener() instances.
The OP's solution works. But if you are extending a CursorAdapter, the position parameter does not exist in newView() and bindView(). What to do?
They do supply a Cursor. Use cursor.getPosition(). It does the same thing.