ListView.getChildAt(validPosition) returns null - android

When user clicks on item of ListView I show Edit button at this item of list. lastSelectedPosition has the position of the list item that was clicked last.
code:
public class MainActivity extends Activity {
private ListView listView;
private MyAdapter adapter;
// static - If the activity is re-created, the data
// about list items remain.
private static List<String> items = loadItems();
private MyItemClickListener listener = new MyItemClickListener();
private int lastSelectedPosition = ListView.INVALID_POSITION;
#Override
protected void onCreate(Bundle savedInstanceState) {
listView = (ListView) findViewById(R.id.myListView);
adapter = new MyAdapter(R.layout.my_item, items);
listView.setAdapter(adapter);
listView.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
listView.setOnItemClickListener(listener);
if (savedInstanceState != null) {
// Is recreating the activity because
// of the change screen orientation.
lastSelectedPosition = savedInstanceState.getInt("lastSelectedPos");
if (lastSelectedPosition != ListView.INVALID_POSITION) {
// !!! getChildAt() always returns null !!!
View listItem = listView.getChildAt(lastSelectedPosition);
View editButton = listItem.findViewById(R.id.editButton);
// Only selected list item has visible EditButton,
// other list items have not
editButton.setVisibility(View.VISIBLE);
}
}
}
#Override
protected void onSaveInstanceState(Bundle outState) {
// Is destroying the activity because
// of the change screen orientation.
outState.putInt("lastSelectedPos", lastSelectedPosition);
}
// Other methods
}
I think that getChildAt() always returns null in Activity.onCreate(), because at that moment the list is not yet fully developed. How I can get View of list item to show Edit button on it?
And sorry for my English.
Thanks

Your adapter needs to know about this selected position so it can be rendered properly in getView(). Just modify the constructor for your adapter to take the int, and update that int value whenever the onclick is called. In general, you should always have all the information you need to recreate the state of your list items within your adapter.

I think it is because you didn't change your lastSelectedPosition's value when user click on item in your listview. Just implement your onItemClickListener like the following code snippet. And change your lastSelectedPosition's value on this. And remove your
private MyItemClickListener listener = new MyItemClickListener();
line.
I think the value of lastSelectedPosition is couldn't changed until you define your listener variable. And also I didn't know where you define your listener variable.
lv1.setOnItemClickListener(new OnItemClickListener() {
public void onItemClick(AdapterView<?> arg0, View arg1, int arg2,
long arg3) {
lastSelectedPosition = arg2
}
});
I hope this will help you.

Related

Problem with spinner in Recyclerview android

Recyclerview item contains spinner and textviews. All item's spinners are correctly set. Whenever ith item spinner changes, ith item textviews values will also be changed.
The problem here is, one item spinner click action changes other items spinner values.
Adapter class:
public void onBindViewHolder(#NonNull final MyViewHolder holder, final int position) {
//do not re-initialize spinner when behaviour of item is changing
if (holder.spinnerWeightUnit.getAdapter() == null) {
List<String> unit_list = new ArrayList<>();
for (Productsku x : productskuList) {
unit_list.add(x.getWeight() + x.getUnit());
}
initializeUnitSpinner(holder.spinnerWeightUnit, unit_list);
holder.spinnerWeightUnit.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
#Override
public void onItemSelected(AdapterView<?> adapterView, View view, int i, long l) {
Timber.d("adapter item changed");
setPriceStockValues(holder, position, i);
}
#Override
public void onNothingSelected(AdapterView<?> adapterView) {}
});
}
}
private void initializeUnitSpinner(Spinner spinnerUnit, List<String> unit_list) {
ArrayAdapter<String> unitArrayAdapter = new ArrayAdapter<>(mContext, android.R.layout.simple_spinner_item, unit_list);
unitArrayAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinnerUnit.setAdapter(unitArrayAdapter);
}
private void setPriceStockValues(MyViewHolder holder, int position, int unit_position) {
//set textviews
}
scenario:
0th item spinner value selected -> all spinners are correct
1st item spinner value selected -> all spinners are correct
again 0th item spinner value selected -> all spinners are set to 1st item's spinner values
again 1st item spinner values selected -> all spinner are set to 0th item's spinner values
..and so on.
I am unable to find out the solution for this. Please any one can help?
Thank you.
try with removing this line
if (holder.spinnerWeightUnit.getAdapter() == null)
set up your adapter every time when onBindViewHolder get called. RecyclerView uses recycling pattern - reusing previously used/shown Views/ViewHolders. above if prevents to re-set paticluar item on proper position, keeps old OnItemSelected listener and adapter

