Issues looping through listview Android - java

I have some issues looping through all objects in a listview that uses my own custom adapterclass. The idea is that for each row where a checkbox is checked, something happens. Now, the function checkBoxCount correctly identifies the number of checked boxes and which position. However, when i check more than one box i get:
java.lang.IndexOutOfBoundsException: Invalid index 1, size is 0
The error occurs at the row where i assign the listitem to "f".
void checkBoxCount(){
for (int i = 0; i < list.getCount(); i++) {
CheckBox cb = list.getChildAt(i).findViewById(R.id.checkBoxSendAnytimerTo);
if (cb.isChecked()){
Log.d("i= ",String.valueOf(i));
f = (Friend) list.getItemAtPosition(i);
}
}
}
This is my adapter because i feel like somethings going wrong there:
public class SendAnytimerAdapter extends ArrayAdapter<Friend> {
ArrayList<Friend> friendList = new ArrayList<>();
public SendAnytimerAdapter(Context context, int textViewResourceId, ArrayList<Friend> objects) {
super(context, textViewResourceId, objects);
friendList = objects;
}
#Override
public int getCount() {
return super.getCount();
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View v;
LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v = inflater.inflate(R.layout.send_anytimer_adapter_layout, null);
TextView textView1 = (TextView) v.findViewById(R.id.textViewSendAnytimerAdapterName);
TextView textView2 = (TextView) v.findViewById(R.id.textViewSendAnytimerAdapterCount);
textView2.setText(friendList.get(position).getAnytimerCountFriend());
textView1.setText(friendList.get(position).getfriendUserName());
return v;
}
Any clues on where my mistake lies?
Thanks in advance!

You need to override the method getCount
#Override
public int getCount() {
return friendList.size();
}

Related

ListView using BaseAdapter not showing in Activity

I'm trying to inflate a list using baseadapter within an activity. The list just doesn't inflate. From the logs implemented within the class, the getView() function doesn't even execute. Here's the code. -
public class CallLog extends Activity {
ListView logList;
List mList;
Context mCtx;
ArrayList<String> logName;
ArrayList<String> logNumber;
ArrayList<String> logTime;
#Override
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.reject_call_log);
mCtx = getApplicationContext();
ListView logList = (ListView) findViewById(R.id.log_list);
mList = new List(mCtx, R.layout.log_row);
logList.setAdapter(mList);
SharedPreferences savedLogName = PreferenceManager.getDefaultSharedPreferences(mCtx);
SharedPreferences savedLogNumber = PreferenceManager.getDefaultSharedPreferences(mCtx);
SharedPreferences savedLogTime = PreferenceManager.getDefaultSharedPreferences(mCtx);
try{
logName = new ArrayList(Arrays.asList(TextUtils.split(savedLogName.getString("logName", null), ",")));
logNumber = new ArrayList(Arrays.asList(TextUtils.split(savedLogNumber.getString("logNumber", null), ",")));
logTime = new ArrayList(Arrays.asList(TextUtils.split(savedLogTime.getString("logTime", null), ",")));
Collections.reverse(logName);
Collections.reverse(logNumber);
Collections.reverse(logTime);
}catch(NullPointerException e){
e.printStackTrace();
//TextView noLog = (TextView)findViewById(R.id.no_log);
}
}
public class List extends BaseAdapter {
LayoutInflater mInflater;
TextView nameText;
TextView numberText;
TextView timeText;
int timePos = 1;
public List(Context context, int resource) {
}
#Override
public int getCount() {
return 0;
}
#Override
public Object getItem(int i) {
return null;
}
#Override
public long getItemId(int i) {
return 0;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View v = convertView;
if (convertView == null) {
v = mInflater.inflate(R.layout.row, null);
}
nameText = (TextView) v.findViewById(R.id.log_name);
numberText = (TextView) v.findViewById(R.id.log_number);
timeText = (TextView) v.findViewById(R.id.log_time);
nameText.setText(logName.get(position));
numberText.setText(logNumber.get(position));
timeText.setText(logTime.get(timePos) + logTime.get(timePos+1));
Log.d("RejectCall", "ListView");
timePos+=2;
return v;
}
}
}
Where is it all going wrong? Also, is there a better way to do what I'm trying to do?
Please replace the following code :
#Override
public int getCount() {
return 0;
}
with
#Override
public int getCount() {
return logName.size();
}
As list view only show the numbers of rows that is returned by this method and right now you are returning 0;
And after fetching the data in arraylist please use adapter.notifyDataSetChanged() to notify the list view.
You have to call notifyDataSetChanged() as you are filling data in array list after setting the adapter. so to notify the list view that data has been changed you have to call notify method(as above)
Your getItem() and getCount() haven't been implemented. If you want any kind of adapter to work for the list, these need to be implemented. Your list is also not holding any actual data, so getItem() has nothing to set.
Don't forget to call notifiyDataSetChanged() in your adapter after you set appropriate implementations for the above two functions.

