I have a button on an activity which when pressed loops through a list of items, adds them to a database and then closes the activity.
My problem is that sometimes on slow phones and a lot of list items the user can press the button again before the activity closes, causing a duplicate insertion.
What is the recommended way of stopping this from happening, I've tried disabling the button on press but it does not get refreshed on the screen.
buttonAddChecked.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
SparseBooleanArray CheckedItemIDs = listViewFavorites.getCheckedItemPositions();
for (int i = 0; i < CheckedItemIDs.size(); i++) {
View element = listViewFavorites.getAdapter().getView(CheckedItemIDs.keyAt(i),
null, null);
ShoppingListItem sli;
sli = (ShoppingListItem) element.getTag();
db.insertItem(sli.itemName, 0, sli.itemNotes,
sli.categoryID);
} // looped round all checked items
finish();
}
});
use progressDialog
to stop user interaction once it presses the button.
Related
I have a listview and in each cell it has a RelativeLayout with 7 buttons.
before the list is scrolled all the buttons work fine (all trigger when clicked) for all visible listView items, but after listView was scrolled some items turn to not clickable (no matter which button in the item I click), and it's random, after another scroll the same item can turn clickable, and other which was before turns to not clickable.
I have noticed that it usually happens (item turns not clickable) after scrolling all the way up.
Another thing that i have noticed that seldom (after 4-5 unsuccessful clicks in a row) the button triggers a few times in a row (like it was delayed). But usually it's not happening after a number of unsuccessful clicks.
In my original code I created an arrayList of RelativeLayouts (each for listView Item), and put the arrayList into adapter. For every 7 buttons (for each cell) I set 7 ids corresponding to their's place in arraylist.
In that way I implemented the OnClick event in the main class.
Here is 3 buttons (out of 7):
for (int i = 0; i < EXPEND_BUTTONS.length; i++) {
if (view.getId() == EXPEND_BUTTONS[i]) {
handleEmojiPanel(i);
break;
}
if (view.getId() == BUTTONS[i] || view.getId() == IMAGES[i]) {
ShowTopItem item = new ShowTopItem(getActivity(), i);
item.show();
break;
}
}
Because of the problem I change the code.
I handled the OnClick event for the buttons in the adapter itself in the getView method (for 2 buttons only):
public View getView(final int position, View convertView, ViewGroup parent) {
pos = position;
Button btn = (Button) listOfObjects.get(position).getChildAt(0);
btn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
ShowTopItem item = new ShowTopItem(getActivity(), position + listChosen);
item.show();
}
});
Button imageBtn = (Button) listOfObjects.get(position).getChildAt(2);
imageBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
ShowTopItem item = new ShowTopItem(getActivity(), position + listChosen);
item.show();
}
});
return listOfObjects.get(position);
}
I have the same result. Nothing changed.
I have looked all over the internet, and it seems that I'm the only one who encountered such issue.
Id anybody knows what can be the issue here?
If some other code is needed, please feel free to ask.
I did not find the reason, but I changed ListView to ScrollView, and all works fine now.
Maybe there is some kind of bug in ListView, but in this case, I wonder why I did not find any complains regarding it.
Anyway, works perfect with ScrollView.
I have a Recyclerview where there is a button onclicklistener in the viewholder constructor:
public ViewHolder(View itemView)
{
super(itemView);
...
button.setOnClickListener(new View.OnClickListener()
{
#Override
public void onClick(View v)
{
...
}
}
}
Each item also has a countdown, every second the countdown is decremented and a progressbar of the item is updated to display the time left.
The timer is done with a runnable:
countdownHandler.postDelayed(countdownRunnable, 1000);
which then iterates through all the items, decrements the countdown and notifies the adapter:
countdownRunnable = new Runnable()
{
#Override
public void run()
{
Iterator<Item> iterator = countdownTasks.iterator();
while (iterator.hasNext())
{
item.decrementCountdown();
adapter.notifyItemChanged(items.indexOf(item));
}
if (countdownTasks.size() > 0)
countdownHandler.postDelayed(countdownRunnable, 1000);
}
}
Here is my problem, it also occurs if there is only one item in the list.
I press the button and is in the pressed state, but when the countdown update triggers, the button is no longer pressed. Releasing the button doesn't activate the button as it should. If I remove the countdown, it works properly.
I don't change the button in onBindViewHolder and I am not scrolling since there is only one item. Is this expected bahavior, that all button presses get canceled as soon as notifyItemChanged is called or am I doing something wrong? Does this even work with the onClickListener or do I need an onTouchListener and save the touchdown state in the item and reset it every update?
Thank you!
Edit:
I found out, that if I set
recyclerView.setItemAnimator(null);
it works without problems. Does anyone know why that is the case and how I can still get animation without the hassle of remembering all the states?
When you call adapter.notifyItemChanged(items.indexOf(item)); it rebind view for that position, which is fresh view stored in ViewHolder & don't have a pressed state & that's why it loses button state.
You can do it by using OnTouchListener and storing states as you mentioned in question.
I am writing as anshwer since i don't have reputation for comment.
I have one activity and here i have 100 buttons, i want that when i press Button 1 then press another Button the Button 1 should get unpressed.
i know i can make this with
if(Button1.isPressed()) {
Button2.setPressed(false);
Button3.setPressed(false);
Button4.setPressed(false);
Button5.setPressed(false);
Button6.setPressed(false);
Button7.setPressed(false);
Button8.setPressed(false);
......................... }
else { do nothing }
.... BUT!
it's too much code
Coders will kill me or will just laugh on me.
any ideas?
maybe there is a way to unpress the all buttons from the activity?
Not the prettiest solution ever, but you could make an OnClickListener like this:
View.OnClickListener listener = new View.OnClickListener() {
public void onClick(View v) {
ViewGroup parent = (ViewGroup) v.getParent();
for (int i = 0; i < parent.getChildCount(); i++) {
View current = parent.getChildAt(i);
if (current != v && current instanceof Button) {
((Button) current).setPressed(false);
}
}
((Button) v).setPressed(true);
}
}
and attach it to all of your buttons.
Then, whenever a button is clicked, it will iterate over all views that are in the same layout (or actually, view group) as the clicked button, and, for any of those views that are buttons except for the clicked button, it will call setPressed(false).
Note that this only works out of the box if all the buttons are in the same layout. If they are in nested layouts, you will have to adapt it a little.
Off topic: What do you need 100 buttons for? That's a lot of buttons. You may want to redesign your user interface
Ok so instead of looping through all the buttons on over and over again when one button is pressed, you can just store a variable which stores the button number of the button that was last pressed. Now, when the second button is pressed, disable the button that was pressed earlier, you get its index from the saved variable, enable the button that was pressed and store its index in the variable.
Heres an example pseudo code to give you and idea:
int buttonLastPressed = 0;
void onButtonClick(Button buttonPressed){
if(buttonLastPressed != 0){
disableButton(buttonLastPressed);
enableButton(buttonPressed);
buttonLastPressed = buttonPressed.getIndex()
}
}
Saves you from looping through each and every button to disable it.
Define id of button 1 to 100
When press button occurs save it's id in some member variable like previous_pressed
Before updating a previous_pressed value find and unpress previous pressed button like this
Button previous_pressed_button = (Button) findViewById(previous_pressed);
Now you have the previous pressed button, So upress it or whatever.
I have a Activity in android that has 4 buttons.
The first 3 buttons fetches a json data from a weather API for 1 day, next 5 days and next 10 days respectively.
I have a 4th button placed at the bottom of the screen, which takes user to second activity.
I want to restrict the entry of user to second Activity if no button from top 3 is clicked.
If the data is fetched, I mean any one of the top 3 buttons have been clicked, allow him to go to second activity on 4th button click else show a message.
How can i check on click of 4th button if any of the top 3 buttons have been clicked before?
Thanks
Put a boolean field in your activity, name it clicked and set it to false on the onCreate method of your first activity, then in the onClick method of your 3 buttons, set it to true,
and in the onClick method of your 4th button check it, if it's true go startActivity, else launch a Toast
You can make the 4th button look disable in "OnCreate" with the function "setEnabled"(may be wrong),
and then just set "setOnClickListener" for the 4th button when you click any of the others.
ps.
Can provide code example if needed.
Why don't you use if statement? You can keep the clicked count data under the first three buttons. Like this;
import java.util.stream.*;
int[] btnMemory = new int[4];
button1.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
btnMemory[0] = 1;
// your code
}
});
after, you can check it with if statement under 4th button;
button4.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
int sum = IntStream.of(btnMemory).sum();
if(sum >= 3)
// your code
}
});
It is definitely firing because I can for only a moment see the dialog pop up, but then the screen backs out anyway. How do I stop the back button from working? My device is on Gingerbread and my Min SDK is 10.
public override void OnBackPressed()
{
base.OnBackPressed();
TableLayout tl = (TableLayout)FindViewById(Resource.Id.myEquip);
int cnt = tl.ChildCount;
for (var i = 0; i < cnt; i++)
{
TableRow tr = (TableRow)tl.GetChildAt(i);
TextView tv = (TextView)tr.GetChildAt(0);
if (tv.Text != "Equipment not found at current store")
{
Dialog d = inst2.showBuilder(this, "test", tv.Text);
d.Show();
}
}
return;
}
You're calling base.OnBackPressed(), which is why you're still getting the default behavior. If you don't want the system to handle the back button, you shouldn't call that method. That said, in most cases you shouldn't be preventing the back button from working since that can be very weird for user experience. One example where it makes sense is if you were building a web browser: pressing back will go back to the previous page if there was one, and call base.OnBackPressed() if there are no more pages left.