Android 线程无法使用 wait() 和 notify() 使 notify() 正常工作
Android threads can't get notify() to work properly using wait() and notify()
所以我正在编写一个 Android 应用程序,它会在用户按下按钮时进行倒计时。线程运行倒计时。我的问题是,当我暂停应用程序时,我希望线程停止计数,然后在应用程序返回后恢复。我的通知无法正常工作。帮忙谢谢!
public class MainActivity extends Activity {
private TextView mText;
private EditText mUserInput;
private CounterThread mCounterThread;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mText = (TextView)findViewById(R.id.text);
mUserInput = (EditText)findViewById(R.id.userInput);
mCounterThread = new CounterThread();
}
@Override
public synchronized void onPause(){
super.onPause();
mCounterThread.running = false;
}
@Override
public synchronized void onResume(){
super.onResume();
mCounterThread.running = true;
notify();//seems like this does nothing!
}
public void startCounterThread(){
mCounterThread.start();
}
public void button_handler(View v){
startCounterThread();
}
public void updateSeconds(final long seconds){
Runnable UIdoWork = new Runnable(){
public void run(){
String time = String.valueOf(seconds);
mText.setText("Your file will open in " + time + " seconds");
}
};
runOnUiThread(UIdoWork);
}
private class CounterThread extends Thread{
int count = 10;
boolean running = true;
@Override
public synchronized void run(){
while(count != 0){
while(!running){
try{
wait();//wait() will wait forever
//I don't want to put a time since
//I have no clue when the user will resume again
}catch(InterruptedException e){
e.printStackTrace();
}
}
try{
Thread.sleep(1000);
}catch(InterruptedException e){
e.printStackTrace();
}
updateSeconds(count--);
}
}
}
这不起作用是有道理的,因为 wait() 和 notify() 在用作锁的对象上工作。当您在 运行() 方法中 运行 wait() 时,您使用的是 CounterThread 的实例作为锁,但是当您在 onResume() 方法中 运行 notify() 时,您正在使用 MainActivity 的一个实例。 CounterThread 永远不会收到通知。您的选择是(在您的 onResume() 方法中):
...
synchronized(mCounterThread) {
mCounterThread.notify();
}
...
稍微修改的代码:
public class MainActivity extends Activity {
private TextView mText;
private EditText mUserInput;
private CounterThread mCounterThread;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main_2);
mText = (TextView) findViewById(R.id.text);
mUserInput = (EditText) findViewById(R.id.userInput);
mCounterThread = new CounterThread();
mCounterThread.start();
}
@Override
public synchronized void onPause() {
super.onPause();
mCounterThread.onPause();
}
@Override
public synchronized void onResume() {
super.onResume();
mCounterThread.onResume();
}
public void startCounterThread() {
mCounterThread.start();
}
public void button_handler(View v) {
startCounterThread();
}
public void updateSeconds(final long seconds) {
Runnable UIdoWork = new Runnable() {
public void run() {
String time = String.valueOf(seconds);
mText.setText("Your file will open in " + time + " seconds");
}
};
runOnUiThread(UIdoWork);
}
private class CounterThread extends Thread {
private int count = 10;
private final Object lock = new Object();
private volatile boolean isRunning = true;
public void onResume() {
if(!isRunning){
isRunning = true;
synchronized (lock){
lock.notify();
}
}
}
public void onPause() {
isRunning = false;
}
@Override
public void run() {
while (count != 0) {
synchronized (lock) {
if (!isRunning) try {
lock.wait();
} catch (InterruptedException e) {
//
}
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
//
}
updateSeconds(count--);
}
}
}
}
- 您的字段
running
必须标记为 volatile
。它基本上意味着多个线程可以更改它并且所有线程都会看到它。
- 不要从
Thread
或 Runnable
中公开监视器对象。使用 activity 作为监视器是非常糟糕的主意。在任何地方传递 activity 的引用是非常糟糕的主意。
- 您使用了不同的监视器对象:
Thread
和 Activity
。使用一根内螺纹。
所以我正在编写一个 Android 应用程序,它会在用户按下按钮时进行倒计时。线程运行倒计时。我的问题是,当我暂停应用程序时,我希望线程停止计数,然后在应用程序返回后恢复。我的通知无法正常工作。帮忙谢谢!
public class MainActivity extends Activity {
private TextView mText;
private EditText mUserInput;
private CounterThread mCounterThread;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mText = (TextView)findViewById(R.id.text);
mUserInput = (EditText)findViewById(R.id.userInput);
mCounterThread = new CounterThread();
}
@Override
public synchronized void onPause(){
super.onPause();
mCounterThread.running = false;
}
@Override
public synchronized void onResume(){
super.onResume();
mCounterThread.running = true;
notify();//seems like this does nothing!
}
public void startCounterThread(){
mCounterThread.start();
}
public void button_handler(View v){
startCounterThread();
}
public void updateSeconds(final long seconds){
Runnable UIdoWork = new Runnable(){
public void run(){
String time = String.valueOf(seconds);
mText.setText("Your file will open in " + time + " seconds");
}
};
runOnUiThread(UIdoWork);
}
private class CounterThread extends Thread{
int count = 10;
boolean running = true;
@Override
public synchronized void run(){
while(count != 0){
while(!running){
try{
wait();//wait() will wait forever
//I don't want to put a time since
//I have no clue when the user will resume again
}catch(InterruptedException e){
e.printStackTrace();
}
}
try{
Thread.sleep(1000);
}catch(InterruptedException e){
e.printStackTrace();
}
updateSeconds(count--);
}
}
}
这不起作用是有道理的,因为 wait() 和 notify() 在用作锁的对象上工作。当您在 运行() 方法中 运行 wait() 时,您使用的是 CounterThread 的实例作为锁,但是当您在 onResume() 方法中 运行 notify() 时,您正在使用 MainActivity 的一个实例。 CounterThread 永远不会收到通知。您的选择是(在您的 onResume() 方法中):
...
synchronized(mCounterThread) {
mCounterThread.notify();
}
...
稍微修改的代码:
public class MainActivity extends Activity {
private TextView mText;
private EditText mUserInput;
private CounterThread mCounterThread;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main_2);
mText = (TextView) findViewById(R.id.text);
mUserInput = (EditText) findViewById(R.id.userInput);
mCounterThread = new CounterThread();
mCounterThread.start();
}
@Override
public synchronized void onPause() {
super.onPause();
mCounterThread.onPause();
}
@Override
public synchronized void onResume() {
super.onResume();
mCounterThread.onResume();
}
public void startCounterThread() {
mCounterThread.start();
}
public void button_handler(View v) {
startCounterThread();
}
public void updateSeconds(final long seconds) {
Runnable UIdoWork = new Runnable() {
public void run() {
String time = String.valueOf(seconds);
mText.setText("Your file will open in " + time + " seconds");
}
};
runOnUiThread(UIdoWork);
}
private class CounterThread extends Thread {
private int count = 10;
private final Object lock = new Object();
private volatile boolean isRunning = true;
public void onResume() {
if(!isRunning){
isRunning = true;
synchronized (lock){
lock.notify();
}
}
}
public void onPause() {
isRunning = false;
}
@Override
public void run() {
while (count != 0) {
synchronized (lock) {
if (!isRunning) try {
lock.wait();
} catch (InterruptedException e) {
//
}
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
//
}
updateSeconds(count--);
}
}
}
}
- 您的字段
running
必须标记为volatile
。它基本上意味着多个线程可以更改它并且所有线程都会看到它。 - 不要从
Thread
或Runnable
中公开监视器对象。使用 activity 作为监视器是非常糟糕的主意。在任何地方传递 activity 的引用是非常糟糕的主意。 - 您使用了不同的监视器对象:
Thread
和Activity
。使用一根内螺纹。