java.lang.IllegalArgumentException: Can't have a viewTypeCount < 1

I'm getting this error:
java.lang.IllegalArgumentException: Can't have a viewTypeCount < 1
I'm pretty sure I know exactly what's causing it, but I don't know how to fix it.
My app loads a users friends from the database. When the user has at least 1 friend to put in the list view, it's fine. When the user is brand new and has no friends yet, the app crashes because the listview has a count of 0.
Is this simply a case of error handling?
If I don't post all the necessary relevant code please let me know!
Here is my adapter:
public class MyAdapter extends ArrayAdapter<HashMap<String, String>> {
Context context;
int resourceId;
LayoutInflater inflater;
private Context mContext;
#Override
public int getViewTypeCount() {
return getCount();
}
#Override
public int getItemViewType(int position) {
return position;
}
ArrayList<HashMap<String, String>> items;
public MyAdapter (Context context, int resourceId, ArrayList<HashMap<String, String>> items)
{
super(context, resourceId, items);
mContext = context;
this.items =items;
inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
#Override
public View getView(int position, View convertView, ViewGroup parent){
final ViewHolder holder;
if (convertView == null){
convertView = inflater.inflate(R.layout.list_item, null);
holder = new ViewHolder();
holder.fbphoto = (ImageView)convertView.findViewById(R.id.fbphoto);
holder.name = (TextView)convertView.findViewById(R.id.name);
convertView.setTag(holder);
} else {
holder = (ViewHolder)convertView.getTag();
}
final HashMap<String,String> item = (HashMap<String,String> ) items.get(position);
if (item != null)
{
String facebookProfilePicUrl = "https://graph.facebook.com/"+item.get(TAG_FACEBOOKID)+"/picture?width=150&height=150";
Picasso.with(mContext)
.load(facebookProfilePicUrl)
.placeholder(R.drawable.no_image)
.into(holder.fbphoto);
holder.name.setText(item.get(TAG_USERNAME));
}
return convertView;
}
public class ViewHolder
{
ImageView fbphoto;
TextView name;
}
}
I think you miss the point of ViewTypeCount. You should return the number of Different View Types in your list.
This is important for recycling of the Views inside the List.
Imaging you have 2 Types of Listitems, one with a white Background and one with black Background. When you return 2 as ViewTypeCount the Listview knows ok, there a 2 types of Listitems and will not mix them up in the getView view recycling.
so just use:
public int getViewTypeCount() {
return 1;
}
or dont override that method at all.
Use this
#Override
public int getViewTypeCount() {
if(getCount() > 0){
return getCount();
}else{
return super.getViewTypeCount();
}
}
getViewTypeCount returns the number of different types of views this adaptor can return. Since you're only returning one type of view, this should just return 1.
Change this function in your Adapter class:
#Override
public int getViewTypeCount() {
return getCount();
}
to:
public int getViewTypeCount() {
if(getCount()<1) return 1;
return getCount();
}
**note: avoid #Override

Array of string with JSON and custom adapter

Good morning, i'm retrieving some values from my MySQL database because i want to display them into a ListView with custom adapter. I have this code.
for(int i=0; i<jsonArray.length();i++) {
ogge = new Ogge();
json = jsonArray.getJSONObject(i);
ogge.title = json.getString("Title");
ogge.array = new String[] {json.getString("field1"), json.getString("field2"), json.getString("field3"), json.getString("field4"), json.getString("field5"), json.getString("field6")};
ogge.adapter = Ogge.MY_CUSTOM;
list.add(ogge);
}
This for is correct because the values are put in the array in Ogge class. This is the adapter
case Ogge.MY_CUSTOM:
view = inflater.inflate(R.layout.custom, null);
textView = (TextView)view.findViewById(R.id.textView1);
textView2 = (TextView)view.findViewById(R.id.textView2);
textView3 = (TextView)view.findViewById(R.id.textView3);
textView.setText(Html.fromHtml(ogge.title));
textView2.setText(MyJsonClass.DATABASE_FIELD[position]);
textView3.setText(ogge.array[position]);
break;
The problem is the follow: when i open my app i see only the first and the second value of ogge.array but i want to show all. If i make a for into the adapter to get the value from the array the values are all stored into the array so the array is correct but, then, why i show only the first two values and not all?
Adapter full code
public MyCustomAdapter(Context context, int resource, ArrayList<Ogge> list) {
super(context, resource, list);
// TODO Auto-generated constructor stub
this.context = context;
this.list = list;
}
#SuppressLint("CutPasteId")
#Override
public View getView(int position, View view, ViewGroup parent) {
inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
final Ogge ogge = list.get(position);
switch(ogge.adapter) {
case Ogge.MY_CUSTOM:
view = inflater.inflate(R.layout.custom, null);
textView = (TextView)view.findViewById(R.id.textView1);
textView2 = (TextView)view.findViewById(R.id.textView2);
textView3 = (TextView)view.findViewById(R.id.textView3);
textView.setText(Html.fromHtml(ogge.title));
textView2.setText(MyJsonClass.DATABASE_FIELD[position]);
textView3.setText(ogge.array[position]);
break;
}
return view;
}
#Override
public boolean isEnabled(int position) {
return false;
}
}