Adding Objects from ListView to ArrayList to add to SQLite

I am trying to create a waiter app which allows the waiter to take orders.
I am trying to achieve this using a ListView and setOnItemClickListener.
My idea is that every time a Item is clicked on the ListView it will be added to a ArrayList<Item>. Which later I can pass this List to a method created in DataBaseHelper which then iterates through the List and adds each Item from the order to the SQLite database.
I have not created the method in the DataBaseHelper class yet but I would like to know how to populate the ArrayList<Item> first and then move on to the next step.
The table I will be adding the list to has a manny to many relationship and is called order_item. Which also brings a question to mind as I do not need the full details about the Item and only the IDto save in the table do I need to get all the information of the Item?
Right now what is happening is the app allows me to click and add one Item and then the apps is forced to close.
I am also not sure if I should make the ArrayList a global variable or have it in the Order Object as a variable?
The log says:
java.lang.IllegalStateException: The content of the adapter has changed but ListView did not receive a notification. Make sure the content of your adapter is not modified from a background thread, but only from the UI thread. Make sure your adapter calls notifyDataSetChanged() when its content changes. [in ListView(2131165292, class android.widget.ListView) with Adapter(class android.widget.ArrayAdapter)]
OrderActivity
public class OrderActivity extends AppCompatActivity {
EditText waiter_id;
Button order;
ListView orderList;
List<Item> itemList = new ArrayList<Item>();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_order);
waiter_id = (EditText) findViewById(R.id.waiter_id);
order = (Button) findViewById(R.id.order_button);
orderList = (ListView) findViewById(R.id.item_list);
//Showing Items on the ListView
DataBaseHelper dbHelp = new DataBaseHelper(OrderActivity.this);
final List<Item> itemList = dbHelp.getMenu();
ArrayAdapter itemArrayAdaptor = new ArrayAdapter<Item>(OrderActivity.this, android.R.layout.simple_list_item_1, itemList);
orderList.setAdapter(itemArrayAdaptor);
// setOnItemClickListener
orderList.setOnItemClickListener(new AdapterView.OnItemClickListener() {
Item item;
#Override
public void onItemClick(AdapterView<?> adapterView, View view, int pos, long id) {
//Selecting the Item and storing it in a reference variable to add to itemList
Toast.makeText(OrderActivity.this, "Order" + pos , Toast.LENGTH_SHORT).show();
Item item = (Item) adapterView.getAdapter().getItem(pos);
Toast.makeText(OrderActivity.this, item.toString() , Toast.LENGTH_SHORT).show();
itemList.add(item);
}
});
}
}
The problem was I was not notifying the list notifyDataSetChanged() that the item I selected had changed here is the code which now populates the list.
// setOnItemClickListener
orderList.setOnItemClickListener(new AdapterView.OnItemClickListener() {
Order order;
#Override
public void onItemClick(AdapterView<?> adapterView, View view, int pos, long id) {
//Selecting the Item and storing it in a reference variable to add to itemList
Toast.makeText(OrderActivity.this, "Order" + pos , Toast.LENGTH_SHORT).show();
orderItemList.add((Item) adapterView.getAdapter().getItem(pos));
itemArrayAdaptor.notifyDataSetChanged();
Toast.makeText(OrderActivity.this, orderItemList.toString(), Toast.LENGTH_SHORT).show();
}
});
orderList.setOnItemClickListener(
new AdapterView.OnItemClickListener() {
#Override public void onItemClick(AdapterView<?> adapterView, View
view, int pos, long id) {
Toast.makeText(OrderActivity.this, "Added"
,Toast.LENGTH_SHORT).show();
itemList.add(adapterView.getItemAtPosition(pos));
}
});

