即使变量已更新,while 循环也永远不会退出

whlie loop never exiting even though variable updated

我创建了一个嵌套的 class,它扩展了 AsyncTask 以从数据库中提取数据。 提取完成后,它会将全局变量 ("notificationsExtracted") 设置为 true,表示该过程已完成。

在主调用代码中,我设置了一个 while 循环,等待该全局变量变为真,然后再使用提取的数据,即

while(!notificationsExtracted) {}
...now continue running other code...

在除一个之外的所有 phone 上,这完美地工作,但是 phone (Conexis x2 - Android 7.0) 拒绝反映全局变量被设置为 true。

当我进行日志记录时,它显示了实例化 class、提取数据、将全局变量设置为 true 的代码流,然后什么都没有。 在其他 phone 上,它执行上述操作,但随后继续 运行 主程序中的进一步代码。

简而言之,我在调用程序中有以下内容

public class FragmentMain extends Fragment {
  static private Boolean notificationsExtracted;
...
  @Override
  public View onCreateView(LayoutInflater inflater, ViewGroup parent, Bundle savedInstanceState) {
      View view = inflater.inflate(R.layout.fragment_main_layout, parent, false);
    ...
    Log.i("notif", "1");
    notificationsExtracted = false;
    GetNotificationsNewMySQL getNotificationsNewMySQL = new GetNotificationsNewMySQL();
    getNotificationsNewMySQL.execute("");
    while (!notificationsExtracted) { };
    Log.i("notif", "2");
    ...

然后是嵌套的class

private class GetNotificationsNewMySQL extends AsyncTask<String, Void, String> {
        @Override
        protected void onPreExecute() {
            super.onPreExecute();
        }

        @Override
        protected String doInBackground(String... params) {
            try {
                Class.forName("com.mysql.jdbc.Driver");
                Connection con = DriverManager.getConnection(url, user, pass);

                Statement st = con.createStatement();
                String q = "SELECT COUNT(*) AS cnt FROM training.app_notifications";
                Log.i("notif", "a");
                ResultSet rs = st.executeQuery(q);
                Log.i("notif", "b");
                ResultSetMetaData rsmd = rs.getMetaData();
                Log.i("notif", "c");
                while (rs.next()) {
                    notificationCount = Integer.parseInt(rs.getString(1).toString());
                }
                Log.i("notif", "d");
                notificationsExtracted = true;
            } catch (Exception e) {
                Log.i("notif", "error extracting");
                e.printStackTrace();
            }
            if (notificationsExtracted)
                Log.i("notif", "true");
            else
                Log.i("notif", "false");
            return "";
        }

        @Override
        protected void onPostExecute(String result) {
        }
    }

现在在除 phone 之外的所有 phone 上,它记录以下程序流序列

2019-11-15 11:18:40.338 1951-1951/com.example.pdcapp I/Notif: 1
2019-11-15 11:18:40.339 1951-1951/com.example.pdcapp I/Notif: 2
2019-11-15 11:18:40.438 1951-1951/com.example.pdcapp I/notif: 1
2019-11-15 11:18:40.512 1951-2025/com.example.pdcapp I/notif: a
2019-11-15 11:18:40.521 1951-2025/com.example.pdcapp I/notif: b
2019-11-15 11:18:40.521 1951-2025/com.example.pdcapp I/notif: c
2019-11-15 11:18:40.522 1951-2025/com.example.pdcapp I/notif: d
2019-11-15 11:18:40.522 1951-2025/com.example.pdcapp I/notif: true
2019-11-15 11:18:40.522 1951-1951/com.example.pdcapp I/notif: 2

除了那个 phone 我得到以下结果,结果是 phone 挂起,即它永远不会通过 while 循环:


2019-11-15 11:20:57.153 20089-20089/com.example.pdcapp I/Notif: 1
2019-11-15 11:20:57.154 20089-20089/com.example.pdcapp I/Notif: 2
2019-11-15 11:20:57.196 20089-20089/com.example.pdcapp I/notif: 1
2019-11-15 11:20:57.267 20089-20348/com.example.pdcapp I/notif: a
2019-11-15 11:20:57.274 20089-20348/com.example.pdcapp I/notif: b
2019-11-15 11:20:57.274 20089-20348/com.example.pdcapp I/notif: c
2019-11-15 11:20:57.274 20089-20348/com.example.pdcapp I/notif: d
2019-11-15 11:20:57.274 20089-20348/com.example.pdcapp I/notif: true

请提供帮助。作为参考,我之前在以下方面寻求帮助 link https://androidforums.com/threads/while-loop-not-exiting.1315976/

能否请您在获取String q、ResultSet和ResultSetMetaData的行后添加logger?也许它卡在这些线上。

你的做法违背了异步执行的原则。如果你启动一个 asynchTask,然后等到它完成,它就不是真正的异步。
不过这没关系,有时您只需要按特定顺序完成某些事情,但您不能在主线程上完成。

我不太确定为什么您的程序在技术层面上不起作用,但我想我曾经遇到过类似的问题。我相信在 Java 中,从一个线程中更新变量并不一定也为所有其他线程更新变量。 Android Studio 是否会在 while 循环中向您发出警告?
我希望在 Java 中对多线程有更多经验的人可以对此说点什么。

但是,您的问题的解决方案很简单:
您希望在 AsyncTask 完成执行后执行 while 循环之后的任何代码,因此只需在 onPostExcecute 方法中执行该代码即可。