Android UI is not updating before a method starting - java

I'm making a Tic-Tac-Toe game on Android. My game is running well, but I have a problem with it. When user touch on a tile, I update the UI and then call ComputerPlay() method. But the UI only update after ComputerPlay() method is completed. I don't know how, sorry, my English is bad and I don't know how to search the answer.
#Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
if (currentTurn == Constants.HUMAN && board.isEmptyCell(r, c)) {
//update the UI
v.setBackgroundResource(R.drawable.cell_touched);
}
return true;
case MotionEvent.ACTION_UP:
if (currentTurn == Constants.HUMAN && board.isEmptyCell(r, c)) {
//update the tile where user touched
v.setBackgroundResource(R.drawable.cell_normal);
board.makeMove(r, c, currentTurn, options.getHumanPiece());
if (board.checkWinner(currentTurn)) {//if user wins
win++;
tvWin.setText(String.format("Win: %d", win));
tvNotice.setText(R.string.winNotice);
} else if (board.isFull()) { //if draw
draw++;
tvDraw.setText(String.format("Draw: %d", draw));
tvNotice.setText(R.string.drawNotice);
} else {
// computer's turn
currentTurn = Constants.COMPUTER;
ComputerPlay();
}
}
return true;
}
return false;
}
In the code below, when user touches on a tile, I update the UI first and then check for game status. If the game is not end, I call method ComputerPlay(). But the problem is: The UI is really updated after ComputerPlay() method is completed (take more time to search the best move for Computer). I want the UI is updated before ComputerPlay() method starts. How can I do this?

If ComputerPlay() is a long-running method, and you want your UI to update before it is done, you should run ComputerPlay() in an other thread.

Related

Drag a view onLongClick and start activity onClick

