I am making an app where when you hold a button, a textview with numbers increases (until you let go).
I tried using the OnTouch, but that doesn't increase the number unless you move your finger in the button. I tried looking at some answered questions here in stackoverflow and implementing the solutions suggested, but it seems to just crash now...
The ontouch listener:
upb.setOnTouchListener(new View.OnTouchListener(){
#Override
public boolean onTouch(View v, MotionEvent event) {
// TODO Auto-generated method stub
/* Button pressed */
if(event.getAction() == MotionEvent.ACTION_DOWN){
startIncreasing();
}
if(event.getAction() == MotionEvent.ACTION_UP){
stopIncreasing();
}
return true;
}
private void startIncreasing(){
setIsIncreasing(true);
new Thread(new Runnable() {
public void run() {
while(isIncreasing()){
if(speed<12){ //max speed determined here
speed++;
speedtext.setText(speed + " km/h");
downb.setEnabled(true);
homeb.setEnabled(false);
revb.setEnabled(false);
//send signal to speed up
}
else {
speedtext.setText("MAX " + speed + " km/h");
upb.setEnabled(false);
}
}
}
}).start();
}
});
Later on in the code:
synchronized private void stopIncreasing(){
setIsIncreasing(false);
}
synchronized private boolean isIncreasing(){
return continueIncreasing;
}
synchronized void setIsIncreasing(boolean newSetting){
continueIncreasing = newSetting;
}
Anybody that can spot what I am doing wrong? Or should I do this in a completely different way?
Thank you for your help
Without seeing logs, I believe your app crashes since you're updating the TextView from a background thread (in speedtext.setText(speed + " km/h");).
Updating UI elements must be done from the UI thread (main).
You can use the runOnUiThread() method for doing such updates from the UI thread.
Related
I have several buttons I want to make INVISIBLE for a short while then make them VISIBLE again. The (View.INVISIBLE) before Timer.sleep() does not work. I have yet to figure this out. Any ideas?
Thanks, Steve
private void commonBtnHandler(Button btn) {
try {
btn.setVisibility(View.INVISIBLE);
Thread.sleep(250);
btn.setVisibility(View.VISIBLE);
} catch (Exception e) {
e.printStackTrace();
}
}
You should not do Thread.sleep() on the UI/main thread. It will cause the UI to freeze & ANR
Try :
btn.setVisibility(View.INVISIBLE);
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
btn.setVisibility(View.VISIBLE);
}
}, 250);
Also 250 ms is a very small amount of time.
btn.setVisibility(View.INVISIBLE);
new Thread() {
public void run() {
try {
runOnUiThread(new Runnable() {
#Override
public void run() {
btn.setVisibility(View.VISIBLE);
}
});
Thread.sleep(250);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}.start();
always put the runOnUiThread when need to change the UI in runtime, This is helps to you.
Thanks for all the input.
I tried all the suggestions with a 3000 millisecond delay but still did not see a blink.
Also, I was wondering if I was blocking the UI thread. I thought the INVISIBLE would complete before the sleep() took effect.
Summary: I wrote a loop to make the call 10 times. The delay seems to be ignored in all cases. I appreciate everyone’s help. It looks like I need to rethink how this should work. I wouldn’t think this would be much different than how a game programmer would insure synchronous operations.
Addressing this issue in another way I did not INVISIBLE the button but temporarily changed the color using MotionEvent within a setOnTouchListener. When pressed the button changes color and when released reverts back to the original color. Works great!
mBtn.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
switch ( event.getAction() ) {
case MotionEvent.ACTION_DOWN:
mBtn.setBackgroundColor(getResources().getColor(R.color.colorLightOrange));
break;
case MotionEvent.ACTION_UP:
mBtn.setBackgroundColor(getResources().getColor(R.color.colorOrange));
break;
}
return true;
}
});
I want to make a program which will tell me the number of seconds I kept holding the button.
for example if I clicked the button for 5 seconds, it should tell me the button remained pressed for 5 seconds.
is this achievable in android?
This is how I tried, didn't work because when I put the while loop in, the button stays clicked even I press it for just one second. The program doesn't crash but the button remains clicked and I think it freezes.
thread = new HandlerThread("");
btn.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View arg0) {
// TODO Auto-generated method stub
while(btn.isPressed())
{
try {
thread.sleep(1000);
total = total++;
temp = temp++;
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
Toast.makeText(MainActivity.this, ""+temp+" "+total, 0).show();
}
});
You could use time stamps, and an OnTouchListener to achieve this.
When your OnTouchListener receives an ACTION_DOWN event, store the first time stamp. When it receives an ACTION_UP event, store the second time stamp and calculate the difference between the two.
As mentioned by Raghunandan, you should never block on the UI thread using calls such as thread.sleep, as this will cause the UI to stop responding, and in some cases can cause the program to be killed because of this.
Here is an example of what I've outlined above. Please note, this code was written from memory, and has not been tested, but you should get the general gist of it.
btn.setOnTouchListener(new OnTouchListener() {
private long firstTouchTS = 0;
#Override
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction()==MotionEvent.ACTION_DOWN) {
this.firstTouchTS = System.currentTimeMillis();
} else if (event.getaction()==MotionEvent.ACTION_UP) {
Toast.makeText(MainActivity.this,((System.currentTimeMillis()-this.firstTouchTS)/1000)+" seconds",0).show();
}
}
});
References: OnTouchListener MotionEvent
thread.sleep(1000);
Calling sleep on the ui thread hence it freezes. Do not call sleep on the ui thread. It blocks the ui thread.
Read
http://developer.android.com/training/articles/perf-anr.html.
Use a Handler if you want to repeat some task
I have an app where I need to have a delay after each touch in an ImageButton.
I tried the Thread.sleep() method, but I am not sure if this is the best way to deal with it.
What do you guys recommend?
Any help is appreciatted!
ONE MORE THING: I want the content of the onTouch() event to be fired THEN I want to delay "X" seconds the next onTouch() event. It's like to prevent the user to click too many times in the button.
Since all touch events are handled by UI thread, Thread.sleep() will block your UI thread which is (I hope) not what you are looking for.
I think the most correct way to solve your problem would be using postDelayed(Runnable, long) interface in your onClick handler which allows your to delay execution:
#Override
public void onClick(View v)
{
postDelayed(new Runnable()
{
#Override
public void run()
{
// do your stuff here
}
}, 10000); //10sec delay
}
UPDATE:
If you want user to prevent clicking too fast on your image view, I strongly recommend go with onClick rather than onTouch (unless there are serious reasons for that)
However, please see the code snippet which might help you:
private boolean blocked = false;
private Handler handler = new Handler();
#Override
public boolean onTouchEvent(MotionEvent event)
{
if (event.getAction() == MotionEvent.ACTION_DOWN)
{
if (!blocked)
{
blocked = true;
handler.postDelayed(new Runnable()
{
#Override
public void run()
{
blocked = false;
}
}, 1000);
} else
{
return false;
}
}
return super.onTouchEvent(event);
}
Could you please tell me how to capture the end of panning of MapView? At the beginning, I thought I could use the MotionEvent.ACTION_UP. However, when my touch is moved fast, the panning animation is still in progress while the ACTION_UP event is already fired before.
I had to come up with a solution to this problem also. It appears there is not a method in the android SDK to handle this event. What I did was create a timer that runs every 200ms and checks to see if the centerpoint of the mapview has changed. If it has and the a flag is set. The timer method knows when the panning has stopped when the centerpoint is no longer changing(oldMapCenter==newMapCenter). It may not be the best solution, but it is working for me. Insert the code below in your MapActivity.
NOTE: This will not update the view WHILE the user is panning, only AFTER.
GeoPoint newMapCenter,oldMapCenter;
int newZoomLevel=0,oldZoomLevel=0;
Boolean isMoving=false;
#Override
public void onResume() {
super.onResume();
autoUpdate = new Timer();
autoUpdate.schedule(new TimerTask() {
#Override
public void run() {
((Activity) getActivity()).runOnUiThread(new Runnable() {
public void run() {
if(oldMapCenter==null){
oldMapCenter=mapView.getMapCenter();
}else{
newMapCenter=mapView.getMapCenter();
if(!geoPointsAreSame(newMapCenter,oldMapCenter)&& (!isMoving)){
isMoving=true;
}else{
if(geoPointsAreSame(newMapCenter,oldMapCenter)&&(isMoving)){
//Insert update overlay code here
isMoving=false;
}
}
oldMapCenter=newMapCenter;
}
newZoomLevel=mapView.getZoomLevel();
if(oldZoomLevel==0){
oldZoomLevel=mapView.getZoomLevel();
}else{
if(oldZoomLevel!=newZoomLevel){
//insert update overlay code here
}
}
oldZoomLevel=mapView.getZoomLevel();
}
}
private boolean geoPointsAreSame(GeoPoint newMapCenter,
GeoPoint oldMapCenter) {
if(newMapCenter.getLatitudeE6()==oldMapCenter.getLatitudeE6()){
if(newMapCenter.getLongitudeE6()==oldMapCenter.getLongitudeE6()){
return true;
}
}
return false;
}
});
}
}, 3000, 200); // updates each 200 millisecs`-
I am building a 2D game with Android SurfaceView. When I touch the screen the game animation runs slowly. Why, and how can I avoid this?
The touch events are stubs just like onTouchEvents(MotionEvents ev){ empty };. All of the game logic and graphics draw code are in run() in an extends Thread class.
Sleeping the UI thread for 16-20ms will keep the touch event handling code from being called too many times per second.
Example:
#Override
public boolean onTouchEvent(MotionEvent event) {
//Event handling logic
try {
Thread.sleep(16);
} catch (InterruptedException e) {
e.printStackTrace();
}
return true;
}
Touch events are dispatched as quickly as the UI thread can read them, by sleeping the thread you are able to skip a number of event dispatches. (Though not a noticeable amount for your game logic or the user)
Have you looked at the tutorials at http://www.droidnova.com ? They are good intro game tuts and ran very quickly when I did them. If they run slowly on your device with touch it is probably not a dev issue
#Override
public void run ( )
{
while(irunning)
{
while(paused)
{
sleep(2);
synchronized ( holder )
{
canvas = holder.lockCanvas(null);
//updateEvents();
//updatePsgstate();
//updateRole();
sortImages();
drawBgland();
drawImages();
drawAdminicle();
holder.unlockCanvasAndPost(canvas);
}
}
sleep(10);
}
}
#Override
public boolean dispatchTouchEvent ( MotionEvent ev )
{
try
{
Thread.sleep( 32 );
}
catch ( InterruptedException e )
{
e.printStackTrace();
}
synchronized ( ev )
{
Log.i( "T" , "onTouch" );
}
return true;
}
#Override
public void surfaceCreated(SurfaceHolder holder)
{
mThread.start();
// if (hasFocus())
// {
// return;
// }
// else
// {
// requestFocusFromTouch();
// }
}
this is base method that i used.
that's my code. any problem about it ?