In this very simple code example, messages get lost every once in a while. What is wrong here?
public class AndroidTesterActivity extends Activity {
private static final int END = 500000;
private static int i = 0;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
i=0;
}
#Override
public void onResume()
{
super.onResume();
while(i < END)
{
Log.d("x", ""+i++);
}
Log.e("x", "END");
}
}
For example i get two consecutive log messages 139371 and 140001 ... so 630 messages are simply lost, even though i is counted up? How can i be counted without the Log being written?
I have already searched, if someone else already had the same problem, but didn't find anything.
Thanks for any help
Just a uneducated guess: The Log class doesn't push everything directly, I think it collects and pushes under some specific conditions. As your loop should go very fast, it might be that in some conditions the log buffer (or what else) might be overwritten before it was flushed.
I would try to make it in a thread and call sleep() with some ms in between. Maybe you can reproduce this or find a value where this behavior disappears.
Related
Experts,
I have a very long code inside onCrate() in a activity. At the beginning of the long code, I need to judge if the net is bad, if yes, return and skip the remaining code.
I understand I cannot judge the net in UI thread, so I need to use AsyncTask, or Handler&Runnable.
But all tutorial I learned is get the net bad or ok status in a new thread and pass to onPostExecute(AsyncTask) or handleMessage(Handler), then update UI or do something in onPostExecute(AsyncTask) or handleMessage(Handler), for they are in UI thread.
Above is not what I need, what I need is bring the net bad or ok info to onCreate() method, so I can know if I should continue run the remaining code inside onCreate() or not.
(Note that before onCreate() got net info from new thread(takes time), need to avoid execute the remaining code)
But I don't know how to do? Could you help please? Thanks in advance.
(Also if I need to pass param inside onCreate() to the new Runnable, how to do?)
My code:
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if net is bad then return;
// more than 1 thousand other codes...
}
}
Handler example:
public class MainActivity extends Activity {
Handler handler = new Handler() {
#Override
public void handleMessage(Message msg) {
switch (msg.num) {
case 1: show net is ok in a UI textview
case 2: show net is bad
(but how to pass the msg.num to inside onCreate()?)
}
}
};
Runnable newTread = new Runnable() {
#Override
public void run() {
// judge net statements
msg.obj = num;
handler.sendMessage(msg);
}
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
}
I have to say, I personal think my question is typical and useful practice, yet no answer.
I also believe I post my question clear enough.
After a few days' study, I found Callable interface should be the right answer, I can define a boolean return value to speak for the net status, also the get() method guarantee thread-safe.
However, I search the whole google and android APIs, cannot find a Callable example for android.
Really cannot understand why this question treated coldly...
I send a request to server via Volley; And after send, increase a variable that show number of requests.
VolleyGeneral.getInstance().addToRequestQueue(jsonObj,TAG);
numberOfReq++;
Then when I get the response, decrease that variable.
#Override
public void onResponse(JSONObject response){
numberOfReq--;
}
On another side, i'm showing an image, using fade in animation for 2 seconds then I finish the activity and go to the next activity.
But i want to wait for all the server responses before finishing the activity. So i write this part like it:
#Override
public void onAnimationEnd(Animation anim){
while(numberOfReq == 0){
numberOfReq = -1;
startActivity(intent);
finish();
break;
}
}
If server send the responses before 2 second, everything is Okey.
But if response is received after 2 second, the activity doesn't finish.
Maybe I'm not understanding the question, because the answer seems incredibly simple. Just set a flag whenever the activity is "ready to finish", and then check for this condition in onResponse() too.
Either onAnimationEnd() or the last onResponse() will run first, and the second one should start the second activity. For example:
private boolean mReadyToProceed;
#Override
public void onAnimationEnd(Animation anim)
{
if (numberOfReq == 0)
startOtherActivityAndFinish();
else
mReadyToProceed = true;
}
#Override
public void onResponse(JSONObject response)
{
numberOfReq--;
if (mReadyToProceed && numberOfReq == 0)
startOtherActivityAndFinish();
}
(Note: make sure that the decrement and comparison is not affected by other request threads finishing, possibly with locks or by using AtomicInteger).
You are aware of the fact that Volley creates and maintains multiple threads, right?
Increments/decrements are not thread safe operations. Instead use something like:
AtomicInteger numberOfReq = new AtomicInteger(0);
numberOfReq.incrementAndGet(); // ++
numberOfReq.decrementAndGet(); // --
Not sure this is the cause of your problem, but event if not - it's a bug waiting to happen.
EDIT:
Setting numberOfReq to be a volatile int will not solve the problem.
Volatile does not guarantee atomicity. it only guarantees that the next
thread to read a variable will see its exact value after operations performed
by a prior thread.
Now, increment (and decrement) operation is in fact a triplet:
a = x;
b = a + 1;
x = b;
If atomicity is not forced on this calculation, e.g. by using AtomicInteger,
nothing will stop another thread visiting even a volatile field in the middle of such calculation and basically do away with the increment-in-process.
As matiash answered you can use set a flag on the onResponse() and can check that value to get the desired result or you can use the broadcast recievers that can be an effective solution also
Why not make the check two way instead of one i.e
If the response arrives whilst you're animating then your onAnimationEnd() must be responsible for shutting down and starting the new activity
Else the otherway round(the image animation ends before the response) onResponse() must be responsible for performing activity finish and new activity.
Ps: Regarding thread safe variables #matiash seems to have thrown enough light
You should separate the method where you start the other activity. Something like this:
private boolean animationEnded = false;
#Override
public void onResponse(JSONObject response){
numberOfReq--;
checkStartOtherActivity();
}
#Override
public void onAnimationEnd(Animation anim){
animationEnded = true;
checkStartOtherActivity();
}
public void checkStartOtherActivity(){
if (numberOfReq == 0 && animationEnded){
startActivity(intent);
finish();
}
}
I have spent a lot of hours trying to reproduce and understand the cause of this problem, with no success in either of these goals.
I have tried to leave only the code related to the problem, but I believe a few minutes are still necessary to understand the problem and context. I hope that someone will be able to spot the problem in my implementation or at least help me understand the cause.
Description of the application:
Word game where you play against the computer. After the computer has laid a word on the board, the definition of this word is fetched online in an AsyncTask and displayed in a TextView
How I discovered the issue:
I use ACRA for crash and error reporting (great free tool by the way). It sends me reports for each unexpected situtation (this one does not lead to a crash). I have been receiving many reports of errors 1,2,3 and 4 (see code)
Some bad reviews on Google Play tend to show that some users do not see the definition even though they are connected to Internet. (I am pretty sure this functional bug is related to the previously mentioned errors, though I cannot prove it)
A word on the code design:
After reading a lot on memory leaks in Android, I have decided to make the AsyncTask that retrieves the definition online a static inner class (even though my main activty currently does not support rotations, which are the main causes of leaks: I put in my Manifest android:screenOrientation="portrait").
I need access to the parent Activity from this AsyncTask because I retrieve strings from the resources, and perform some changes on the UI in onPostExecute().
Hence, I use a WeakReference in the AsyncTask which is pointing to the parent Activity. This should prevent memory leaks in case the Activity is recreated or killed while theAsyncTask` is still running.
What exactly is the problem:
The WeakReference or the return of its get() method is null in
some unexplained situations (I suspect it impacts more than 1% of the games or
players) (see code)
All kinds of devices and Android versions are impacted, and I often see several occurences coming from the same device)
I have never been able to reproduce these errors (the most obvious try was exiting the activity while the definition is being downloaded, but this didn't cause any error)
Meaningful parts of my code:
public class GameActivity extends Activity {
private TextView _definition; //inflated from XML in onCreate()
private ProgressDialog _pDialog; //created in onCreate()
private Handler _handlerToDelayDroidMove = new Handler();
private Handler _handlerToDelayProgressDialog = new Handler();
private Handler _handlerToDelayDefinitionClosure = new Handler();
public void onClickValidatePlayerMoveAndTriggerDroidMove(View v) {
int score = _arbitre.validatePlayerMoveAndReturnScore(_listOfLetters);
toast(String.format(getResources().getString(R.string.player_word_score), score));
// ***** Only start Droid move when previous toast has been displayed ****
timedDroidPlayWithSpinner();
}
private void timedDroidPlayWithSpinner() {
_handlerToDelayProgressDialog.removeCallbacks(_droidThinkingDialogRunnable);
_handlerToDelayDroidMove.removeCallbacks(_droidPlayRunnable);
_handlerToDelayProgressDialog.postDelayed(_droidThinkingDialogRunnable, 1500);
_handlerToDelayDroidMove.postDelayed(_droidPlayRunnable, 1500 + DUMMY_DELAY);
}
private Runnable _droidThinkingDialogRunnable = new Runnable() { //Show a "Droid is thinking spinner dialog"
public void run() {
_pDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
_pDialog.setMessage(getResources().getString(R.string.droid_thinking));
_pDialog.setCancelable(false);
_pDialog.show();
}
};
private Runnable _droidPlayRunnable = new Runnable() {
public void run() {
String word = playBestMoveAndUpdateGUI(); // Droid move (CPU intensive, can take several seconds)
saveGameStateToPrefs();
_pDialog.dismiss(); //Hide "Thinking dialog")
new SearchDefinitionTask(GameActivity.this).execute(word);
}
};
private Runnable _hideDefinitionRunnable = new Runnable() {
public void run() {
_definition.startAnimation(_slideUpAnim);
_definition.setVisibility(View.GONE);
}
};
// Made static so we are sure if does not reference the Activity (risk of leak)
public static class SearchDefinitionTask extends AsyncTask<String, Void, String[]> {
private WeakReference<GameActivity> weakRefToGameActivity;
public SearchDefinitionTask(GameActivity context) { //Save a weak reference to the Activity
super();
weakRefToGameActivity = new WeakReference<GameActivity>(context);
}
protected String[] doInBackground(String... words) {
try {
DefFetcherInterface defFetcher = null;
Language l = weakRefToGameActivity.get()._dictionaryId;
defFetcher = new OnlineDefinitionFetcher(l);
return defFetcher.getDefinition(words[0]);
} catch (Exception e) { // Typical exceptions are due to lack of internet connectivity
Log.e("Definition fetch error: ", e.toString());
String[] ret = { "", "" };
ret[0] = mots[0];
if (weakRefToGameActivity == null) { // !!! This occurs in ~0.3% of the games !!!
ErrorReporter.getInstance().handleSilentException(new Exception("Silent ERROR 1: weakRef is NULL"));
return ret;
}
if (weakRefToGameActivity.get() == null) { !!! This occurs in ~1% of the games !!!
ErrorReporter.getInstance().handleSilentException(new Exception("Silent ERROR 2: weakRef.get() is NULL"));
return ret;
}
// If we get here we still have a reference on our Activit/context, so let's show a decent error message
ret[1] = weakRefToGameActivity.get().getResources().getString(R.string.no_connection);
return ret;
}
}
protected void onPostExecute(String[] result) {
if (result[0] != "") { //Don't send another error report if WeakRef was already NULL in doInBackground()
if (weakRefToGameActivity == null) { !!! This occurs in ~0.5% of the games !!!
ErrorReporter.getInstance().handleSilentException(new Exception("Silent ERROR 3: weakRef is NULL"));
} else if (weakRefToGameActivity.get() == null) { !!!!!!!! This occurs in ~1% of the games !!!!!!!!
ErrorReporter.getInstance().handleSilentException(new Exception("Silent ERROR 4: weakRef.get() is NULL"));
} else {
// Everything is fine, show a box with the definition of the word for a few seconds
//(with animation to make the box appearing from the top of the screen)
weakRefToGameActivity.get()._definition.setVisibility(ImageView.VISIBLE);
weakRefToGameActivity.get()._handlerToDelayDefinitionClosure.removeCallbacks(weakRefToGameActivity.get()._hideDefinitionRunnable);
weakRefToGameActivity.get()._definition.setText(Html.fromHtml("<b>" + result[0].toUpperCase() + "</b> " + result[1]));
weakRefToGameActivity.get()._definition.startAnimation(weakRefToGameActivity.get()._slideDownAnim);
weakRefToGameActivity.get()._handlerToDelayDefinitionClosure.postDelayed(weakRefToGameActivity.get()._hideDefinitionRunnable,
DURATION_OF_DEFINITION);
}
}
}
}
}
Any idea of what could go wrong or how to reproduce?
Sebastien, maybe you can try to check the onDestroy is never called for your Activity... The activity can be restarted when the screen is rotated (which you already handle), but there are other configuration changes that may cause the same behavior.
Another pretty common one is to take the keyboard out on some phones, but there are others that are even more obscure to me. You can see the list there
Beside that, I really don't see anything wrong in your code and cannot imagine what else could cause your trouble.
The worst ones are your errors 1 and 3. Can you check in the constructor that weakRefToGameActivity is not null after it is created? (and if it is null, what about the context argument).
Please post updates once you find the root cause of your problem.
Bonne chance.
I have a little problem with ChangeableText in AndEngine. I want to know how to update it's text without freezing the screen? For now I'm using this way, but it's freezing my phone for maybe 2-3 seconds :
private void removeFace(final Sprite face) {
hm = getIconNames();
if(face.getUserData().equals("petrol")){
elapsedText.setText(hm.get(25));
final PhysicsConnector facePhysicsConnector = this.mPhysicsWorld.getPhysicsConnectorManager().findPhysicsConnectorByShape(face);
this.mPhysicsWorld.unregisterPhysicsConnector(facePhysicsConnector);
this.mPhysicsWorld.destroyBody(facePhysicsConnector.getBody());
this.mScene.unregisterTouchArea(face);
this.mScene.detachChild(face);
} else {
}
System.gc();
}
Any ideas how to do that?
Remember that when you detachChild you should do this in thread because if you don't it can causes errors. Use this construction
runOnUpdateThread(new Runnable(){
#Override
public void run() {
if(yourSprite.hasParent())
scene.detachChild(yourSprite);
}});
You can put there all code if you want then your phone shouldn't freez
private void removeFace(final Sprite face) {
runOnUpdateThread(new Runnable(){
#Override
public void run() {
hm = getIconNames();
if(face.getUserData().equals("petrol")){
elapsedText.setText(hm.get(25));
final PhysicsConnector facePhysicsConnector = this.mPhysicsWorld.getPhysicsConnectorManager().findPhysicsConnectorByShape(face);
this.mPhysicsWorld.unregisterPhysicsConnector(facePhysicsConnector);
this.mPhysicsWorld.destroyBody(facePhysicsConnector.getBody());
this.mScene.unregisterTouchArea(face);
this.mScene.detachChild(face);
} else {
}
System.gc();
}});
}
Thats probably because you are fetching some information while setting the text.
What you should do is, get your
String hm = hm.get(25); //What ever the correct object is or variable. im guessing its a string or int.
Then
pass it to the Changeable text to be set.
elapsedText.setText(hm); //If its a int make sure you do String.valueOf(hm);
The only 3 methods here that have the possibility to take long are getIconNames() and get(), and System.gc()
The others are usually methods that return immediately, or have a very low complexity. For example, getPhysicsConnectorManager() returns immediately. findPhysicsConnectorByShape, unregisterPhysicsConnector, unregisterTouchArea and detachChild all have complexity of O(n), (And most of the others methods also have complexity of O(1) or O(n)).
I recommend you to look in the LogCat and when System.gc() is called, you will see a Log.i (blue) message of the tag of dalvikvm which will begin with GC_EXPLICIT and will give you some information about how long did the garbage collection took, etc....
If that GC call isn't taking the time, it must be your 2 methods, getIconNames() and hm.get(). You can put a Log.d message after each code line, which will write the last code line executed. This way you can follow the times.
Im doing a little app, its a memory game, you choose one card, it turns up, you choose the second card, it turns up, if they are the same they are out of the game, if they dont match, they are turned down again.
I have
public class PlayActivity extends Activity implements OnClickListener.
The flip events are trigged by click handlers, declared at public void onCreate(Bundle savedInstanceState) they work fine.
When the first card is selected, it calls my method Action, this sets the image from default (the card back) to the 'real' image (the card front). Fine so far.
My problem is the second card: when its selected, it calls method Action, where it should set the front image (lets call it 'middle action'), then a litle pause (a while loop doing nothing until x milliseconds), and then it checks what to do (if they match or not) and turn them down or take the out of the game. You can see where is the problem: the screen only displays the result after x milliseconds (the 'middle action' is not being draw).
Since I have done some little games with XNA, I know the loop Update-Draw, so I know here im updating the same thing twice so always the last one is drawn. But here, the only updating I can have is when click events are trigged, I need a periodic, constant update.
Help?
You can probably use a TimerTask in order to handle that. You can implement it like the following.
This probably isn't the most robust way to do it, but it is an idea. If I figure out a better way to do it in a short time I'll edit my post. :)
Also I would like to add that if you want to make a game that uses an update / draw loop you may need to use a SurfaceView to draw your game. Look at the example here http://developer.android.com/resources/samples/JetBoy/index.html
public class TestGameActivity extends Activity {
/* UIHandler prevents exceptions from
performing UI logic on a non-UI thread */
private static final int MESSAGE_HIDE_CARD = 0;
private class UIHandler extends Handler {
#Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MESSAGE_HIDE_CARD:
ImageView cardView = (ImageView) msg.obj;
cardView.setImageResource(R.drawable.faceDownCard);
break;
}
}
}
private UIHandler handler = new UIHandler();
// Handle my click. V is the card view
public void onClick(View v) {
final int viewID = v.getId();
// Create a hide task
TimerTask hideTask = new TimerTask() {
#Override
public void run() {
// Construct a message so you won't get an exception
Message msg = new Message();
msg.what = MESSAGE_HIDE_CARD;
msg.obj = findViewById(viewID);
handler.sendMessage(msg);
}
};
// Schedule the task for 2 seconds
new Timer().schedule(hideTask, 2000);
}
}