I'm banging my head with this problem which probably is simple but since I'm new to this topic I somehow haven't been able to figure it out yet.
I've successfully implemented dragging a view with onTouch method. I've also successfully implemented onLongClick and onClick methods. But both of these functionalities were implemented separately.
The problem, like the title says is when I want to join these functionalities. I want the onTouch method to be called when a user long clicks a view and I want a new activity to start when a user clicks a view.
Here is the pseudo code:
public class Website extends AppCompatActivity implements View.OnTouchListener{
TextView longpress;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_website);
longpress = (TextView) findViewById(R.id.longpress);
longpress.setOnLongClickListener(new View.OnLongClickListener() {
#Override
public boolean onLongClick(View view){
//I don't really know how to do this part
onTouch(View view, Motion Event event);
return true;
}
});
longpress.setOnClickListener(new View.OnClickListener(){
#Override
public void onClick(View v){
//Code for new activity comes here (I know how to do this part)
}
});
}
public boolean onTouch(View view, MotionEvent event) {
switch(event.getAction(){
case MotionEvent.ACTION_DOWN:
//Save initial coordinates of view <-- view.getX(), view.getY()
break;
case MotionEvent.ACTION_MOVE:
//Calculate dX and dY and setX and Y of the view (move view)
break;
case MotionEvent.ACTION_UP:
//If view is certain distance away from initial points do something
break;
}
}
}
Like I said, onTouch works on itself if I don't try to call it from onLongClick method. If I try to call onTouch(View view, MotionEvent event) from onLongClick method the problem occurs because onLongClick only receives one out of two arguments onTouch method should receive (onLongClick only receives view argument but it should also receive event argument).
Maybe I'm trying to do this in a totally wrong way but I have been looking at some documentation e.g. https://developer.android.com/training/gestures/ but still won't get an idea what to do.
(I would like to have a similar functionality to notifications on android phones)
So I've come to a solution which might or might not be a good one but for now it serves my functionality. If someone has a better solution and thinks mine is bad in some way please say so.
Here is the code:
boolean flag;
public boolean onTouch(View view, MotionEvent event){
int action = event.getAction() & MotionEvent.ACTION_MASK;
if(action == MotionEvent.ACTION_DOWN){
//do something on a down press
flag = true;
return true;
}
if(action == MotionEvent.ACTION_UP && flag == true){
//do something if we move finger away from screen we
//didn't move the view first
return true;
}
if(action == MotionEvent.ACTION_UP && flag == false){
//do something if we move finger away from screen and we moved
//the view before we moved the finger away from screen
}
if(action == MotionEvent.ACTION_MOVE){
//do something when moving the view
flag = false;
}

Need a method called after on touch has completed

In our android program we are having trouble getting a method to call at the right time. We have an ontouchlistener and we tried to have it called on release, meaning the other functions would proceed it. However, it appears everything in "ontouch" happens at the same time. How do we get this other method to be called after the others have completed?
#Override
public boolean onTouch(View v, MotionEvent event) {
Tile touchedTile = (Tile) v;
if (touchedTile.isEmpty() || !touchedTile.isInRowOrColumnOf(emptyTile)) {
return false;
}
else {
mediaPlayer.start();
if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
movedTile = touchedTile;
currentMovement = getTilesBetweenEmptyTileAndTile(movedTile);
//movedTile.numberOfMoves = 0;
}
else if (event.getActionMasked() == MotionEvent.ACTION_MOVE) {
if (lastDragPoint != null) {
followFinger(event);
}
lastDragPoint = new PointF(event.getRawX(), event.getRawY());
}
else if (event.getActionMasked() == MotionEvent.ACTION_UP) {
currentMovement = getTilesBetweenEmptyTileAndTile(movedTile);
if (lastDragMovedAtLeastHalfway() || isClicked()) {
animateTilesToEmptySpace();
checkMatch();
}
else {
animateTilesBackToOrigin();
}
currentMovement = null;
lastDragPoint = null;
movedTile = null;
}
return true;
}
}
Why don't you try to extend the view where you're setting the OnTouchListener and override the method onTouchEvent from that view. Call the super, after invoke your own methods, that way you ensure that they will be triggered before the onTouchLister. Let me know if that did the trick.
If you're looking for a complex listener, you should look at MotionEvent, So for MotionEvent.ACTION_UP the doc says:
... A pressed gesture has finished, the motion contains the final release location as well as any intermediate points since the last down or move event....
There is a lot of info about it.
#Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
// I just put my finger on the view
return true;
case MotionEvent.ACTION_MOVE:
// I am moving my finger over the screen
return true;
case MotionEvent.ACTION_UP:
// I have just released my finger from the screen
return true;
default:
return super.onTouchEvent(event);
}
}
EDIT: looks like you're trying to make a jigsaw puzzle app with one empty cell.
Considering you must be using an animator object, u also must have registered an on animate update listener. Shouldn't you put the checkMatch() method inside it so that it gets called whenever the animation ends, since a match will occur only after the user moves tiles?

How to catch the OnTouchEvent just in a particular situation?

