grantka grantka - 2 months ago 12
Android Question

ListView onItemClick and DelayedConfirmationView onTimerSelected triggered with same click

I did a SO search but didn't really know what to look for. So sorry if this is a dumb question. I'm new to android programming and I'm trying to make a wearable app with a listview. When the user clicks an item, it should show a delayed confirmation view that allows the user to cancel the selection. I have an activity with two views, a ListView and a DelayedConfirmationView.

When a list item is clicked, the timer is started and delayedConfirmationView is shown.

@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
mSelectedPosition = position;
setListViewVisible(false);

// Two seconds to cancel the action
mDelayedView.setTotalTimeMs(2000);
// Start the timer
mDelayedView.start();
}


I switch between the two views like this:

private void setListViewVisible(boolean listViewVisible) {
if(listViewVisible){
mListView.setVisibility(View.VISIBLE);
mDelayedView.setVisibility(View.GONE);
}else{

mListView.setVisibility(View.GONE);
mDelayedView.setVisibility(View.VISIBLE);
}
}


If the cancel button is pressed, I switch back to the listview so the user can revise their selection:

@Override
public void onTimerSelected(View view) {
// cancel selected, so go back to listview
setListViewVisible(true);
}


The problem I'm having is that when I hit the cancel button, it also triggers the onItemClickListener for the listview, so it instantly transfers back to the delayed confirmation view.

I feel like the answer should be simple, but it's strange to me that the same click triggers both onTimerSelected and onItemClick.

Edit:
I tried adding a delay before switching the views to see if the view transition was too fast and picking up the button press.

Here are the logs BEFORE the delay was added:


D/AddClimbActivity: onCreate()

D/AddClimbActivity: setListViewVisible(true)

D/AddClimbActivity: onItemClick

D/AddClimbActivity: setListViewVisible(false)

D/AddClimbActivity: onTimerSelected <-- PRESSING THE CANCEL BUTTON

D/AddClimbActivity: setListViewVisible(true)

D/AddClimbActivity: onItemClick <-- UNEXPECTED BEHAVIOR

D/AddClimbActivity: setListViewVisible(false)

D/AddClimbActivity: onTimerFinished


New onTimerSelected:

@Override
public void onTimerSelected(View view) {
Log.d(TAG, "onTimerSelected");
// cancel selected, so go back to listview
Handler handler = new Handler();
handler.postDelayed(new Runnable() {

@Override
public void run() {
setListViewVisible(true);
}
}, 50);
Log.d(TAG, "onTimerSelected exit");
}


And the new log:


D/AddClimbActivity: onCreate()

D/AddClimbActivity: setListViewVisible(true)

D/AddClimbActivity: onItemClick

D/AddClimbActivity: setListViewVisible(false)

D/AddClimbActivity: onTimerSelected

D/AddClimbActivity: onTimerSelected exit

D/AddClimbActivity: setListViewVisible(true)

D/AddClimbActivity: onTimerFinished <-- UNEXPECTED BEHAVIOR


So by adding the delay I get some unintended behavior where both the onTimerSelected and onTimerFinshed callbacks are called.

Answer

I ended up having to add two things to get this to work. I had to delay the view switch (see the edit in my post) as well as setting the delayed confirmation view listener to null so onTimerFinished didn't get called. It seems strange that android wouldn't cancel the timer when it's selected by default, but maybe there's a use case for having the user press the button without the timer being stopped?

Anyways, here's what my code ended up being:

@Override
public void onTimerSelected(View view) {
    Log.d(TAG, "onTimerSelected");

    mDelayedView.setPressed(true);

    // Prevent onTimerFinished from being heard.
    mDelayedView.setListener(null);

    // cancel selected, so go back to listview
    Handler handler = new Handler();
    handler.postDelayed(new Runnable() {

        @Override
        public void run() {
            setListViewVisible(true);
        }
    }, 50);
}