Keep listview item selected even if view changes

I have a listview in fragment.
When I select a listview item, it gets highlighted and then I open another fragment.
Now, what I want is, when I move back to previous fragment, the list item should stay selected.
How can I do that?
I have implemented like
add this two methods in your Adapter
private int selectedIndex = ListView.NO_ID;
public int getSelectedIndex() {
return selectedIndex;
}
public void setSelectedIndex(int index) {
this.selectedIndex = index;
// Re-draw the list by informing the view of the changes
notifyDataSetChanged();
}
and in your Adapter getView(...) do
// Highlight the selected item in the list
if (selectedIndex != -1 && selectedIndex == position) {
YourView.setBackgroundResource(R.color.lightred);
}
and implement in Fragment in setOnItemClickListener onItemClick(...) like
adapter.setSelectedIndex(position);
save this selected value in some preferences and when you come back again call in Fragment on resume(...)
adapter.setSelectedIndex(selectedIndex);
OK let's do this
declare one field in your adapter say
private int selectedPosition=-1;
now create a setter for this
private void setSelectedPosition(int position)
{
selectedPosition=position;
}
Now in your getView method
if(position==selectedPosition)
{
listItemView.setSelected(true);
//OR
listItemView.setBackgroundColor(<Some Color>);
}
Now after setting the adapter when user tap and your OnItmeSelected called
adapter.setSelectedPosition(<your desired selected item position>);
adapter.notifyDataSetChanged();

How to get the id resource id of a view in a List view

I have Listview which is showing different images of animals,birds,reptiles. The list view is working fine. Now I want when user click to any picture it should appear in the ImageView.The ImageView is just below the listview. so when ever user will click any image in the listview it should appear in the Imageview.
Also there is a button. Now I want to achieve that when user select any image and press Ok button that paticular image should show on the image view of other activity also. I Know I can send the Id through intent.putextra(), but the problem is first place how to get the id of particular picture.
Source code
public class MainActivity2 extends ActionBarActivity {
private TypedArray ListIcons;
private HorizontalListView listView;
private ArrayList<AnimalsListItems> SuitItems;
private AnimalsListAdapter adapter1 = null;
/** An array of strings to populate dropdown list */
String[] actions = new String[] {
"Bookmark",
"Subscribe",
"Share"
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main_activity2);
listView = (HorizontalListView) findViewById(R.id.suits_list);
AnimalsItems = new ArrayList<AnimalsListItems>();
/** Create an array adapter to populate dropdownlist */
ArrayAdapter<String> adapter = new ArrayAdapter<String>(getBaseContext(), android.R.layout.simple_spinner_dropdown_item, actions);
/** Enabling dropdown list navigation for the action bar */
getSupportActionBar().setNavigationMode(ActionBar.NAVIGATION_MODE_LIST);
getSupportActionBar().setDisplayShowTitleEnabled(false)
;
getSupportActionBar().setDefaultDisplayHomeAsUpEnabled(true);
getSupportActionBar().setTitle(" "+" "+" ");
/** Defining Navigation listener */
android.support.v7.app.ActionBar.OnNavigationListener navigationListener = new android.support.v7.app.ActionBar.OnNavigationListener() {
#Override
public boolean onNavigationItemSelected(int itemPosition, long itemId) {
Toast.makeText(getBaseContext(), "You selected : " + actions[itemPosition], Toast.LENGTH_SHORT).show();
ListIcons = getResources()
.obtainTypedArray(R.array.ic_launcher);// load icons from
// strings.xml
for (int i = 0; i<=ListIcons.length(); i++) {
AnimalsItems.add(new AnimalsListItems(ListIcons.getResourceId(i,-1)));
}
adapter1 = new SuitsListAdapter(getApplicationContext(),SuitItems);
Log.v(adapter1.getCount()+"");
listView.setAdapter(adapter1);
return false;
}
};
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
//With the position parameter, you can fetch the item at the clicked position like below. Cast it to whatever type your ListView is.
Object yourItem = (Object) listView.getItemAtPosition(position);
//Now you can assign the image to an imageview
}
});
/** Setting dropdown items and item navigation listener for the actionbar */
getSupportActionBar().setListNavigationCallbacks(adapter, navigationListener);
this.overridePendingTransition(R.anim.anim_slide_in_left,
R.anim.anim_slide_out_left);
}
}
For your ListView, you can set an onItemClickListener as below
ListView listView1 = (ListView) findViewById(R.id.listView1);
listView1.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
//With the position parameter, you can fetch the item at the clicked position like below.
AnimalsListItems yourItem = (AnimalsListItems) listView1.getItemAtPosition(position);
//Now you can assign the image to an imageview
}
}
Not sure what you mean by "id", if you're talking about drawable id's, path to image files, or just any way to identify your image. It depends a lot on how you populate your list. You didn't supply any code at all.
But since you have a ListView I suppose you have an Adapter, and that you're backing that adapter with some data, such as an array, database etc. When you click on an item, you get an onItemClick callback with the index of the item you clicked on. You should be able to use this index to find which image you clicked on from your data source.
Then when it comes to passing that to another activity, well, again it depends on how you represent your images but you should be able to pass whatever data you need to represent the image in an intent extra to the second activity.
You can use the setOnItemClickListener method of ListView to get witch item clicked.Because one item one image, you can get the target image.
1.Step
Rather getting resource id you can create one integer array containing resource id's like,
int resourceID[] = [R.drawable.image1, R.drawable.image2, ...]
Assign this array to your ListView image item
2.Step
Now can easily get the postion of selected list item or image using Lists on item click method
listView.setOnItemClickListener(new OnItemClickListener() {} )
3.Step
Just pass your ResourceID array & tapped position to next/target activity & use it, rather passing resourceID
or
Otherwise make your ResourceID as static, pass only tapped position to next Activity & use this static ResourceID from previous Activity
i.e -> yourImageView.setImageResource(FirstActivity.ResourceID[position])

