I try to use this code to prevent multi-click in ImageView but it doesn't help.
Boolean isClicked = false;
#Override
public void onClick(View v)
{
if (v == imgClick && !isClicked)
{
//lock the image
isClicked = true;
Log.d(TAG, "button click");
try
{
//I try to do some thing and then release the image view
Thread.sleep(2000);
} catch (InterruptedException e)
{
e.printStackTrace();
}
isClicked = false;
}
}
In the log cat, I can see 5 lines "button click" when I click on ImageView for 5 times as quickly as possible. I can see the log cat print the first line, wait for a while (2 seconds) and then print the next line. I think when I click the ImageView, the fired event is moved to queue in order, isn't it?. So how can I stop that?
I also try to use setEnable() or setClickable() instead of isClicked variable but it doesn't work too.
Just try this working code
Boolean canClick = true; //make global variable
Handler myHandler = new Handler();
#Override
public void onClick(View v)
{
if (canClick)
{
canClick= false; //lock the image
myHandler.postDelayed(mMyRunnable, 2000);
//perform your action here
}
}
/* give some delay..*/
private Runnable mMyRunnable = new Runnable()
{
#Override
public void run()
{
canClick = true;
myHandler.removeMessages(0);
}
};
Instead of sleeping in 2 seconds, I use some task like doSomeThing() method (has accessed UI thread), and I don't know when it completed. So how can I try your way?
//I referred this android link. You can handle thread more efficiently but i hope below code will work for you..
//you try this and
Boolean canClick = true; //make global variable
public void onClick(View v) {
if(canClick){
new DownloadImageTask().execute();
}
}
private class DownloadImageTask extends AsyncTask<String, Void, Bitmap> {
protected Bitmap doInBackground(String... urls) {
Log.d("MSG","Clicked");
canClick =false;
//perform your long operation here
return null;
}
protected void onPostExecute(Bitmap result) {
canClick =true;
}
}
You could keep track of the last consumed click upon your View, and based on it either perform the necessary actions, or simply return:
private long calcTime;
private boolean isClickedLately(final long millisToWait)
{
if (System.currentTimeMillis() - calcTime < millisToWait)
return true;
return false;
}
#Override
public void onClick(View v)
{
if (isClickedLately(2000))
return;
calcTime = System.currentTimeMillis();
Log.d(TAG, "consuming button click");
// perform the necessary actions
}
With the millisToWait parameter you can adjust the threshold of "waiting", but if you know that you want to wait exactly 2 seconds between two consecutive clicks, you can eliminate it.
This way you don't have to deal with Threads, which is good, since it's not a great idea to make the gui thread wait.
Related
i am trying to make a button that when its clicked , it changes its color image and starts a countdowntimer in a method activeDelay() as here:
piscaAutoButton = (Button) rootView.findViewById(R.id.piscaAutoButton);
piscaAutoButton.setOnClickListener(new Button.OnClickListener() {
#Override
public void onClick(final View view) {
if (sessionManager.getPisca()) {
sessionManager.setPisca(false);
trigger = false;
piscaAutoButton.setBackgroundResource(R.drawable.button_bg_round);
} else {
sessionManager.setPisca(true);
piscaAutoButton.setBackgroundResource(R.drawable.button_add_round);
trigger = true;
activeDelay(trigger);
}
here is my activeDelay method:
private boolean activeDelay(boolean trigger) {
while (trigger) { // LOOP WHILE BUTTON IS TRUE CLICKED
int timerDelay = manualControl.getDelayPisca(); //input for timer
//delay manual
new CountDownTimer(timerDelay * 1000, 1000) {
public void onFinish() {
System.out.println("sent");
try {
System.out.println("blink button " + manualControl.getBlinkButton());
if (!manualControl.getBlinkButton().isEmpty()) {
MenuActivity.mOut.write(manualControl.getBlinkButton().getBytes());
}
} catch (IOException e) {
e.printStackTrace();
}
}
public void onTick(long millisUntilFinished) {
}
}.start();
}
return trigger;
}
My problem is that i need the counter keeps going after finished, stopping just when the user clicks again in the button (trigger = false). I am having problems to program that, if someone could help,i know the return inside activeDelay ejects from the method, how can we solve that ,tks
I would suggest you to don't use CountDownTimer(this runs for some specific time period) , instead of this you should use Handler(this run infinitely) . i am sending you handler code.
private Handler handler = new Handler();
//call this when you want to start the timer .
handler.postDelayed(runnable, startTime);
Runnable runnable = new Runnable() {
#Override
public void run() {
// Do here , whatever you want to do(show updated time e.t.c.) .
handler.postDelayed(this, xyz); //xyz is time interval(in your case it is 1000)
}
};
//Stop handler when you want(In your case , when user click the button)
handler.removeCallbacks(runnable);
I have tried so many ways of solving my problem, but still no success.I have a method, which returns me a string value and I am using it to update TextView on my screen like this:
outCPU.setText(getCpuInfo());
Which would be fine, but I need to update this TextView until back button was pressed.
I guess i have need a while loop which starts after activity has been created and stops after back button was pressed. This loop should be in a new thread, because:- I have to load the activity first and execute the loop in another thread so the executing won't affect main thread and loading of the activity.
As I've already said, I don't know how to do this properly even though i have spent few hours on it.
Could someone show me an example how to get this done? Thanks...!!
EDITED - WORKING:
private Handler mHandler;
private int i;
#Override
protected void onCreate(Bundle savedInstanceState) {
setContentView(R.layout.activity_systeminfo);
outCPU = (TextView) findViewById(R.id.outCPU);
outMEM = (TextView) findViewById(R.id.outMEM);
outTASKS = (TextView) findViewById(R.id.outTASKS);
i = 0;
mHandler = new Handler();
mHandler.post(mUpdate);
}
private Runnable mUpdate = new Runnable() {
#Override
public void run() {
outCPU.setText(getCpuInfo());
outMEM.setText(getMemInfo());
outTASKS.setText(getTasksInfo());
i++;
mHandler.postDelayed(this, 1000);
}
};
#Override
public void onBackPressed() {
mHandler.removeCallbacks(mUpdate);
super.onBackPressed();
Log.i("MSG", "Going back");
finish();
}
You can use AsyncTask to perform operations on UI Thread while being in a Thread. Or you can use 'my favorite' , the combination of Thread and Handler. To make sure the thread is stopped when back is pressed, you can use handler.removeCallBacks(Runnable) The following example could solve your problem:
//Global
Handler h = new Handler();
private static boolean flag = true;
public void updateTextView(){
// call thread here
h.post(thread);
}
// take this thread out side so that it can be stopped with handler
Thread thread = new Thread(){
public void run(){
while(flag)
outCPU.setText(getCpuInfo());
}
}
public void onBackPressed(){
flag = false;
h.removeCallBacks(thread);
super.onBackPressed();
}
Use a shared flag somewhere in your app:
private volatile boolean wasPressed = false;
In while loop, check this flag:
while (!wasPressed) {
runOnUiThread(new Runnable() {
#Override
public void run() {
outCPU.setText(getCpuInfo());
}
});
// sleep for a while
}
On button click listener, switch wasPressed to true.
I've tried a hundred different methods to implement a delay between automated button clicks, including thread.sleep, Handler.postDelayed, and so on… It could be I have used it incorrectly somehow. My most recent attempt was with a simple boolean toggle. It seems that no matter how I try, all the buttons that are to be automatically clicked happen at the same time after the delay, INSTEAD of being delayed between clicks.
my code as it stands now:
setting up button onClickListener:
for (int i = 0; i < mDifficulty; i++) {
ButtonsOCLArray[i].setOnClickListener(new OnClickListener() {
public void onClick(final View v) {
animating = true;
while (animating) {
animateButtons(v);
}
}
});
}
animation of buttons:
public static void animateButtons(View v) {
AlphaAnimation fadeInAnimation = new AlphaAnimation(0F, 1F);
fadeInAnimation.setDuration(1500);
fadeInAnimation.setFillAfter(true);
v.startAnimation(fadeInAnimation);
animating = false;
}
and finally, from a separate class, the automatic button setup:
public void pushAiButton(final View [] v){
mWhichButton = (mGameAi.getRandomNumber(MainActivity.mDifficulty)); // get random number for random button to press
mListOfAiButtonsToPress.add(mWhichButton); // add random number to mLOABTP
mListOfAiButtonsTemp.addAll(mListOfAiButtonsToPress); // add all elements of mLOABTP to mLOABT
boolean empty = false;
while (!empty) {
if (empty) {
break;
}
tempArrayIndex = mListOfAiButtonsTemp.get(0); // tempArray given value in first slot of mLOABT
mListOfAiButtonsTemp.remove(mListOfAiButtonsTemp.get(0)); // first slot of MLOABT removed
if (mListOfAiButtonsTemp.isEmpty()) {
// looped through whole list, empty now
empty = true;
} // end if
v[tempArrayIndex].performClick(); // click button at index *button*[*index*]
} // end !empty while
} // end pushAiButton()
any ideas HIGHLY appreciated! thanks!
UPDATE
This got it working:
mButtonStart.setOnClickListener(new OnClickListener() {
#Override
public void onClick(final View v) {
Log.d(TAG, "START BUTTON CLICKED!");
if (firstRun) {
mGameAi.setupAiButtons();
firstRun = false;
}
v.setVisibility(View.INVISIBLE);
animateButtons(ButtonsOCLArray[mGameAi.getFirstButtonInList()]);
mGameAi.deleteFirstButtonInList();
v.postDelayed(new Runnable() {
public void run() {
if (!mGameAi.buttonsListIsEmpty()) {
v.performClick();
}
else {
v.setVisibility(View.VISIBLE);
firstRun = true;
}
}
}, 500);
System.out.println("end of mButtonStart's onclicklistener");
}
});
You have coded it so that they all click nearly simultaneously. The automatic button setup does a "while" loop that iterates through all the buttons - removing them one at a time nearly simultaneously.
In other words, your while loop iterating through the buttons needs to pause (or not queue another click) until the animation is complete.
Here is the problem said another way; when each "onClick" occurs, the boolean "animateButtons" is true and they all enter into the animateButtons method.
You need to have a thread with a wait call on in pushAiButton and wait for each button to finish its animation.
public class TestingActivity extends Activity implements View.OnClickListener
{
ScheduledThreadPoolExecutor scheduler = new ScheduledThreadPoolExecutor(1);
ScheduledFuture now = null;
public void onCreate(Bundle savedInstanceState)
{
//oncreate
}
public void rollthedice()
{
//rollthedice
}
public void onClick(View view)
{
Runnable runner = new Runnable()
{
public void run()
{
rollthedice();
}
};
if(view.equals(continuous))
{
if(now == null)
now = scheduler.scheduleAtFixedRate(runner, 0, 250, TimeUnit.MILLISECONDS);
else
return;
}
if(view.equals(stop))
{
if(now != null)
{
now.cancel(true);
now = null;
}
else
return;
}
if(view.equals(roll))
rollthedice();
if(view.equals(exit))
System.exit(0);
}
I used it in a Java application and it worked fine, i put it into android project and it doesnt work i want the continuous button to run rollthedice() continuously and the stop button to stop it then continuous to start it again and stop back and forth
Are you sure the onCLick is executed?
Did you call
continuous.setOnClickListener(this);
stop.setOnClickListener(this);
etc?
Because you need to add it some while loop with a flag, try this:
public void run()
{
while (runningFlag){
//do something here
}
}
At the start you need to set the flag to true and then start the thread, and when you want it to stop set the flag to false.
You can have a while loop and set the condition to true to stop it (because of the !). You should also highly consider having the rolling in a separate thread. If you do you may or may not need a handler.
boolean mPaused = false;
while(!mPaused) {
doSomething();
}
//to stop it set mPaused = true
//to resume call the method again
Handler
//called by
Message msg0 = new Message();
msg0.obj = "someting";
handler.sendMessage(msg0);
private Handler handler = new Handler() {
#Override
public void handleMessage(Message msg) {
if (msg.obj.equals("something")) {
doSomething();
}
}
};
I've written a AsyncTask:
public class AudioTransition extends AsyncTask <Void, Void, MediaPlayer>
{
private int goalID;
private int milliseconds;
private MediaPlayer tempPlayer;
AudioTransition(int ID, int Milliseconds)
{
goalID = ID;
milliseconds = (int)(((float)Milliseconds)/100);
}
#Override
protected void onPreExecute()
{
tempPlayer = MediaPlayer.create(context, goalID);
tempPlayer.setVolume(0, 0);
tempPlayer.setLooping(true);
tempPlayer.start();
}
#Override
protected MediaPlayer doInBackground(Void... arg0) {
for (int i = 0; i < 100; i++)
{
value = i;
publishProgress();
try {
Thread.sleep(milliseconds);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if (!player.isPlaying())
tempPlayer.pause();
}
return tempPlayer;
}
#Override
protected void onProgressUpdate(Void... v) {
super.onProgressUpdate(v);
player.setVolume(100-value, 100-value);
tempPlayer.setVolume(value, value);
}
#Override
protected void onPostExecute( MediaPlayer result ) {
super.onPostExecute(result);
player.reset();
player = tempPlayer;
player.setVolume(100,100);
transitioning = false;
}
}
But the volume doesn't fade out. It just starts both tracks, then stops. The MediaPlayers are not updated until doInBackground completes. How can I make the MediaPlayers get updated within this type of background worker? It seems like the publishProgress() thing should work.
Oh lord. Dont be sleeping threads inside of AsyncTask! You are completely misusing AsyncTask. You couldn't think of another way to do a timer type thing, so you're latching onto the idea of publishprogress from AsyncTask (which doesn't even work how I think you think it works) even though AsyncTask should be used for one thing and one thing only: doing heavy work off of the main (UI) thread.
If you just wanted to fade the volume out then use something like this: (this goes somewhere outside of any method).
private Runnable VolumeFadeRunnable = new Runnable() {
#Override
public void run() {
volume--;
player.setVolume(volume, volume);
if(volume>0)
handler.postDelayed(this, 1000);
else
handler.removeCallbacks(this);
}
};
just initialize your handler as a field inside of onCreate or whatever and make sure that and the counter variable are visible inside of that runnable.