In my game i use a surfaceview. There i update my game logic and draw on an ondraw loop.
I want to show a toast like "good catch" but it doesn't show. I think its because its in a loop. Even if i put it in an if block that limit it to show once, it doesn't work.
void onDraw()
{
if(isGood)
Toast.makeText((Activity)getContext(), adMessage, Toast.LENGTH_SHORT).show();
}
Thanks
That code should work if isGood is true.
BTW - you dont need to cast with (Activity)
Related
I am working on my first Android app and I am trying to create a toast and specify the location where I want it to appear. When I was using the code that is now commented (it didn't customize the toast's location) the app ran perfectly on the emulator, but now that I am trying to customize the location and using the code below the comments, the app stops running when I click in the UI on the button meant to show the toast.
Do you have any idea of why this is happening? Because I have seen very similar codes (almost the same) presented as correct, so this should be working. I know this is a very simple code and a simple question, but still, I cannot figure out what is wrong with my code.
This is the code on my onButtonClick:
public void onClick(View V) {
// Toast.makeText(QuizActivity.this,
// R.string.correct_toast,
// Toast.LENGTH_SHORT).show();
Toast t = new Toast(QuizActivity.this);
t.setText(R.string.correct_toast);
t.setDuration(Toast.LENGTH_SHORT);
t.setGravity(Gravity.TOP|Gravity.LEFT,0,0);
t.show();
}
From https://developer.android.com/reference/android/widget/Toast#Toast(android.content.Context) :
Construct an empty Toast object. You must call setView(View) before you can call show().
Your code crashes because now you are using the Toast() constructor. And you need to setView(View) before show(). While this is not necessary with makeText().
As I understand, makeText() creates a View for you setting the text from the second parameter. But the constructor doesn't, and the setText() method does not either. setText() only update the an existing text:
From https://developer.android.com/reference/android/widget/Toast#setText(int) :
Update the text in a Toast that was previously created using one of the makeText() methods.
Here is an example of how to do that:
Custom toast on Android: a simple example
Edit
In any case, you can create the Toast with your initial code, without calling show().
public void onClick(View V) {
Toast t = Toast.makeText(QuizActivity.this,
R.string.correct_toast,
Toast.LENGTH_SHORT);
t.setGravity(Gravity.TOP|Gravity.LEFT,0,0);
t.show();
}
Edit 2
Now you have edited your code, but you are passing the Button View.
mid project here and looking for a quick and dirty way out of a sticky situation.
The game looks like this. To play, click a card, and click another, and if they match they both stay shown. Match all and game is over.
In my case, when I have one card shown, when the user selects the second card, the processing logic, should set the card to be visible AND ONLY THEN, check if there is a match. And if not, return the card back to the old image.
This code, I hope, helps you understand what I'm trying to do.
gridLayout.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
//HOW DO I FORCE THE INTERFACE TO REDRAW BEFORE CONTINUING THE THREAD?
engine.setCardStateToShow(position);
gridLayout.invalidate();
gridLayout.invalidateViews();
try{
Thread.sleep(1000);
}catch (Exception x){
}
//DETERMINE IF THE CARDS MATCH AND IF NOT -- SET CARD INVIS
String message = engine.itemClicked(position, gridLayout);
Toast.makeText(getApplication(), message, Toast.LENGTH_SHORT).show();
//If engine returns a value of WASWINNER, we can end the activity and end the game.
if (message.equals(GameEngine.WASWINNER)) {
startActivity(endActivity);
}
}
});
}
The final result as it stands, is the application changes the image to show, checks for match, if no match changes to not show. And only afterwards, re-draws the interface again with the new values, so to the end user, if there was no match, they never see the "wrong" tile, because it is reverted back to "not show."
Thanks in advance and please correct me if the question could have been asked better.
Okay, I managed to resolve this issue making use of the AsyncTask abstract class. By using AsyncTask, I effectively could "multi thread", separating the comparison logic from the UI logic. As a result, I could manage the UI directly and seperately as shown in the basic explanation below.
By using the onPreExecute() I showed the cards.
BY using doInBackground() I could check and set card show state processing.
By using onPostExecute() I could return the cards to their final view state, directly in the UI thread, based on the results from the DoInBackground() method of the AsyncTask implementation.
Like many others, i've been trying to solve the problem of toast accumulation.
How to prevent Multiple Toast Overlaps
toast issue in android
Cancelling an already open toast in Android
Best way to avoid Toast accumulation in Android
I finally decided to keep track of the current displayed toast and cancel it when another arrives (there's some more logic involved), but i could have use only one toast and change it message. What i want to know is this... Is there a way to TEST this behaviour? Im currently using Robotium and tried different things, but unfortunately the methods to check for toasts (solo.waitForText and solo.searchForText) aren't helping me as i can't make something like
assertTrue(solo.waitForText(text));
//maybe even some sleep here
assertFalse(solo.searchText(text);
Has anyone done something like this? Is there a way to test this using Robotium? using somethig else?
You can use a robotium condition to wait for the text to disappear. Here's a method I use for that.
private void waitForTextToDisappear(final String text, int wait) {
Condition textNotFound = new Condition() {
#Override
public boolean isSatisfied() {
return !solo.searchText(text);
}
};
assertTrue("Text gone: " + text, solo.waitForCondition(textNotFound, wait));
}
I have a view (custom drawn) added with getWindowManager().addView() and later I'm modifiying the LayoutParameters of it (changing x & width) and call getWindowManager().updateViewLayout(). This works but I am getting two screen refreshes, first one only moves the whole thing according to the new x and later one scales it according to the new width. Any ideas about why is this happening even though I only call updateViewLayout just one time with the new layout parameters?
FYI: onDraw method of the custom drawn view mentioned here is also called only one time by the system during this process.
Try:
runOnUiThread(new Runnable() {
public void run() {
view.updateViewLayout();
}
});
http://developer.android.com/reference/android/app/Activity.html#runOnUiThread(java.lang.Runnable)
If it doesn't work, check this:
How to move a view in Android?
Are you doing this?
try to do :
view.post(new Runnable() {
public void run() {
view.updateViewLayout();
}
});
updateViewLayout is an a method that can be overriden by your custom ViewGroup and in this overrided method you can implement all what your want to change.
Maybe you do something wrong in it?
Or also maybe you have to implement this code in UiThread like in other questions. - In this case when you change your parameters asynchronously with first call of drawing function by system you method maybe can change only one parameter and on second call the second parameter will be also changed.
I'm trying to move a ball on canvas. a and b are similar to x,y coordinate positions. Any way from my code im trying to get different values dynamically. The a,b are global variables. But it seems that "invalidate()" or the refreshing of screen only happens afer end of the whole loop. Do you know why?. And if i have to build this on another thread please suggest me with some simple codes.
private void shootBall(){
while (a>b){
a = getPositionX();
b = getPositionY();
invalidate();
}
}
}
I think it's more correct to say that you can call invalidate() from within a loop, but that that invalidation will not be handled (the canvas won't be redrawn) until after your loop is complete. The problem is that you are calling invalidate on the same thread (the UI toolkit thread) as the one that would call your onDraw() method. So unless/until you hand control back to the toolkit, it cannot possibly do the rendering. So your invalidate() call does actually invalidate the view ... but the view won't be redrawn until after your loop completes and your function returns.
It is more correct to change the position in some function that is called via some timer (which is essentially what the animation classes do). In that function, you would change the values, invalidate() appropriately, and return. Then the toolkit re-renders the scene and your function will get future callbacks and update the position accordingly.
do it like this, and use postInvalidate() instead:
private void shootBall(){
new Thread(new Runnable() {
public void run() {
while (a>b){
a = getPositionX();
b = getPositionY();
postInvalidate();
}
}
}).start();
}
edit: but as mentioned before, don't assume that the invalidate redraws the screen, it marks it as to-be-redrawn and the UI thread will get around to it.
You can put invalidate() at the end of onDraw() like in this example: How can I use the animation framework inside the canvas?
However this works well on some devices while bottlenecks and slows down on other.
To use a thread and SurfaceView go through all of these tutorials: http://www.droidnova.com/playing-with-graphics-in-android-part-i,147.html
UI cant be modified form any new thread..you should use invalidate() in the same thread where your view