I have a list view and each row contains two textviews and a checkbox.
I need user sets just one of checkboxes and if user sets other checkbox, previous checkbox should be cleared and second checkbox can be set.
I can generate the list but i don't know why onListItemClick() method does not work? therefore, I don't know which checkbox is set.
and my next question is, how can i redraw list after clicking checkbox by user?
my code is:
package com.Infindo.DRM;
import android.app.ListActivity;
import android.content.Context;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.CheckBox;
import android.widget.ListView;
import android.widget.TextView;
public class Infindo_PackageActivity extends ListActivity {
private final String[] titels = {"Try before buy", "Pay per play", "Pay per day", "Pay per week", "Pay per month", "Daily subscription", "Weekly subscription", "Monthly subscription"};
private final String[] descriptions = {"Free of charge", "Price: $1.00", "Price: $5.00", "Price: $10.00", "Price: $30.00", "Price: $5.00", "Price: $10.00", "Price: $30.00"};
private String[] flag = {"false", "false", "false", "false", "false", "false", "false", "false"};
private ListAdapter listAdapter;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.infindo_packagepage);
listAdapter = new ListAdapter(this);
setListAdapter(listAdapter);
}
#Override
public void onListItemClick(ListView l, View v, int position, long id) {
super.onListItemClick(l, v, position, id);
Log.i("List Clicked:", "******");
}
public void onCheckboxClicked(View v){
int i = getSelectedItemPosition();
Log.i("item pos:", String.valueOf(i)); // every time the result is -1???
}
//*********************
// RowModel Class
//*********************
private class RowModel{
TextView title;
TextView description;
CheckBox checkbox;
}
//*********************
// ListAdapter Class
//*********************
private class ListAdapter extends ArrayAdapter<String>{
public ListAdapter(Context c) {
super(c, R.layout.infindo_listformat, titels);
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
RowModel holder;
View row = convertView;
if(row == null){
LayoutInflater inflater = getLayoutInflater();
row = inflater.inflate(R.layout.infindo_listformat, parent, false);
holder = new RowModel();
holder.title = (TextView) row.findViewById(R.id.title);
holder.description = (TextView) row.findViewById(R.id.description);
holder.checkbox = (CheckBox) row.findViewById(R.id.checkbox);
row.setTag(holder);
} else {
holder = (RowModel) row.getTag();
}
holder.title.setText(titels[position]);
holder.description.setText(descriptions[position]);
String s = flag[position];
if(s.equalsIgnoreCase("false"))
holder.checkbox.setChecked(false);
else
holder.checkbox.setChecked(true);
return(row);
}
}
}
Update:
I have added
#Override
public void notifyDataSetChanged() {
super.notifyDataSetChanged();
Log.i("List Redrawed:", "**notifyDataSetChanged()**");
}
into my List Adapter class and called it in
public void onCheckboxClicked(View v){
int i = getSelectedItemPosition();
Log.i("item pos:", String.valueOf(i)); // every time the result is -1???
listAdapter.notifyDataSetChanged();
}
I think the problem of redraw is solved. but I still I don't know what checkbox is clicked by the user in order to change flag array.
You can use setOnCheckedChangeListener to know which checkbox was selected. You can look at complete example of ListView with CheckBox here.
UPDATE
To make your onListItemClick() work you need to write android:focusable="false" for other items of the ListView, its because of the focus of other views ListView's onListItemClick() is not peforming as it should be performing.
Checkout this answer, why Android custom ListView unable to click on items
You probably need to handle the click from the checkbox itself and not just the listview.
Related
I have a problem by selecting CheckBoxes in my ListItems. Each ListItem has a CheckBox in it's layout and when the ListItem is clicked the CheckBox should be activated. The problem is that the CheckBoxes are randomly activated. For example: When i have 2 ListItems and click on ListItem1, it's CheckBox is activated. When i click again, CheckBox of ListItem2 is activated, too. When i click again, CheckBox of ListItem1 is deactivated. When i click again, CheckBox of ListItem2 is deactivated. When i click again it all starts from the beginning. I understand ListView reuses the Items and that i have to use getView() method, but i just can't make it work. I have to mention that I'm a bloody beginner, so please forgive me if some code doesn't make sense at all.
You need to create a Custom Array Adapter and all set.
Here is the Activity Class I created for ListView for ChekBoxList
ActivityGamesList.java
package com.rdc.gameListApp;
import java.util.List;
import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.CheckBox;
import android.widget.ListView;
import android.widget.Toast;
public class ActivityGamesList extends Activity {
private ListView listGames = null;
private DBAdapter database = null;
private Context context = null;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.list_of_games);
final CheckBox favBox = (CheckBox) findViewById(R.id.favbuttonInList);
listGames = (ListView) findViewById(R.id.listViewGame);
context = getApplicationContext();
database = new DBAdapter(context);
//here I am getting the data from database and putting in to List
List<String> gamelistArrayR = database.selectAllName();
// custom adapter for adding fav box
//make sure here "gamelistArrayR" is List and type is String
listGames.setAdapter(new CustomAdapter(this, gamelistArrayR));
//listener for list view
listGames.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
Toast.makeText(getApplicationContext(), "You have selected: " +
position+" no row", Toast.LENGTH_SHORT).show();
}
});
}
}
and below is the Custom Array Adapter
CustomAdapter.java
package com.rdc.gameListApp;
import java.util.List;
import android.content.Context;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.TextView;
import android.widget.Toast;
public class CustomAdapter extends ArrayAdapter<String> {
private final Context context;
private final List<String> values;
public CustomAdapter(Context context, List<String> gamelistArrayR) {
super(context, R.layout.list_row_custom, gamelistArrayR);
this.context = context;
this.values = gamelistArrayR;
}
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
LayoutInflater inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View rowView = inflater.inflate(R.layout.list_row_custom, parent, false);
//Game Name Text in list
TextView textView = (TextView) rowView.findViewById(R.id.txtGameNameInList);
// Check Box in list
CheckBox favBox = (CheckBox) rowView.findViewById(R.id.favbuttonInList);
textView.setText(values.get(position));
//listener for check box
favBox
.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton buttonView,boolean isChecked) {
Boolean flag = isChecked;
if(flag){
Log.v("Debug", "step no 1");
Toast.makeText(context, "Marked as Favorite Game!", 1).show();
}
}
});
return rowView;
}
}
and i got the output like this way..
Edit:
When you scroll list, the chekboxrs gets uncheked because or recreate view.
so you need to store the state of checkbox for that you should check below links
this So thread or
this tutorial
Try using setOnItemSelectedListener instead of setOnItemClickListener . I believe the click event is getting invoked more often that you need.
You need to store the item states in your Adapter, not in the View itself, because it could be a reused one, just like you say. Your call to super.getView() will fill in the correct text for you, but not change the checkbox state. Keep a bool array reflecting the state of each checkbox, and in getView() apply the state before returning your view:
CheckBox cb = (CheckBox) view.findViewById(R.id.cb);
cb.setChecked(cbStates[position]);
Here is my buttonAdapter class that i think is accurate:
package com.example.test;
import android.content.Context;
import android.graphics.Color;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.GridView;
public class ButtonAdapter extends BaseAdapter {
private Context mContext;
public String [] fName = { "File 1", "File 2", "Roflcopters"};
// Gets the context so it can be used later
public ButtonAdapter(Context c) { mContext = c; }
// Total number of things contained within the adapter
public int getCount () { return 8; }
// Require for structure, not really used in my code.
public Object getItem (int position) { return null; }
// Require for structure, not really used in my code. Can be used to get the id of an item in the adapter for manual control.
public long getItemId (int position) { return position; }
public View getView (int position, View convertView, ViewGroup parent){
Button btn;
if (convertView == null) { // if it's not recycled, initialize some attributes
btn = new Button (mContext);
btn.setLayoutParams (new GridView.LayoutParams (190, 190));
btn.setPadding (1, 1, 1, 1);
} else {
btn = (Button) convertView;
}
// btn.setText(filesnames[position]);
// filenames is an array of strings
//btn.setTextColor (Color.WHITE);
//btn.setBackgroundResource (R.drawable.sample_2);
//btn.setBackgroundColor (Color.BLACK);
btn.setHighlightColor(Color.GREEN);
btn.setId (position);
return btn;
}
}
Here is my home class. I can't get the onItemClick to work out. What am I doing wrong here:
package com.example.test;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.GridView;
import android.widget.Toast;
public class home extends Activity implements OnItemClickListener {
public final static String EXTRA_MESSAGE1 = "com.example.text.MESSAGE";
public void onCreate (Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView (R.layout.activity_home);
GridView gridview = (GridView) findViewById (R.id.gridview);
gridview.setAdapter (new ButtonAdapter (this));
/*gridview.setOnItemClickListener (new OnItemClickListener () {
public void onItemClick (AdapterView <?> parent, View v, int position, long id) {
Toast.makeText (home.this, "" + position, Toast.LENGTH_LONG).show ();
Intent intent = new Intent (this, alarm.class);
String message = "Position:" + position;
intent.putExtra(EXTRA_MESSAGE1, message);
startActivity (intent);
}
});
* */
}
#Override
public void onItemClick (AdapterView <?> parent, View v, int position, long id) {
Intent intent = new Intent (this, alarm.class);
String message = "Position:" + position;
intent.putExtra(EXTRA_MESSAGE1, message);
startActivity (intent);
}
}
The onItemClick doesn't work and neither does the commented 'setOnItemClickListener' when it isn't commented out and 'onItemClick' is commented. What am I doing wrong?
If GridView, ListView have click able controls like BUtton, then onItemClick will not fired.
You need to implement Button Click listener in your getView method of the adapter.
like
public View getView(int position, View convertView, ViewGroup parent) {
Button btn;
if (convertView == null) { // if it's not recycled, initialize some
// attributes btn = new Button (mContext);
btn.setLayoutParams(new GridView.LayoutParams(190, 190));
btn.setPadding(1, 1, 1, 1);
} else {
btn = (Button) convertView;
} // btn.setText(filesnames[position]); // filenames is an array of
// strings //btn.setTextColor (Color.WHITE);
// btn.setBackgroundResource (R.drawable.sample_2);
// btn.setBackgroundColor (Color.BLACK);
btn.setHighlightColor(Color.GREEN);
btn.setId(position);
btn.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
// TODO Handle the click here
}
});
return btn;
}
You can add this line in the root layout of GridView items:
android:descendantFocusability="blocksDescendants"
Then onItemClickListener.onItemClick() will not fire when you tap on subviews which OnClickListener has been defined for them separately.
I've tested that Set Button.onClickListener() (in API 15) won't solve the problem.
So the GridView will not trigger onItemClick if it contains clickable views.
You can use ImageView instead Button.
i have the same problem when i was trying to implement onitemclick on gridview where filled with button. Because the button is stealing the focus of each space on gridview, you have to give the inflated button android:focusable="false" . however, the button is taking up almost entire space inside a grid, so you have to click the very edge of the button to trigger onitemclick call-back. i am suggesting you can set onclick or use image and designe it like a button.
Following is some test code , done to recreate a strange bug: After deleting some items from a ListView , it stops refreshing when data is invalidated. More items are deleted but list does not refresh. Even Log cat does not show debug messages for deletion. I will appreciate if any one could find out what's wrong.
Item Layout:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="horizontal">
<TextView android:id="#+id/nameTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
<Button android:id="#+id/deleteButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Delete"
/>
</LinearLayout>
Item class:
import android.content.Context;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
public class Item implements View.OnClickListener {
private String name;
private View itemView;
private MyActivity owner;
//--- getters--
public String getName() {
return name;
}
public View getView() {
return itemView;
}
public Item(String n, Context c , MyActivity o)
{
//---store the name given--
name = n;
//---store reference to the owner activity--
owner = o;
//--- create a View for this item----
LayoutInflater inflater = (LayoutInflater) c.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
itemView = inflater.inflate(R.layout.item,null);
//---set up data to show--
TextView nameTextView = (TextView) itemView.findViewById(R.id.nameTextView);
Button deleteButton = (Button) itemView.findViewById(R.id.deleteButton);
nameTextView.setText(name);
//---set up events to be handled--
deleteButton.setOnClickListener(this);
Log.d("My_Test","Item: Hello world, my name is " + name);
}
//----request owner to delete this item---
#Override
public void onClick(View view) {
Log.d("My_Test","Item:"+name+" requesting owner to delete me");
owner.deleteItem(this);
}
Activity layout:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<ListView android:id="#+id/myListView"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
/>
</LinearLayout>
Activity class:
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import java.util.ArrayList;
public class MyActivity extends Activity {
private ArrayList<Item> myItems;
private ListView myListView;
private ArrayAdapter<Item> myArrayAdapter;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
//-----adapter for item list----
//----since each item has its own view , it just returns the same---
myArrayAdapter = new ArrayAdapter<Item>(this,0){
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
Item item = getItem(position);
Log.d("My_Test","Adapter : View for Item: " + item.getName() +"is requested." );
return item.getView();
}
};
//-----set up my list view with the adapter------
myListView = (ListView) findViewById(R.id.myListView);
myListView.setAdapter(myArrayAdapter);
//------add items-------
//----each item has its own view and a reference to this activity as their owner----
myArrayAdapter.add(new Item("Sunday", this, this));
myArrayAdapter.add(new Item("Monday", this, this));
myArrayAdapter.add(new Item("Tuesday", this, this));
myArrayAdapter.add(new Item("Wednesday", this, this));
myArrayAdapter.add(new Item("Thursday", this, this));
myArrayAdapter.add(new Item("Friday", this, this));
myArrayAdapter.add(new Item("Saturday", this, this));
myArrayAdapter.notifyDataSetChanged();
}
//----- called by items requesting to be deleted from the item list----
public void deleteItem(Item item) {
myArrayAdapter.remove(item);
Log.d("My_Test","Owner : Deleted item :" + item.getName());
myArrayAdapter.notifyDataSetChanged();
}
}
Looks like ListView stops re-drawing it self. Even when List Item is no more in the item array, and myAdapter.notifyDataSetInvalidated(); is called, The List Item stays visible , with further code execution some how blocked.
Use an ArrayAdapter to do this. Try something like this instead...
import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ListView;
import android.widget.TextView;
public class MyActivity extends Activity{
private ListView myListView;
private ArrayAdapter<Item> myArrayAdapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
myArrayAdapter = new ArrayAdapter<Item>(this,R.layout.item){
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View returnedView = convertView;
//inflate your view here
if(returnedView == null){
LayoutInflater inflater = (LayoutInflater)getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
returnedView = inflater.inflate(R.layout.item,null);
}
final Item item = getItem(position);
//set the views
if(returnedView != null){
TextView nameTextView = (TextView) returnedView.findViewById(R.id.nameTextView);
nameTextView.setText(item.getName());
Button deleteButton = (Button) returnedView.findViewById(R.id.deleteButton);
deleteButton.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
remove(item);
notifyDataSetChanged();
}
});
}
return returnedView;
}
};
myArrayAdapter.add(new Item("Sunday"));
myArrayAdapter.add(new Item("Monday"));
myArrayAdapter.add(new Item("Tuesday"));
myArrayAdapter.add(new Item("Wednesday"));
myArrayAdapter.add(new Item("Thursday"));
myArrayAdapter.add(new Item("Friday"));
myArrayAdapter.add(new Item("Saturday"));
myListView = (ListView) findViewById(R.id.myListView);
myListView.setAdapter(myArrayAdapter);
}
}
public class Item{
private String name;
public Item(String n){
this.name = n;
}
public String getName() {
return name;
}
}
Looking inside the working of ListViews and ListAdapters, I came to know there's a lot of recycling of objects, specifically List View Item Objects which adapters produce. Here are the lessons learnt along with solution to Original problem:
When a ListView has to draw/show a list item, it requests a View from ListAdapter, and some times (NOT ALWAYS) also provides an old View object to reuse. This reuse of objects is there so as to increase performance,there's an in built Re-Cycler in ListView to do this, why inflate new layouts for each new list item, when there are already some whose properties can be modified so that they look like the new view item. Until this point , its OK for adapter to change some text on old views and give them back, or create new ones if no recycled views are available, or even discard recyclable views and always create new one.
However, If your List Item's state is more than just some text in a TextView , that is, another object is registered as an onClickListener for your list item, or your list item has a reference to some object somewhere and vice-verca; it is NOT OK for adapter to just change appearance of the reusable Views or simply discard them. Adapter has to update entire state of a reusable item. that includes de-registering old event listeners, re-registering new ones and updating all reference to external objects that may be there.
Changed getView() method for adapter to:
#Override
public View getView(int position, View convertView, ViewGroup parent) {
Item item = getItem(position);
Log.d("My_Test","Adapter : View for Item: " + item.getName() +"is requested." );
if(convertView != null)
{
(convertView.findViewById(R.id.deleteButton))
.setOnClickListener(item);
((TextView)convertView.findViewById(R.id.nameTextView))
.setText(item.getName());
return convertView;
}
else
{
return item.getView();
}
}
NOTE: While always creating new items in this case does not cause any errors, the ListView fails to detect changes and redraw. Making use of recycled items seems to solve this.
I have defined onCheckedChanged for the checkbox in my listview.
When i click on the check box to check / uncheck it this function is getting invoked.
But when i setthe state of the check box from code like
check.setChecked(true);
the onCheckedChanged is not getting invoked.
Please help.
Adapter file :
package com.idg.project.adapters;
import java.util.List;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.graphics.BitmapFactory;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.CompoundButton.OnCheckedChangeListener;
import android.widget.ImageView;
import android.widget.TextView;
import com.idg.project.R;
import com.idg.project.activities.ScanListActivity;
import com.idg.project.activities.SearchResultActivity;
import com.idg.project.adapters.WishListAdapter.ViewHolder;
import com.idg.project.entity.ScannedProduct;
public class ScanListAdapter extends BaseAdapter {
private Context context;
private List<ScannedProduct> productList;
protected LayoutInflater mInflater;
Button showOrHideButton;
static public int count = 0;
String barcodeForSelectedRow;
String formatForSelectedRow;
OnItemClickListener rowListener;
Activity parentActivity;
boolean isWishList;
public ScanListAdapter(Context context, List<ScannedProduct> objects,
Button button, Activity parentActivity) {
super();
this.productList = objects;
this.context = context;
this.mInflater = LayoutInflater.from(context);
showOrHideButton = button;
this.parentActivity = parentActivity;
this.isWishList = isWishList;
}
public int getCount() {
return productList.size();
}
public Object getItem(int arg0) {
// TODO Auto-generated method stub
return null;
}
public long getItemId(int arg0) {
// TODO Auto-generated method stub
return 0;
}
#Override
public void notifyDataSetChanged() {
// TODO Auto-generated method stub
super.notifyDataSetChanged();
}
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
final int pos = position;
Log.i("checkboxflag at : ", pos+"is"+(productList.get(pos).getCheckboxflag()));
Log.i("getview : fresh", "getview"+pos);
convertView = mInflater.inflate(R.layout.product_list_row, null);
holder = new ViewHolder();
holder.text1 = (TextView) convertView.findViewById(R.id.productid);
holder.text1.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
Intent intent = new Intent(parentActivity,
SearchResultActivity.class);
intent.putExtra("barcode", productList.get(pos)
.getBarcode());
intent.putExtra("format", productList.get(pos).getFormat());
intent.putExtra("IsScan", false);
Log.i("", "" + productList.get(pos).getBarcode());
parentActivity.startActivity(intent);
Log.i("", "" + pos);
}
});
holder.text2 = (TextView) convertView.findViewById(R.id.price);
// holder.text2.setOnClickListener(listener);
holder.image = (ImageView) convertView
.findViewById(R.id.productimageid);
convertView.setTag(holder);
// holder.image.setOnClickListener(listener);
holder.text1.setText(productList.get(position).getTitle());
holder.text2.setText(productList.get(position).getPrice().toString());
if (productList.get(position).getSmallImage() != null) {
byte[] bb = (productList.get(position).getSmallImage());
holder.image.setImageBitmap(BitmapFactory.decodeByteArray(bb, 0,
bb.length));
} else {
holder.image.setImageBitmap(null);
holder.image.setBackgroundResource(R.drawable.highlight_disabled);
}
// holder.image.setImageBitmap(Utils.loadBitmap(productList.get(position).getSmallImage()));
final CheckBox check = (CheckBox) convertView
.findViewById(R.id.checkbox);
check.setClickable(true); // to remove anything carried over from prev convert view
if(productList.get(pos).getCheckboxflag()==1)
{
Log.i("CheckBox set checked",""+pos);
check.setChecked(true);
}
else{
Log.i("CheckBox set unchecked",""+pos);
check.setChecked(false);
}
setWishListItemsInScanList(pos, convertView);
check.setOnCheckedChangeListener(new OnCheckedChangeListener() {
public void onCheckedChanged(CompoundButton buttonView,
boolean isChecked) {
Log.i("OnclickListener","Current Position"+pos);
if (check.isChecked()
&& productList.get(pos).getWishListFlag() == 0) {
if(check.isClickable()){
Log.i("CheckBox check",""+pos);
ScanListActivity.updateCheckBoxSelection(1, pos);
ScanListAdapter.count++;
}
} else if (!check.isChecked()
&& productList.get(pos).getWishListFlag() == 0){
if(check.isClickable()){
ScanListActivity.updateCheckBoxSelection(0, pos);
ScanListAdapter.count--;
Log.i("CheckBox UNcheck",""+pos);
}
}
if (ScanListAdapter.count == 0) {
// showOrHideButton.setClickable(false);
// showOrHideButton.setVisibility(View.GONE);
showOrHideButton.setEnabled(false);
} else {
// showOrHideButton.setVisibility(View.VISIBLE);
showOrHideButton.setEnabled(true);
}
}
});
return convertView;
}
private void setWishListItemsInScanList(int pos, View convertView) {
if (productList.get(pos).getWishListFlag() == 1) {
Log.i("CheckBox set checked from wish list",""+pos);
CheckBox check = (CheckBox) convertView.findViewById(R.id.checkbox);
check.setClickable(false);
check.setChecked(true);
}
}
static class ViewHolder {
TextView text1;
ImageView image;
TextView text2;
}
}
List activity file :
package com.idg.project.activities;
import java.util.ArrayList;
import java.util.List;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.Window;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
import com.idg.project.R;
import com.idg.project.adapters.WishListAdapter;
import com.idg.project.adapters.ScanListAdapter;
import com.idg.project.entity.ScannedProduct;
import com.idg.project.services.ScannedProductDataAccessManager;
public class ScanListActivity extends BaseActivity {
static Button scanlist;
ScanListAdapter listAdapter;
static List<ScannedProduct> productList;
/* Notes for the Developer :
* For tracking the checked items Checkboxflag
* is maintained.
* Point1 : Select all will just set this flag in the local list and then call notifyDatachange of the adapter
* within adapter the check box is set or reset based on this flag for each row
*
* Point 2: When individual rows are selected , there is an onclick of the check box is invoked
* Here the Checkboxflag of the local list is set /unset . Also we need a way to knpw the select all button is
* to enabled or diabled. for that Count variable is updated here.
* Now Important point is these two actions shoulnt be taking place if the checkbox state change due to select all
* So there is a special check of isclickable in the onclicklistener
*
* Point 3: In scan list the items in the wish list are to be marked. This again needs special logic.
* This is done in the adapter code by checking all the rows whose wishListFlag is 1 and making it non clickable
*
* Important : Listview has the concept of ViewGroup and each view group is usually the rows fitting in the display screen
* so when we scroll, the viewGropu changes.
* Convertview is get reused for view groups. So need to careful undesired values that will be carried to next viewgroup*/
#Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
this.requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.scan_list);
productList = new ArrayList<ScannedProduct>();
productList = getProductList();
for(int i=0;i<productList.size();i++){
Log.i("checkboxflag at : ", i+"is"+(productList.get(i).getCheckboxflag()));
}
final ListView lv = (ListView) findViewById(R.id.list);
scanlist = (Button) findViewById(R.id.addtowishlist);
scanlist.setEnabled(false);
listAdapter = new ScanListAdapter(this, productList, scanlist, this);
lv.setAdapter(listAdapter);
}
private List<ScannedProduct> getProductList() {
List<ScannedProduct> productList = new ArrayList<ScannedProduct>();
ScannedProductDataAccessManager productDataBaseManager = new ScannedProductDataAccessManager(
getApplicationContext());
String[] colList = { "title", "smallImage", "price" };
productList = productDataBaseManager.fetchAllProducts();
return productList;
}
static boolean selectFlag = false;
public void selectAll(View view) {
ListView listView = (ListView) findViewById(R.id.list);
view = findViewById(R.id.select_all);
if (selectFlag == false) {
for (int i = 0; i < listView.getAdapter().getCount(); i++) {
productList.get(i).setCheckboxflag(1);
}
view.setBackgroundResource(R.drawable.login_remme_dwn_btn);
selectFlag = true;
TextView text=(TextView) findViewById(R.id.select);
text.setText("Unselect All");
scanlist.setEnabled(true);
} else {
for (int i = 0; i < listView.getAdapter().getCount(); i++) {
productList.get(i).setCheckboxflag(0);
}
view.setBackgroundResource(R.drawable.login_remme_up_btn);
selectFlag = false;
TextView text=(TextView) findViewById(R.id.select);
text.setText("Select All");
scanlist.setEnabled(false);
}
((BaseAdapter)listView.getAdapter()).notifyDataSetChanged(); // we are only setting the flags in the list
// so need to notify adapter to reflect same on checkbox state
//listView.refreshDrawableState();
}
public void addToWishList(View view) {
ListView listView = (ListView) findViewById(R.id.list);
for (int i = 0; i < listView.getAdapter().getCount(); i++) {
ScannedProduct product = productList.get(i);
if (product.getWishListFlag() == 0 && product.getCheckboxflag()==1) {
product.setWishListFlag(1);
new ScannedProductDataAccessManager(getApplicationContext())
.updateProduct(product, "title",
new String[] { product.getTitle() });
product.setCheckboxflag(0);
//ScanListAdapter.count--;
}
Log.i("ScanList selected", product.getTitle());
}
Toast.makeText(getApplicationContext(),
"Added selected items to Wish List", Toast.LENGTH_SHORT).show();
scanlist.setEnabled(false);
((BaseAdapter)listView.getAdapter()).notifyDataSetChanged();
}
static public void updateCheckBoxSelection(int flag,int pos){ // when individual row check box is checked/ unchecked
// this fn is called from adapter to update the list
productList.get(pos).setCheckboxflag(flag);
}
}
Since your checkbox is inside listview, so you need to call notifyDataSetChanged method on your list's adapter to refresh it's contents.
update
instead of ((BaseAdapter)listView.getAdapter()).notifyDataSetChanged();, try calling listAdapter.notifyDataSetChanged();
I got the answer / bug in my code
i am not reusing convertview so its every time a new holder.
I am changing the flag of the checkbox and then assigning a statechange listener for the checkbox
thus its not getting invoked
when i changed the order to assign checkchangelistener before actually changing the state , its working as expected. The listener is getting called.
thanks all of you
So this is a bit complicated situation, so I will try to explain what is going on as best I can. I have a sqlite db which populates a listview. Each item in the listview contains the name of the item, along with two buttons. I want these two buttons to be able to use the sqlite db row id of the item they're contained in order to execute their purpose. So I need to get the id of the item, but I don't think using onListItemClick(ListView l, View v, int position, long id) will work for me, becuase I'm not clicking the entire item, rather, buttons within it. If I'm misunderstanding this point, please let me know. In order for the buttons to be clicked, I've created a class which extends SimpleCursorAdapter, which correctly handles clicks. Here are the two classes in question. First, the listactivity, and second, the custom listadapter.
import android.app.ListActivity;
import android.content.Intent;
import android.content.SharedPreferences;
import android.database.Cursor;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.SimpleCursorAdapter;
public class FriendRequestList extends ListActivity implements OnClickListener {
private Button m_closeButton;
private TagDBAdapter mDbAdapter;
private Cursor mCursor;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mDbAdapter = new TagDBAdapter(this);
mDbAdapter.open();
this.initLayout();
fillData();
}
private void initLayout() {
setContentView(R.layout.request_list);
m_closeButton = (Button)findViewById(R.id.request_window_close_button);
m_closeButton.setOnClickListener(this);
}
private void fillData() {
SharedPreferences prefs = this.getSharedPreferences("Prefs", MODE_WORLD_READABLE);
String username = prefs.getString("keyUsername", "");
RestClient.getRequests(username, this);
mCursor = mDbAdapter.fetchAllRequests();
startManagingCursor(mCursor);
String[] from = new String[] {TagDBAdapter.KEY_NAME};
int[] to = new int[] {R.id.requester};
SimpleCursorAdapter requests = new FriendRequestListAdapter(this, R.layout.request_view, mCursor, from, to);
this.setListAdapter(requests);
}
public String getRequester() {
return null;
}
#Override
public void onClick(View v) {
SharedPreferences prefs = this.getSharedPreferences("Prefs", MODE_WORLD_READABLE);
String username = prefs.getString("keyUsername", "");
RestClient.getUpdates(username, this);
Intent intent = new Intent(this, MainMenu.class);
this.startActivity(intent);
}
#Override
public void onDestroy() {
super.onDestroy();
mDbAdapter.close();
}
}
And the adapter class:
import android.app.Activity;
import android.content.Context;
import android.content.SharedPreferences;
import android.database.Cursor;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.SimpleCursorAdapter;
public class FriendRequestListAdapter extends SimpleCursorAdapter implements OnClickListener {
private Context mContext;
public FriendRequestListAdapter(Context context, int layout, Cursor c,
String[] from, int[] to) {
super(context, layout, c, from, to);
mContext = context;
}
public View getView(int position, View convertView, ViewGroup parent) {
View view = super.getView(position, convertView, parent);
Button confirm = (Button)view.findViewById(R.id.confirm_request);
confirm.setOnClickListener(this);
Button deny = (Button)view.findViewById(R.id.deny_request);
deny.setOnClickListener(this);
return view;
}
#Override
public void onClick(View v) {
SharedPreferences prefs = mContext.getSharedPreferences("Prefs", Activity.MODE_WORLD_READABLE);
String username = prefs.getString("keyUsername", "");
//want to get the id here so i can do stuff with the buttons
switch(v.getId()) {
case R.id.confirm_request :
String confirmState = "2";
//these buttons both work
break;
case R.id.deny_request :
String denyState = "3";
//these buttons both work
Log.e("TESTING", "deny");
break;
}
}
}
I hope I've made my question clear enough. To summarize, I don't know how I would get the rowId of the item a pair of buttons is nested in, because I'm not ever using the onListItemClick method, which is, as far as I'm aware, the way one would normally get the id of the item. Thank you for reading and thank you for your answers. Please let me know if there is any clarifications I can make.
Create your a class by implements OnClickListener
class myCustomClass implements OnClickListener {
int rowid;
public myCustomClass(int rowid){
this.rowid=rowid;
}
#Override
public void onClick(View v) {
//do you code in 'rowid' will have the current row position
}
}
So in your
getView
function you can set listener like this
//your other codes
confirm.setOnClickListener(new myCustomClass(position));
//your other codes
deny.setOnClickListener(new myCustomClass(position));
//your other codes
Hope this give you an idea.
you maybe can do like this,in your custom adapter the getView method
public View getView(int position, View convertView, ViewGroup parent) {
View view = super.getView(position, convertView, parent);
//you can set view's tag here
//and you should do the reflect on your position to your rowid
view.setTag(customMethodForGetId(position));
//end
Button confirm = (Button)view.findViewById(R.id.confirm_request);
confirm.setOnClickListener(this);
Button deny = (Button)view.findViewById(R.id.deny_request);
deny.setOnClickListener(this);
return view;
}
and in your click event you can get the id by view.getTag();
public View getView(int position, View convertView, ViewGroup parent) {
View view = super.getView(position, convertView, parent);
Button confirm = (Button)view.findViewById(R.id.confirm_request);
confirm.setOnClickListener(this);
view.setTag(position);
Button deny = (Button)view.findViewById(R.id.deny_request);
deny.setOnClickListener(this);
view.setTag(position);
return view;
}
#Override
public void onClick(View v) {
// get the position here
Integer position = (Integer)v.getTag();
switch(v.getId()) {
case R.id.confirm_request :
break;
case R.id.deny_request :
String denyState = "3";
break;
}
}