Delete item from listview

I have listview which contains textview and buttons. When i delete listview item and i try to scroll down, i get exception on this:
BuildQueue eile = countryList.get(position);
Exception:
02-08 19:11:04.279: E/AndroidRuntime(10509): java.lang.IndexOutOfBoundsException: Invalid index 15, size is 15
Seems i do not updating something when i delete item from listview. I think i have problem with ViewHolder, but i do not know what kind of...
My ArrayAdapter code:
public class MyCustomAdapter extends ArrayAdapter<BuildQueue> {
private ArrayList<BuildQueue> countryList;
public MyCustomAdapter(Context context, int textViewResourceId,ArrayList<BuildQueue> countryList) {
super(context, textViewResourceId, countryList);
this.countryList = new ArrayList<BuildQueue>();
this.countryList.addAll(countryList);
}
private class ViewHolder {
TextView code;
TextView field;
Button del;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder = null;
if (convertView == null) {
LayoutInflater vi = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = vi.inflate(R.layout.queue_buildings, null);
holder = new ViewHolder();
holder.code = (TextView) convertView.findViewById(R.id.code);
holder.field = (TextView) convertView.findViewById(R.id.field_text);
holder.del = (Button) convertView.findViewById(R.id.del_button);
convertView.setTag(holder);
holder.del.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
Button del_button = (Button) v;
BuildQueue building = (BuildQueue) del_button.getTag();
countryList.remove(building);
dataAdapter.notifyDataSetChanged();
}
});
} else {
holder = (ViewHolder) convertView.getTag();
}
BuildQueue eile = countryList.get(position);
holder.code.setText(" ( Level: " + eile.getOld_level() + " to "+eile.getNew_level()+")");
holder.field.setText(eile.getNameSort());
holder.field.setTag(eile);
holder.del.setText("Delete");
holder.del.setTag(eile);
return convertView;
}
}
You are using a two arrays in your Adapter, but only changing one of them.
Every Adapter uses getCount() to determine how many row should be drawn. ArrayAdapter's getCount() simply asks for the size of the array that you pass to the super constructor here: super(context, textViewResourceId, countryList);. But you are also using a second, local array and when you delete a value from this countryList getCount() has no idea this happened which results in getView() throwing an IndexOutOfBoundsException...
Either extend BaseAdapter, or use ArrrayAdapter's methods like getItem(), add(), and remove() and remove your local data set.

Android Listview Caching work unexpectedly on initialization

