For implementation of onClick function which approach is better?
Saving touch start / touch up coordinates and processing this values for closeness? Like, if starting point and up point close each other, let the click action start.
Saving touch start / touch up time difference and processing this value? Like, if touch starting time and up time difference less than a value, let the click action start.
And why?
Depends on how many kind of touch events you want to support:
on Up : click
on Up : without moving much - > click , moved -> swipe
on Up : short duration - > click , long duration -> long press has
been triggered, ignore.
on Up and long press triggered : without moving much - > ignore , moved -> drag n drop
You go into details of duration and displacement , when you really need more kinds of touch events.Best approach depends on scenario. So, if your touchscreen doesn't have a notion of swipe or long press or drag n drop, you might just fire a click on every up event, simplest scenario.
If you absolutely must implement your own, I would use the option 2.
if(motionEvent==MotionEvent.ACTION_UP){
long duration = motionEvent.getDownTime() - .getEventTime();
if(duration < THRESHOULD)
click();
}
Related
I have a classic implementation of a recycler view that, when I click on an item inside the recycler view, that item gets deleted.
The problem is that, when I successively click twice one after another (without any noticeable delay between the clicks) on an item in that recycler view, then the second click on that same item is registered at a different position.
The way I identify the item that received the click is by holder.adapterPosition (where holder is an instantiation of ViewHolder class). I wonder if I'm doing wrong by relying on this.
To further troubleshoot, I added the following println statement to troubleshoot:
println("layoutpos ${holder.layoutPosition} adapterpos ${holder.adapterPosition} oldpos ${holder.oldPosition}")
Then, as I repeated those successive clicks, I got the following output in Android Studio's Run tab:
[Galaxy_Nexus_API_22 [emulator-5554]]: I/System.out: layoutpos 1 adapterpos 1 oldpos -1
[Galaxy_Nexus_API_22 [emulator-5554]]: I/System.out: layoutpos 0 adapterpos -1 oldpos -1
Right now, my thoughts are: use adapterPosition, and ignore it when its value is -1 (assume that -1 means a declaration of a racing condition). But I feel that I might be missing something deeper.
How should I handle this situation?
Show the user that the system is refreshing while you're disabling the user from deleting a new object until the previous transaction is completed.
I found two solutions:
if (holder.adapterPosition == -1) return // Race condition; do nothing
// else, do stuff
This does the trick. However, it is not elegant in my view, as: why receive clicking events to begin with if we are not supposed to? It doesn't seem to be solving the problem from its roots.
To solve it more elegantly (from its roots), I did this in the setOnClickListener:
holder.item.setOnClickListener {
// we don't want 2nd click right? so let's delete the listener
holder.item.setOnClickListener{}
/* then, do the stuff for this listener. this stuff
will be done once, as we deleted its listener earlier,
so, subsequent clicks are not possible. */
}
This way, the item with that listener is clicked on once, and a second click does not happen to begin with, hence a racing condition is not possible from its roots. Because the clicking listener is deleted right when the first click is received. Should I want to allow the item to get clicks again, I can redefine a listener for it again.
I have implemented scroll view and I need to detect the visibility of the view when scrolling and trigger that event once per screen initialization.
But, at random times, I get it triggered multiple times in a very short time (a few ms), and it messes up with my logic in VM.
Is there a way to restrict this triggering and make it trigger once every 100ms or something similar?
An easy way to do this is something like this right where the trigger happens
if (System.currentTimeMillis() - lastTime < 100)
return
else {
lastTime = System.currentTimeMillis()
// rest of your code
}
where lastTime is just some variable you keep in your class
I want to create a condition to wait for a broadcast upon a button press
right now I am just doing solo.sleep(10000)
but I dont want to sleep solo for nothing
How do I formulate the condition "broadcast received" ?
Ok explanations
Robotium Solo is an instrumentation framework with nice api
It has a method called "solo.waitForCondition(Condition, int timeout)"
I want to formulate (the word formulate means say what i want to say in correct words)
the correct condition that will tell me that the broadcast was indeed received
I want to write some code (I don't know which exactly) to know that the broadcast was indeed sent
for example, if i want to know that a button is now visible i would write
solo.waitForCondition(new Condition(){
public boolean isSatisfied(){
Button b = getActivity().findViewById(R.id.myButton);
return b.getVisibility() == View.VISIBLE;
}
}
now back to my question - What (not how, but what) do I write in order to know for sure that the broadcast was sent inside the isSatisfied method
I suppose you meant that you don't want to sleep for 10 seconds, if you get the broadcast earlier. What you can do is
long beginTime = new Date().getTime();
while (new Date().getTime() - beginTime < 10000) {
solo.sleep(500);
if (conditionMet) {
// Do something
break;
}
}
This way you can do these checks on smaller intervals.
Ok, so in fact this is more or less how waitForCondition is implemented. Unfortunately I don't think you can listen for events with robotium. What you can do is monitor the view hierarchy. In your case, there should be some difference to the views that is triggered when the button is clicked, so that is what you need to check for in the Condition (and your example does that).
This is if you don't want to edit the code you are testing. If you are willing to change the code, you can add an onClickListener() and in that you can set a view's Tag to a boolean for example. Later in robotium you can check for that tag for being set. This is however not good way to do it, because you are adding more code just for the sake of the tests.
I'm trying to find some kind of elegant solution for fading in/out a TextView that is part of an item in a ListView.
To give you some context, the listview shows a list of players in a basketball game. The user taps on a name and is provided with a dialog to log an event, for example a shot or a foul for that player. Once the dialog is dismissed the user is brought back to the listview and it is here that I'd like to provide some feedback about the event that has just been logged.
The way I'd like to do it is to have a small string appear for about 5 seconds in the view of the item (player) that has just been tapped on. The small string would display something like "3rd foul" or "4 turnovers".
A naive implementation is straightforward. Change the text of the view to the required string and then start an animation that fades in the view, keeps it there for a while and then fades it out. Problems arise however when a second event for the same player is logged shortly after the first. Ideally the first feedback string should be allowed to stay for the allotted 5 seconds and the second string should fade in/out in the next 5 seconds.
This queueing of animation and text changes on a per-player bases I'm not quite sure how to implement. Furthermore, I'm concerned by the interaction between the animations and the Activity's life cycle. What happens (or should happen) to the queued animations when the activity is sent to the background, stopped or even removed from memory? Or when an item is removed from the ArrayAdapter behind the listview?
Thoughts?
Manu
Don't worry about the lifecycle of the activity. There will be no adverse effects. However if the activity goes into the background during the animation, the animation will take place and you will not see it.
As for haveing one animation wait for the next, simply do this:
// here we will keep track of any listView and when the last animation took place.
// The keys will be your listView identifiers. Here I assumed an integer, but use whatever is a good ID for your listView
private HashMap<Integer, Long> listViewLastAnimations;
// the length of the animation in milliseconds
private static long ANIMATION_LENGTH_MS = 5000;
// put this code where you would start your animation
// get when the last event animation occurred
Long lastAnimation = listViewLastAnimations.get(YOUR_LIST_ITEM_IDENTIFIER);
Date new = new Date();
if (lastAnimation == null ||
new.currentTimeMillis () - lastAnimation > ANIMATION_LENGTH_MS ){
listViewLastAnimations.put(YOUR_LIST_ITEM_IDENTIFIER, new.currentTimeMillis ());
// perform animation as normal
}else{
// set a delay to your animation with
long delay = ANIMATION_LENGTH_MS - (new.currentTimeMillis () - lastAnimation);
listViewLastAnimations.put(YOUR_LIST_ITEM_IDENTIFIER, new.currentTimeMillis () + delay);
setStartOffset(delay) ;
}
Can someone please show me a code example about how to get a long click (2 sec for example) on the volume up hardware key?
Thanks :)
EDIT
The class that i want to capture the long click with is a Service. How can i do that?
If you just need to capture long clicks, this answer might be helpful:
https://stackoverflow.com/a/5269673/1401257
EDIT:
I have never tried to have a key listener inside a service, but with a little help from Google I found this: Volume change listener?
It seems that normal key events can only be handled from Activities. I do not have time to try this out myself, but for capturing long clicks it might be possible to combine the answer from the link and Lukes answer.
From what I understand about BroadcastReceivers, you would want to create a receiver, that notify the Service whenever someone click the volume buttons.
Optionally you could do something like this:
if(clickedDown) {
if(beginningTime + 2000 < System.currentTimeMillis()) {
// Ok, the button has been clicked down for 2 seconds
}
}
else {
beginningTime = System.currentTimeMillis();
}
Applying something like this, you'll be able to define the amount of time to wait.