即使变量已更新,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
方法中执行该代码即可。
我创建了一个嵌套的 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
方法中执行该代码即可。