Spinner OnclickListener event executes twice, how to handle both events

Spinner OnclickListener event executes twice -
Spinner initialization
User selected manually
where as implementation of listener is as :
spinner.setOnItemSelectedListener(new OnItemSelectedListener() {
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
}
public void onNothingSelected(AdapterView<?> parent) {
}
});
Problem definition
I want to save user selected text into data storage, when user choose any item from spinner, and I am able to do this. But my another task is that to show previously selected item (access from data storage) as selected item in spinner, but each time when I call spinner's activity, spinner shows first item as default selected item, and also in data storage it make change previous item to default.
How can I make difference between 'Spinner initialization' and 'User selected manually' events?
You have to handle both events logically. As these references (Android Spinner selection, problem on spinner) says that you have to use flag variable to handle this, I am putting a code sample.
Hope this will help you to clear your logic.
public class TestActivity extends Activity {
//Checks report spinner selection is default or user selected item
private boolean isDefaultSelection;
//Spinner setup
Spinner spinner;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.your_layout);
// Set true at onCreate
isDefaultSelection = true;
spinner = (Spinner) findViewById(R.id.id_of_spinner);
ArrayAdapter<String> spinnerAdapter = new ArrayAdapter<String> (this, R.layout.drop_down_custom_row, data);
//Implement custom view for drop down of spinner
//spinnerAdapter.setDropDownViewResource( android.R.layout.simple_spinner_dropdown_item);
spinner.setAdapter(spinnerAdapter);
spinner.setOnItemSelectedListener(new OnItemSelectedListener() {
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
if(isDefaultSelection) { //If spinner initializes
spinner.setSelection("Set_here_id_of_data_item_from_storage_which_was_previously_stored");
isDefaultSelection = false;
} else { //If user manually select item
int itemPosition = spinner.getSelectedItemPosition();
//Write here code to store selection (itemPosition) of user into data storage
}
}
public void onNothingSelected(AdapterView<?> parent) {
//User selected same item. Nothing to do.
}
});
}
}
Hope it will clear your doubt.
You can call the setSelection at the same time that the items are added to the adapter, see this example: How to avoid onItemSelected to be called twice in Spinners

Categories

Resources