I have a bit troublesome with view caching in listview (a.k.a convertView)
so here is my code,
private class CurrencyAdapter extends ArrayAdapter<CurrencyModel> {
Context ctx;
int layoutResourceId;
List<CurrencyModel> adapter_models = null;
public CurrencyAdapter(Context ctx, int layoutResourceId,
List<CurrencyModel> model) {
super(ctx, layoutResourceId, model);
this.ctx = ctx;
this.layoutResourceId = layoutResourceId;
adapter_models = model;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
// TODO Auto-generated method stub
Log.d(Constants.APP_TAG, "position: " + position);
View row = convertView;
CurrencyAdapterContainer holder = null;
if (row == null) {
Log.d(Constants.APP_TAG, "APP NULL");
row = ((Activity) ctx).getLayoutInflater().inflate(
layoutResourceId, parent, false);
holder = new CurrencyAdapterContainer();
holder.textView = (TextView) row
.findViewById(R.id.currencies_txt);
holder.imgView = (ImageView) row
.findViewById(R.id.currencies_flag_icon);
row.setTag(holder);
} else {
Log.d(Constants.APP_TAG, "APP NOT NULL");
holder = (CurrencyAdapterContainer) row.getTag();
}
CurrencyModel curr = getItem(position);
if (curr.currency_value == null) {
if (counter < MAX_COUNTER) {
++counter;
CurrencyJsonDownloader cDownloader = new CurrencyJsonDownloader(
curr, holder.textView); //download currency value in background, and set textview text if currency_value has been loaded in onpostExcecute (i'm using AsyncTask)
String url = CURRENCY_URL.replace("<symbol>", curr.symbol);
Log.d(Constants.APP_TAG, "Url currency: " + url);
cDownloader.execute(url);
}
holder.textView.setText("");
} else {
holder.textView.setText(curr.currency_value);
}
holder.imgView.setImageResource(curr.drawableId);
return row;
}
#Override
public CurrencyModel getItem(int position) {
// TODO Auto-generated method stub
return adapter_models.get(position);
}
#Override
public int getCount() {
// TODO Auto-generated method stub
return adapter_models.size();
}
}
static class CurrencyAdapterContainer {
ImageView imgView;
TextView textView;
}
and here is the output in my logcat
position : 0
APP NULL
position : 1
APP NOT NULL
position : 2
APP NOT NULL
position : 3
APP NOT NULL
.
.
.
position : 10
APP NOT NULL
which make a disaster because it means that the textview being passed in the background job is the same textview and the the changed view is the same textview and the other textview will have blank view unless i scroll it of course which call again the getView() and everything is fine. But it's a problem when starting the app, because just one textview that always changing its value.
so why is this happen? and is there any hack that i can do??
thanks before...
ListView item Views are recycled, so never hold a reference to a particular item view and expect it to represent same data after ListView has been scrolled.
Pass the data item to your worker task instead and let it update the data to it.
Updating:
If your current item is off screen, It'll be requested from adapter (
when ListView scroll to it), and will show updated data.
If that item is currently being displayed , call notifyDataSetChanged() on adapter, this will make ListView refresh its displayed items.
I think problem is with your List adapter. Here i had posted a adapter class i think it will help you.
public class UploadListAdaptor extends BaseAdapter {
private Context context;
private List<UploadDetailsObj> uploadList;
public UploadListAdaptor(Context context, List<UploadDetailsObj> list) {
this.context = context;
uploadList = list;
}
public int getCount() {
return uploadList.size();
}
public Object getItem(int position) {
return uploadList.get(position);
}
public long getItemId(int position) {
return position;
}
/** LIST CATEGORY */
public View getView(int position, View convertView, ViewGroup viewGroup) {
final UploadDetailsObj chlListObj = uploadList.get(position);
if (convertView == null) {
LayoutInflater inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater
.inflate(R.layout.inflator_progress_bar, null);
TextView photoName = (TextView) convertView
.findViewById(R.id.tv_photoname);
Button btnProgress=(Button)convertView.findViewById(R.id.btn_progress);
photoName.setText(chlListObj.getPhotoName());
}
return convertView;
}
}
You can call this adapter by using this code.
List<UploadDetailsObj> listofUploads= new ArrayList<UploadDetailsObj>();
UploadListAdaptor uploadListAdptr = new UploadListAdaptor(yourclass.this,
listofUploads);
uploadListView.setAdapter(uploadListAdptr);

Categories