I am about to write a little quiz app. I have 4 Buttons which represent the possibilities of answers. When one button is depressed It should blink red or green to indicate right or wrong. So far no problem.
But the next step should be to slide out the old question and to slide in the new one. This should initiate by a touch of the user anywhere on the screen.
How can I achieve this? Which methods I have to use?
Code:
#Override
public void onClick(View v) {
Button button = (Button)findViewById(v.getId());
if(button.getText().equals(quizWorld.getCurrentQuestion().getRightAnswer())){
//right
}else{
//wrong
}
}
#Override
public boolean onTouchEvent(MotionEvent event){
switch(event.getAction()){
case MotionEvent.ACTION_UP:
//Game Over?
if(quizWorld.swapQuestion()==false){
viewFlipper.setDisplayedChild(1);
}
break;
}
return true;
}
Just for Explanation: In the onClick the Programm compares the text on the button with the saved answer and initiate the blinking (not coded yet). And on the onTouchEvent it changes the question.
And now: onTouchEvent should be only "activated" when the Programm has just finished the checking process. After that the Programm shouldn't react on OnEventTouch.
If you don't need to handle the touch event, just return false onTouchEvent and let the touch pass through.
#Override
public boolean onTouchEvent(MotionEvent event){
if (I don't need this touch)
{
return false;
}
switch(event.getAction()){
case MotionEvent.ACTION_UP:
//Game Over?
if(quizWorld.swapQuestion()==false){
viewFlipper.setDisplayedChild(1);
}
break;
}
return true;
}

Why is my onTouchListener called for neighbour views?

In my application I want to add a simple animation to buttons and other views acting as buttons.
To do this I set a custom onTouchListener to all views and call startAnimation on them.
My onTouch method looks like this:
public boolean onTouch(View v, MotionEvent event) {
// Only show animation when enabled.
if (v.isEnabled()) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
v.startAnimation(shrink);
break;
case MotionEvent.ACTION_UP:
v.startAnimation(grow);
break;
}
}
return v.onTouchEvent(event);
}
This works ok as the views are resized to a smaller size while the user presses the button and returns to the original size when the user releases the finger.
However for some reason other buttons that lie near the touched button also get the UP event so they get a small animation flicker as well.
Why is this, and more importantly, how do I prevent this annoying behaviour?
Edit: Just to be clear. The neighbour views are also registered to the same listener instance, but they are not touched by my finger.
The view to wich you have registered listener then should only get notified then also use following approach.
You can explicitly check what is id of View and then only start animation.
public boolean onTouch(View v, MotionEvent event) {
if (v.getId() == R.id.desired_view_id) {
// Only show animation when enabled.
if (v.isEnabled()) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
v.startAnimation(shrink);
break;
case MotionEvent.ACTION_UP:
v.startAnimation(grow);
break;
}
}
}
return v.onTouchEvent(event);
}
The problem was using the same Animation instance on several views. Creating seperate instances for each view fixed the problem.

OnTouchListener() will only execute once while button is pressed and held down

brown = (Button) findViewById(R.id.brownButton);
brown.setOnTouchListener(new OnTouchListener() {
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
count++;
Log.d("count", "" + count);
return true;
} else if (event.getAction() == (MotionEvent.ACTION_UP)) {
count--;
Log.d("count", "" + count);
return true;
}
return false;
}
});
When my finger presses and holds the button my count will only increment ONCE. When I let go it will decrement accordingly. Please can someone show me how I can get my code to increment as long as my finger is holding the button down. Thanks.
A touch listener works like this:
It receives a ACTION_DOWN event (the user touches)
It then receives all the following events (if true is returned) and treats all the following events as ACTION_MOVE events
The touch lisetener keeps receiving ACTION_MOVE events until it receives an ACTION_UP or ACTION_CANCEL event.
So ACTION_DOWN is only triggered once, then any number of ACTION_MOVE events, then either a single ACTION_UP or ACTION_CANCEL.
If you want your counter to increment you need to check for ACTION_MOVE events.
#Override
public boolean onTouch(View v, MotionEvent event) {
switch(event.getAction()){
case MotionEvent.ACTION_DOWN:
//do something on DOWN
break;
case MotionEvent.ACTION_MOVE:
//do something on MOVE
break;
case MotionEvent.ACTION_UP:
//do something on UP
break;
}
return true;
}
I also needed to do this, but this question was never adequately answered, even though it is fairly old. However, a good solution can be found here: android repeat action on pressing and holding a button
I am adapting that solution to this problem. I tested it and it works for me.
Button brown = (Button) findViewById(R.id.brownButton);
brown.setOnTouchListener(new View.OnTouchListener() {
private Handler mHandler;
private int count = 0;
#Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
if (mHandler != null)
return true;
mHandler = new Handler();
mHandler.postDelayed(mAction, 500);
break;
case MotionEvent.ACTION_UP:
if (mHandler == null)
return true;
mHandler.removeCallbacks(mAction);
mHandler = null;
break;
}
return true; // before I had written false
}
Runnable mAction = new Runnable() {
#Override
public void run() {
Log.d("count: ", "" + count);
count++;
mHandler.postDelayed(this, 500);
}
};
});
In the future I will apply this solution to a custom soft keyboard to allow the space and delete keys to continue working when being held down.
Update: Today I finally got around to making the continuous delete key. I thought I had tested my above code before, but today when I was doing it I had to return true from the onTouch method in order to get it to work.

Categories