I have two Samsung tablets (Samsung SM-T580 Android 7.0 and SM-T280 Android 5.1).
I have a list view with a custom adapter. It works fine on the SM-T580 but it crashes on the first iteration of method:
public override View GetView(int position, View convertView, ViewGroup parent)
on the SM-T280 tablet. I do not understand how it works perfect on the SM-T580 and crashes on the SM-T280. The error message when it crashes is:
The application is in break mode.
Your app has entered a break state, but there is no code to show because all threads were executing external code (typically system or framework code.)
I have the compiler set to:
Compile using Android version: (Target Framework)
Android 5.1 (Lollipop)
I am using Visual Studio 2017 with Xamarin.
The following is my code.
The layout code:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TableLayout
android:minWidth="25px"
android:minHeight="25px"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:stretchColumns="2"
android:id="#+id/tableLayout1">
<TableRow
android:id="#+id/tableRow1"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_weight="1">
<TextView
android:id="#+id/CompanyNameLabel"
android:text=""
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:layout_column="1"
android:layout_gravity="left"
android:textStyle="bold"
android:textSize="16sp"
android:padding="8dip" />
<TextView
android:id="#+id/CompanySalesLabel"
android:text=""
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:layout_column="2"
android:layout_gravity="right"
android:padding="8dip" />
</TableRow>
</TableLayout>
<TextView
android:id="#+id/CompanyAddressLabel"
android:text=""
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingLeft="20dip" />
<TextView
android:id="#+id/CompanyCityStateZipLabel"
android:text=""
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingLeft="20dip" />
</LinearLayout>
The view holder code:
public class MyMainCompanyRowHolder : Java.Lang.Object
{
public TextView CompanyName { get; set; }
public TextView CompanyAddress { get; set; }
public TextView CompanySales { get; set; }
public TextView CompanyCityStateZipLabel { get; set; }
public static T Cast<T>(Java.Lang.Object obj) where T : MyMainCompanyRowHolder
{
var propInfo = obj.GetType().GetProperty("Instance");
return propInfo == null ? null : propInfo.GetValue(obj, null) as T;
}
}
The custom adapter:
public class ListAdapter : BaseAdapter<Company>
{
List<Company> company;
Activity context;
public ListAdapter(Activity currentContext, List<Company> companyList) : base()
{
this.company = companyList;
this.context = currentContext;
}
public override Company this[int position]
{
get { return company.ToArray()[position]; }
}
public override int Count
{
get { return company.Count; }
}
public override long GetItemId(int position)
{
return position;
}
public override View GetView(int position, View convertView, ViewGroup parent)
{
Models.ViewHolder.MyMainCompanyRowHolder myViewHolder = null;
View view = convertView;
if (view != null)
myViewHolder = Models.ViewHolder.MyMainCompanyRowHolder.Cast<Models.ViewHolder.MyMainCompanyRowHolder>(view.Tag);
if (myViewHolder == null)
{
myViewHolder = new Models.ViewHolder.MyMainCompanyRowHolder();
//view = context.LayoutInflater.Inflate(Android.Resource.Layout.SimpleListItem1, null);
view = context.LayoutInflater.Inflate(Resource.Layout.MainCompanyListRow, null);
myViewHolder.CompanyName = view.FindViewById<TextView>(Resource.Id.CompanyNameLabel);
myViewHolder.CompanyAddress = view.FindViewById<TextView>(Resource.Id.CompanyAddressLabel);
myViewHolder.CompanySales = view.FindViewById<TextView>(Resource.Id.CompanySalesLabel);
myViewHolder.CompanyCityStateZipLabel = view.FindViewById<TextView>(Resource.Id.CompanyCityStateZipLabel);
view.Tag = myViewHolder;
}
myViewHolder.CompanyName.Text = company.ToArray()[position].CompanyName;
myViewHolder.CompanyAddress.Text = company.ToArray()[position].Address;
myViewHolder.CompanySales.Text = company.ToArray()[position].ActualSales.ToString("C0");
myViewHolder.CompanyCityStateZipLabel.Text = company.ToArray()[position].City + ", " + company.ToArray()[position].State + " " + company.ToArray()[position].Zip;
return view;
}
}
The call in the Activity module:
myCompany = myDBF.getCompany("");
var listView = FindViewById<ListView>(Resource.Id.OrderMethodListView);
listView.Adapter = new Models.Adapters.ListAdapter(this, myCompany);
Thanks! I figured it out. Android 5.1 does not like:
android:layout_weight="1"
android:layout_column="1"
android:layout_gravity="left"
Once I removed those lines from my Layout Code, the app works correctly.
Related
I have a ListView that shows list items (duh). When you click on a list item, another Activity opens. Part of the list item layout is a grey star, an ImageView. When you click on this ImageView, I don't want to open another Activity, but I want to change the color of the star to green (= mark the item as favourite) or back (= mark it as not favourite). I managed to do that with an OnClickListener, loading another ImageView on Click, and refreshing the adapter. But for the ImageView to change, after clicking it I need to leave the Activity and enter again. It doesn't refresh instantly. Why, and how can I change that? I've tried lots of different versions, so far nothing works. My ListViewAdapter extends BaseAdapter. Thank you!
public class ListViewAdapterKeysAToZ extends BaseAdapter {
private ArrayList<KeyTagIntern> keyTags;
private ObservableArrayList<KeyTagIntern> list;
private Context context;
TextView name;
TextView place;
ImageView star, favoriteStar;
public ListViewAdapterKeysAToZ(Context context, ObservableArrayList<KeyTagIntern> list)
{
this.context = context;
this.list = list;
keyTags = new ArrayList<>();
for (KeyTagIntern keytag : list) {
keyTags.add(keytag);
}
//(....)
}
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
KeyTagIntern key = (KeyTagIntern) getItem(position);
if (convertView == null) {
convertView = LayoutInflater.from(context).inflate(R.layout.list_item_keys, parent, false);
}
name = (TextView) convertView.findViewById(R.id.text_keylist_item);
name.setText(key.getName());
place = (TextView) convertView.findViewById(R.id.text_keylist_item_place);
place.setText(key.getPlace());
star = (ImageView) convertView.findViewById(R.id.right_icon_keylist_item);
favoriteStar = (ImageView) convertView.findViewById(R.id.right_icon_keylist_item_favorite);
if (key.isFavorite())
{
star.setVisibility(View.INVISIBLE);
favoriteStar.setVisibility(View.VISIBLE)
favoriteStar.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// This makes key.isFavourite() = false for the next time
Paper.book().delete(FAVORIT + String.valueOf(key.getKeyTagID()));
//Since notifyDataSetChanged() didn't work for me, I tried this - but no change
int index = list.indexOf(key);
list.remove(index);
list.add(index, key);
keyTags = new ArrayList<>();
for (KeyTagIntern keytag : list) {
keyTags.add(keytag);
}
notifyDataSetChanged();
}
});
}
// Then do the opposite for if (!key.isFavourite())
Und hier das xml:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/list_item_keys"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:background="#color/MiddleDarkGrey">
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/btn_list_item_keys"
android:layout_width="match_parent"
android:layout_height="#dimen/height_list_item"
android:layout_marginBottom="3dp"
android:layout_marginLeft="20dp"
android:layout_marginRight="20dp"
android:layout_marginTop="3dp"
android:background="#drawable/white_list_item"
android:paddingLeft="13dp"
android:paddingRight="10dp">
<ImageView
android:id="#+id/icon_keylist_item"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_centerVertical="true"
android:visibility="visible"
app:srcCompat="#drawable/ic_key" />
<ImageView
android:id="#+id/icon_reserved"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toRightOf="#+id/chb_add_key"
android:layout_centerVertical="true"
android:visibility="invisible"
app:srcCompat="#drawable/ic_reservate_orange" />
<ImageView
android:id="#+id/icon_taken"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toRightOf="#+id/chb_add_key"
android:layout_centerVertical="true"
android:visibility="invisible"
app:srcCompat="#drawable/ic_taken_red" />
<TextView
android:id="#+id/text_keylist_item"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:layout_marginStart="10dp"
android:layout_toEndOf="#+id/icon_keylist_item"
android:layout_toRightOf="#+id/icon_keylist_item"
android:gravity="center_vertical"
android:layout_centerVertical="true"
android:text="Text"
android:textColor="#color/DarkGrey"
android:textSize="#dimen/text_list_item" />
<TextView
android:id="#+id/text_keylist_item_place"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#+id/text_keylist_item"
android:layout_alignLeft="#+id/text_keylist_item"
android:layout_marginLeft="2dp"
android:layout_marginBottom="5dp"
android:text="Where is the key?"
android:textColor="#color/DarkGrey"
android:textSize="#dimen/text_list_item_sub" />
<ImageView
android:id="#+id/right_icon_keylist_item"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
app:srcCompat="#drawable/ic_fav_green" />
<ImageView
android:id="#+id/right_icon_keylist_item_favorite"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:srcCompat="#drawable/ic_fav_chosen"
android:visibility="invisible"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true" />
</RelativeLayout>
I think your approach should be something like this.
rather hiding and displaying an image just change source of it!
if (key.isFavorite())
{
favoriteStar.setImageResource(R.drawable.aaa);
favoriteStar.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v)
favoriteStar.setImageResource(R.drawable.bbb);
// and vice-versa
and I don't thing you will be needing notifyDataSetChanged(); as you are making no changes in the Listdata actually!
In the end the answer was rather stupid, as it is so often, and you guys couldn't have helped me since I excluded the code at the beginning of my adapter class (added it now). It actually worked the whole time, but I didn't see it, since the listitem at the very end of the list was changed, not the selected one. This was due to me declaring the variables at the beginning of the adapter class, rather than inside the getView method.
I changed it to this and now it works perfectly:
public class ListViewAdapterKeysAToZ extends BaseAdapter {
private ArrayList<KeyTagIntern> keyTags;
private ObservableArrayList<KeyTagIntern> list;
private Context context;
public ListViewAdapterKeysAToZ(Context context, ObservableArrayList<KeyTagIntern> list) {
this.context = context;
this.list = list;
keyTags = new ArrayList<>();
for (KeyTagIntern keytag : list) {
keyTags.add(keytag);
}
// (...)
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
KeyTagIntern key = (KeyTagIntern) getItem(position);
TextView name;
TextView place;
ImageView star, favoriteStar;
if (convertView == null) {
convertView = LayoutInflater.from(context).inflate(R.layout.list_item_keys, parent, false);
}
name = (TextView) convertView.findViewById(R.id.text_keylist_item);
name.setText(key.getName());
place = (TextView) convertView.findViewById(R.id.text_keylist_item_place);
place.setText(key.getPlace());
star = (ImageView) convertView.findViewById(R.id.right_icon_keylist_item);
favoriteStar = (ImageView) convertView.findViewById(R.id.right_icon_keylist_item_favorite);
if (key.isFavorite()) {
star.setVisibility(View.INVISIBLE);
favoriteStar.setVisibility(View.VISIBLE);
}else {
star.setVisibility(View.VISIBLE);
favoriteStar.setVisibility(View.INVISIBLE);
}
star.setOnClickListener(v -> {
key.setFavorite(true);
Paper.book().write(FAVORIT + String.valueOf(key.getKeyTagID()), true);
notifyDataSetChanged();
});
favoriteStar.setOnClickListener(v -> {
key.setFavorite(false);
Paper.book().delete(FAVORIT + String.valueOf(key.getKeyTagID()));
notifyDataSetChanged();
});
I found many similar questions on StackOverflow, but can't seem to figure out this issue.
I'm trying to bind an ObservableCollection to a ListView so that when the contents of the collection change the ListView will automatically update. Unfortunately, when elements are added to the collection (via button click), the ListView isn't being updated. How can I make the ListView reflect the current contents of the collection?
Note: It seems that if I force layout with listView.RequestLayout(); the listView will contain the correct number of items. However, it won't necessarily contain the right items. For example, if I delete the first item and add a new one at the end, forcing a layout has no effect. If I force the layout after deleting the first item, then again after adding one at the end, the contents are correct.
Activity code
public class MainActivity : Activity
{
int count = 1;
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
ObservableCollection<UserTask> allTasksCollection = new ObservableCollection<UserTask>();
while(count < 6)
{
allTasksCollection.Add(new UserTask("Task number " + count));
count++;
}
// Set our view from the "main" layout resource
SetContentView(Resource.Layout.Main);
// Bind listview to all tasks
ListView listView = FindViewById<ListView>(Resource.Id.allTasksListView);
UserTaskListAdapter adapter = new UserTaskListAdapter(this, allTasksCollection);
listView.Adapter = adapter;
// Button click should add a new task and remove the first task.
Button button = FindViewById<Button>(Resource.Id.myButton);
button.Click += delegate {
allTasksCollection.Add(new UserTask("Task number " + count));
button.Text = string.Format("{0} tasks!", count++);
};
}
}
Adapter
public class UserTaskListAdapter : BaseAdapter<UserTask>
{
Activity context;
ObservableCollection<UserTask> list;
public UserTaskListAdapter(Activity _context, ObservableCollection<UserTask> _list)
: base()
{
this.context = _context;
this.list = _list;
}
public override int Count
{
get { return list.Count; }
}
public override long GetItemId(int position)
{
return position;
}
public override UserTask this[int index]
{
get { return list[index]; }
}
public override View GetView(int position, View convertView, ViewGroup parent)
{
View view = convertView;
if (view == null)
view = context.LayoutInflater.Inflate(Resource.Layout.UserTaskRowItem, parent, false);
UserTask item = this[position];
view.FindViewById<TextView>(Resource.Id.Title).Text = item.Name;
return view;
}
}
Main XAML
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:id="#+id/rootLayout">
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/allTasksContainer">
<Button
android:id="#+id/myButton"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="#string/hello" />
<ListView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/allTasksListView" />
</LinearLayout>
</LinearLayout>
ListItem XAML
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<LinearLayout
android:orientation="horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/linearLayoutHorizontal">
<LinearLayout
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/CheckboxContainer">
<CheckBox
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/checkboxSelect" />
</LinearLayout>
<LinearLayout
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/TextContainer">
<TextView
android:text="Large Text"
android:textAppearance="?android:attr/textAppearanceLarge"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/Title" />
<TextView
android:text="Small Text"
android:textAppearance="?android:attr/textAppearanceSmall"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/DueDate" />
</LinearLayout>
</LinearLayout>
</RelativeLayout>
Try to call NotifyDataSetChanged() on your adapter after updating its items, AFAIK ListView in Android doesn't observe the changes on your ObservableCollection:
Try this code:
button.Click += delegate {
allTasksCollection.Add(new UserTask("Task number " + count));
button.Text = string.Format("{0} tasks!", count++);
adapter.NotifyDataSetChanged();
};
You can also try to add a litener to your ObservableCollection, in your adapter, change the constructor to this:
this.list.CollectionChanged += (sender,args) => { NotifyDataSetChanged(); };
Take a look at the INotifyPropertyChanged interface. It will warn the listview that variables within an object within the listview have changed.
https://developer.xamarin.com/guides/xamarin-forms/xaml/xaml-basics/data_bindings_to_mvvm/
Edit: misread your question. My bad.
I have used a TableLayout to produce the following cart activity output.
.
So the listview has 3 listviews(Item,Price,quantity) and a button (for delete)
I wanted to give a heading to the cart. So, I initalized the first item of the listview as the title ('Item Name','Price','Quantity','Delete')
Now The problem is, Whenever the user clicks on delete button (as circled in the pic), The title also gets deleted. (Since the onClickListener has been applied to all buttons by default in the adapter class)
How should i remove the onClickListener on the first Button and keep it as it is for the rest of the buttons ?
Extra: If you guys can suggest some awesome way to format this cart so that it doesnt look so naive, It'd be great. :) Happy Diwali and Thanks in Advance.
- Android newBee
cartlayout.xml file
<TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:stretchColumns="*"
android:background="#ffffff">
<TableRow>
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/cartlist_layout"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/t1"
android:textStyle="normal|bold"
android:padding="5dip"
android:layout_alignParentLeft="true"
android:layout_toLeftOf="#+id/t2"
/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/t2"
android:padding="5dip"
android:textStyle="normal|bold"
android:layout_centerHorizontal="true"
/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_toRightOf="#+id/t2"
android:id="#+id/t3"
android:textStyle="normal|bold" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/button6" />
</TableRow>>
</TableLayout>
The Java Code:
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View view=inflater.inflate(R.layout.fragment_mycart,container,false);
this.getActivity().setTitle("AADESH");
cartlistview=(ListView)view.findViewById(R.id.listView1);
db=new DatabaseHelper(this.getContext());
db.onCreate();
Cursor res=db.onView();
int len=res.getCount();
listCartItems = new ArrayList<CartItems>();
listCartItems.add(new CartItems("Item Name", "Quantity", "Price","Delete"));
if(len==0)
{
Toast.makeText(this.getContext(),"Cart is Empty.",Toast.LENGTH_SHORT).show();
statusOfCart=false;
}
else {
while (res.moveToNext()) {
String itemname = res.getString(1).toString(); // 0 is id, 1 is name, 2 is qty, 3 price
String itemqty = Integer.toString(res.getInt(2));
String itemprice = Integer.toString(res.getInt(3)) ;
Toast.makeText(this.getContext(),itemname,Toast.LENGTH_SHORT).show();
listCartItems.add(new CartItems(itemname, itemqty, itemprice,"X"));
}
}
CartListAdapter cartListAdapter = new CartListAdapter(getContext(), R.layout.cartlist_layout, listCartItems);
cartlistview.setAdapter(cartListAdapter);
return view;
}
}
And the CartAdapter Java Code here:
public class CartListAdapter extends ArrayAdapter<CartItems> {
Context context;
int resLayout;
List<CartItems> listCartItems;
int pos;
public CartListAdapter(Context context,int resLayout,List <CartItems> listCartItems) {
super(context, resLayout, listCartItems);
this.context=context;
this.resLayout=resLayout;
this.listCartItems=listCartItems;
}
#NonNull
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
View v=View.inflate(context,resLayout,null);
pos=position;
TextView name=(TextView)v.findViewById(R.id.t1);
TextView qty=(TextView)v.findViewById(R.id.t2);
TextView price=(TextView)v.findViewById(R.id.t3);
Button delete=(Button)v.findViewById(R.id.button6);
CartItems cartItems=listCartItems.get(position);
name.setText(cartItems.getItemname());
qty.setText(String.valueOf(cartItems.getQty()));
price.setText(String.valueOf(cartItems.getPrice()));
delete.setText(String.valueOf(cartItems.getDel()));
delete.setOnClickListener(
new View.OnClickListener() {
#Override
public void onClick(View v) {
listCartItems.remove(position);
notifyDataSetChanged();
}
}
);
return v;
}
}
execute listCartItems.remove(position); only when position > 0.
I have a ListView in one of my activities that I have bound to an ArrayList using a custom ArrayAdapter. I have set an OnItemClickListener to the ListView which should call a method that starts another activity. However, I find that when I click on the ListView items, it only sometimes works. Sometimes it will start the activity as it should; other times it seems to detect the click (the ripple effect appears on the list item) but does nothing; other times it doesn't even appear to detect the click (the ripple effect doesn't appear).
I've tried all the usual suggestions that I've come across: blocking descendants on the parent view item, setting clickable and focusable to false on all the components of the item views, setting isEnabled to return true in the custom adapter, etc, but the behavior remains the same. Any help appreciated. Here is the relevant code:
Activity containing the ListView:
public class ViewCollectionActivity extends AppCompatActivity {
private final String className = this.getClass().getSimpleName();
private CollectionHandler collectionHandler;
private Context context;
private ArrayList<Game> displayedCollection;
private GameCollectionAdapter collectionAdapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_view_collection);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
context = this;
collectionHandler = CollectionHandler.getInstance(this);
TextView view = null;
if (collectionHandler.getDisplayedCollection().size() > 0) {
view = (TextView) findViewById(R.id.no_items_textview);
view.setVisibility(View.GONE);
}
String currentDate = collectionHandler.getDateLastSynchronised();
view = (TextView) findViewById(R.id.last_updated_textview);
view.setText("Last synchronised: " + currentDate + " Total games: " + String.valueOf(collectionHandler.getDisplayedCollection().size()));
collectionAdapter = collectionHandler.getCollectionAdapter();
ListView listView = (ListView) findViewById(R.id.collection_list_view);
listView.setAdapter(collectionAdapter);
AdapterView.OnItemClickListener collectionItemClickListener = new AdapterView.OnItemClickListener(){
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
launchGameDetailsActivity(position);
}
};
listView.setOnItemClickListener(collectionItemClickListener);
}
public void launchGameDetailsActivity(int position){
Log.d(className,"Starting lauchGameDetailsActivity method");
collectionHandler.setSelectedGame(position);
Intent intent = new Intent(this,ViewGameDetailsActivity.class);
startActivity(intent);
Log.d(className, "Ending lauchGameDetailsActivity method");
}
The XML for the activity:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:paddingBottom="#dimen/activity_vertical_margin"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
tools:context="com.bleachedlizard.ludome.viewcollection.ViewCollectionActivity">
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Synchronise Collection"
android:onClick="synchroniseCollection"/>
<TextView
android:id="#+id/last_updated_textview"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Last synchronised: "
android:textAlignment="center"
/>
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Display Collection"
android:visibility="gone"
android:onClick="displayCollection"/>
<ListView
android:id="#+id/collection_list_view"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1">
</ListView>
<TextView
android:id="#+id/no_items_textview"
android:layout_width="match_parent"
android:layout_height="50dp"
android:text="You have no items in your collection."
android:textAlignment="center"
android:textSize="20sp"/>
</LinearLayout>
The XML for the item views:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/collection_item_layout"
android:layout_width="match_parent"
android:layout_height="75dp"
android:orientation="horizontal"
android:clickable="false"
android:descendantFocusability="blocksDescendants"
android:focusable="false"
android:focusableInTouchMode="false">
<ImageView
android:id="#+id/collection_item_image"
android:layout_width="75dp"
android:layout_height="75dp"
android:src="#drawable/testimage"
android:focusable="false"
android:focusableInTouchMode="false"
android:clickable="false"
/>
<TextView
android:id="#+id/collection_item_name"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="center_vertical"
android:padding="16dp"
android:singleLine="false"
android:textColor="#android:color/darker_gray"
android:focusable="false"
android:focusableInTouchMode="false"
android:clickable="false"
android:textIsSelectable="false"/>
<TextView
android:id="#+id/collection_item_plays"
android:layout_width="100dp"
android:layout_height="match_parent"
android:gravity="center_vertical"
android:padding="8dp"
android:textColor="#android:color/darker_gray"
android:text="Plays: 0"
android:focusable="false"
android:focusableInTouchMode="false"
android:clickable="false"
android:textIsSelectable="false"/>
</LinearLayout>
The code for the custom adapter:
public class GameCollectionAdapter extends ArrayAdapter<Game> {
private ArrayList<Game> collection;
public GameCollectionAdapter(Context context, int resource, ArrayList<Game> collection){
super(context, resource, collection);
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
LinearLayout gameView = (LinearLayout) convertView;
LayoutInflater mInflater = LayoutInflater.from(getContext());
if (gameView == null) {
gameView = (LinearLayout) mInflater.inflate(R.layout.collection_item_view, null);
}
//Game game = collection.get(position);
Game game = super.getItem(position);
if (game != null) {
// This is how you obtain a reference to the TextViews.
// These TextViews are created in the XML files we defined.
TextView gameTitle = (TextView) gameView.findViewById(R.id.collection_item_name);
TextView numOfPlays = (TextView) gameView.findViewById(R.id.collection_item_plays);
ImageView thumbnail = (ImageView) gameView.findViewById(R.id.collection_item_image);
// check to see if each individual textview is null.
// if not, assign some text!
if (gameTitle != null){
gameTitle.setText(game.getTitle());
}
if (numOfPlays != null){
numOfPlays.setText("Plays: " + String.valueOf(game.getNumOfPlays()));
}
if (thumbnail != null){
thumbnail.setImageBitmap(game.getThumbnail());
}
}
// the view must be returned to our activity
return gameView;
}
#Override
public boolean isEnabled(int position) {
return true;
}
}
I discovered what was causing the problem: the way I had set up the array that backed the ListView meant that it was downloading and storing the Bitmaps for every element in the array all the time. Once I changed the implementation so that it only downloaded the images as the ListView required them, then that seemed to improve performance and the onClickListener started to work fine.
The implementation I used was the exact same one shown here:
http://developer.android.com/training/displaying-bitmaps/process-bitmap.html
I think the issue is due to the position of the item selection whenever you click you have an list position which is passed to your method launchGameDetailActivity(int position) check with log or toast on item click what all the position you are getting do the needful.
Here is my code try this like this if it helps.
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Toast.makeText(RecipeClass.this, "Position is" + position, Toast.LENGTH_SHORT).show();
Intent intent = new Intent(RecipeClass.this, RecipeIngredients.class)
intent.putExtra("position", position);
startActivity(intent);
}
Check your arraylist value also whether they are not null.
I have a Activity that displays a list of check boxes (Focus Areas) that can be assigned to an activity event in my application. However I want to be able to prevent the user form editing these values until a button is clicked to put the form into edit mode.
Can some one explain or provide code sample how I can implement this into my application?
This list is held in a ListView with a custom ArrayAdapter of a Type FocusArea a class I have created for my application.
The xml for the Activity is shown below:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" android:background="#drawable/horizontal_gradient_line_reverse">
<TextView
android:id="#+id/textViewCustomerNameNumber"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:text="Customer Name & Number" android:layout_margin="5dp"/>
<ListView
android:id="#+id/listViewFocusAreas"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_above="#+id/relativeLayoutControls"
android:layout_alignParentLeft="true"
android:layout_below="#+id/textViewCustomerNameNumber"
android:layout_margin="5dp"
android:background="#drawable/myborder" >
</ListView>
<RelativeLayout
android:id="#+id/relativeLayoutControls"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true" >
<ImageView
android:id="#+id/imageViewCancelFocusAreaChanges"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_alignParentTop="true"
android:src="#drawable/ic_mini_undo" />
<ImageView
android:id="#+id/imageViewSaveFocusAreaChanges"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_toLeftOf="#+id/imageViewCancelFocusAreaChanges"
android:src="#drawable/ic_mini_save" />
<ImageView
android:id="#+id/imageViewEditFocusArea"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_toLeftOf="#+id/imageViewSaveFocusAreaChanges"
android:src="#drawable/ic_mini_edit" />
</RelativeLayout>
<ImageView
android:id="#+id/imageViewEditMode"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBottom="#+id/textViewCustomerNameNumber"
android:layout_alignRight="#+id/listViewFocusAreas"
android:src="#drawable/edit16x16"
android:visibility="gone" />
</RelativeLayout>
The following is the xml for the focus area row:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<CheckBox
android:id="#+id/checkBoxFocusArea"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Focus Area" />
</LinearLayout>
The following is the code for the Custom ArrayAdapter:
public class FocusAreaAdapter extends ArrayAdapter<FocusArea> {
private ArrayList<FocusArea> focusAreas;
private Context context;
public FocusAreaAdapter(Context context, int textViewResourceId, ArrayList<FocusArea> focusAreas) {
super(context, textViewResourceId, focusAreas);
this.context = context;
this.focusAreas = focusAreas;
}
#Override
public View getView(final int position, View convertView, final ViewGroup parent) {
View v = convertView;
if(v == null) {
LayoutInflater vi = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v = vi.inflate(R.layout.focus_area_menu_item, null);
}
FocusArea focusArea = focusAreas.get(position);
if(focusArea != null) {
CheckBox cbFocusArea = (CheckBox)v.findViewById(R.id.checkBoxFocusArea);
cbFocusArea.setText(focusArea.getFocusAreaCodeDescription());
if(focusArea.isFocusAreaCodeChecked() == 1) {
cbFocusArea.setChecked(true);
} else {
cbFocusArea.setChecked(false);
}
cbFocusArea.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
FocusArea focusArea = focusAreas.get(position);
if(focusArea.isFocusAreaCodeChecked() == 1) {
focusArea.setFocusAreaCodeChecked(0);
} else {
focusArea.setFocusAreaCodeChecked(1);
}
}
});
}
return v;
}
}
Finally I instanciate my custom array adapter with the following code:
private void assignFocusAreasToAdapter() {
// get reference to available responsibles list view control
lvFocusAreas.clearChoices();
// create an array adapter with the communications data array
activityFocusAreaAdapter = new FocusAreaAdapter(this, R.layout.focus_area_menu_item, activityFocusAreas);
// assign the my customers list control the array adapter
lvFocusAreas.setAdapter(activityFocusAreaAdapter);
activityFocusAreaAdapter.notifyDataSetChanged();
Log.i(TAG, "Available Activity Focus Areas Loaded");
}
Ok i found the solution to this problem for anyone who might have the same issue.
The XML for the Focus Area activity stays the same as posted above.
The XML for the Focus Area row item is modified accordingly:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:descendantFocusability="blocksDescendants" >
<CheckBox
android:id="#+id/checkBoxFocusArea"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Focus Area" />
</LinearLayout>
You can see that this now has the following line added android:descendantFocusability="blocksDescendants" This prevents the checkboxes onClickListener from firing which normally will block the ListViews OnItemClickedListener from firing.
The Custom Adapter code is modified to remove the checkboxes OnClickListener like so:
public class FocusAreaAdapter extends ArrayAdapter<FocusArea> {
private ArrayList<FocusArea> focusAreas;
private Context context;
public FocusAreaAdapter(Context context, int textViewResourceId, ArrayList<FocusArea> focusAreas) {
super(context, textViewResourceId, focusAreas);
this.context = context;
this.focusAreas = focusAreas;
}
#Override
public View getView(final int position, View convertView, final ViewGroup parent) {
View v = convertView;
if(v == null) {
LayoutInflater vi = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v = vi.inflate(R.layout.focus_area_menu_item, null);
}
FocusArea focusArea = focusAreas.get(position);
if(focusArea != null) {
CheckBox cbFocusArea = (CheckBox)v.findViewById(R.id.checkBoxFocusArea);
cbFocusArea.setText(focusArea.getFocusAreaCodeDescription());
if(focusArea.isFocusAreaCodeChecked() == 1) {
cbFocusArea.setChecked(true);
} else {
cbFocusArea.setChecked(false);
}
cbFocusArea.setClickable(false);
}
return v;
}
}
The Custom Adapter is instanciated using the same code as posted in above but you must add an OnItemClickListener to the ListView and preform the check of the checkbox inside the OnItemClickListener click event like so:
lvFocusAreas = (ListView)findViewById(R.id.listViewFocusAreas);
lvFocusAreas.setOnItemClickListener(new AdapterView.OnItemClickListener() {
public void onItemClick(AdapterView<?> adapter, View view, int position, long id) {
if(editMode){
FocusArea focusArea = (FocusArea)lvFocusAreas.getItemAtPosition(position);
if(focusArea.isFocusAreaCodeChecked() == 0) {
focusArea.setFocusAreaCodeChecked(1);
} else {
focusArea.setFocusAreaCodeChecked(0);
}
activityFocusAreaAdapter.notifyDataSetChanged();
setControlsEnabled();
}
}
});
Hope this helps any one thats having the same problem. :D