• After 15+ years, we've made a big change: Android Forums is now Early Bird Club. Learn more here.

WHILE loop not exiting

ShamusVW

Newbie
I have a WHILE loop that exits when run on one phone, yet on a different phone it doesn't!
In my class I declare the following variable
Code:
public class FragmentMain extends Fragment {
private Boolean notificationsExtracted;
...

Then in my onCreateView I have the following with logging
Code:
...
Log.i("notif", "3");
GetNotificationsNewMySQL getNotificationsNewMySQL = new GetNotificationsNewMySQL();
getNotificationsNewMySQL.execute("");
while (!notificationsExtracted) {};
Log.i("notif", "4");
...

The reason for the while loop is to stop the code until a different class GetNotificationsNewMySQL has been called, and in this class I set notificationsExtracted = true, as shown in the following piece of code
Code:
notificationsExtracted = true;
if (notificationsExtracted)
    Log.i("notif", "true");
else
    Log.i("notif", "false");

Now when I run it on all the phones except one (a Conexis x2), it logs that notificationsExtracted has been set to true, it never seems to register this state where the class was called from. Note that when first instantiating the class, it first sets notificationsExtracted = false, does some work, and then sets it true, hence the 2nd logging line "notificationExtracted = false"

This is my logging output (where it works as expected)

2019-11-13 16:34:04.156 12400-12400/com.example.pdcapp I/notif: 3
2019-11-13 16:34:04.156 12400-12400/com.example.pdcapp I/notif: notificationExtracted = false
2019-11-13 16:34:04.261 12400-12435/com.example.pdcapp I/notif: true
2019-11-13 16:34:04.261 12400-12400/com.example.pdcapp I/notif: 4

The above shows that the while loop waits until the variable gets set to true before continuing the flow of code (i.e. when it logs "4" it has then continued).
However, on this one particular phone, it will log the exact same first 3 lines, i.e. in the called class it logs the variable as being true, but it never exits the while loop, with the result that the 4th line (the "4") never gets logged, and the phone then hangs.

Very perplexing, and I hope someone can shed some light on this please
 
What are the OS versions of the different phones? SDK versions?

From your description, my gut is saying "threading problem" or "multiple instances".

One thread (or one instance of the object) is setting the value to true, but the other, the one with the loop, isn't reading the same data - it's reading its own variable.

First thing I might try would be to make notificationExtracted a static property.
 
Thank you for the suggestion.
I tried making the variable static, it still doesn't work.
As you surmised, I am working with AsyncTask which is nested within my class FragmentMain.
I don't re-declare this variable either in this nested class. I did originally set notificationExtracted to false within the newly instantiated class, but I have now set it to false before instantiating it, just to be on the safe side, although this shouldn't affect the outcome (unless it tries to run the while loop before it is set to false, in which case it would matter)

Regarding multiple instances, I have logging in the instantiated class, and it never runs more than once according to the logs.
Also, the onCreateView only gets called once when switching to that fragment, and that is where I have called this new class.
To explain the program flow, each time the fragment is switched to, it checks in a database on the count of a certain item. This is done by instantiating the class, and then waiting until the result had been extracted, and it then updates the notificationExtracted variable, at which time I would then continue the program flow, i.e. setting a TextView with this extracted variable.
The reason for waiting is that since it was running in parallel, I would have the case where I set the TextView to a value that hadn't yet been extracted, so I wait.

The specs of the phone it doesn't work on is:
ConeXis X2
Android version 7.0
Kernel version 3.18.31

At this point, all other phone types work, no-one has said differently to me.
 
It definitely seems a bit of a stumper. Are you stuck on doing it this way, with the while loop?

I'm thinking maybe run the async task and just do the update in a callback function instead? Why would you not take that approach?

(No criticism implied, just working the problem)
 
The reason for trying it this way I actually discuss in this thread https://androidforums.com/threads/sequence-of-the-program-running.1314113/
So it really is the only way I know how to do it. I have a desktop programming background (but not using Java, last time I did anything Java related was varsity!)
So I really am for the most part clueless with the best way of doing certain things, but I will look into callback functions.
It just frustrates me that logically I can't see anything wrong. Possibly this particular brand of phone doesn't support threading very well...?

If anyone else has an idea what I might be doing wrong, please help me.
I am willing to post more complete code if that will help.
 
It just frustrates me that logically I can't see anything wrong. Possibly this particular brand of phone doesn't support threading very well...?

I don't really see anything wrong either, not sure why a particular phone would be failing when others aren't. But here is how I would approach what you're trying to do:

First, split your onCreateView into two functions, where you currently have the while - with a small addition:
Code:
public void onCreateView() {
    // ...
    Log.i("notif", "3");
    
    GetNotificationsNewMySQL getNotificationsNewMySQL = new GetNotificationsNewMySQL(this);
    getNotificationsNewMySQL.execute("");
}

public void notificationsLoaded() {
    Log.i("notif", "4");
    // ...
}
From how I'm reading this, I assume GetNotificationsNewMySQL() is an AsyncTask class? Add a fragment param to your doInBackground() - so something like:
Code:
private class GetNotificationsNewMySQL extends AsyncTask<FragmentMain,Void,Void> {
    FragmentMain callingFragment;
    // ...
    @Override
    protected Void doInBackground(Fragment... params) {
        callingFragment = params[0];
        // ...
    }
and add an onPostExecute:
Code:
    protected void onPostExecute(Void v) {
        callingFragment.notificationsLoaded();
    }

I don't know for sure if this will work with Fragments, but I have a couple apps where I follow a similar construct with Activities. Hopefully this will at least put you on a path to a solution.
 
Back
Top Bottom