Android:暂停和恢复活动中的话题



编辑:我发现我在下面描述的内容只发生在我的模拟设备上(Nexus 5,目标 api 19,4.4.2 与英特尔凌动 (x86( cpu(,而不是在我的物理设备(HTC One(上。

编辑2:Edit1是由于我没有捕获的非法状态异常。添加了一些代码以在尝试启动线程之前检查线程是否已运行。这与接受的答案相结合解决了我的问题。

我已经实现了一个活动,它在活动的 onCreate 方法中启动一个新线程,如下所示:

...
private boolean running;
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    running = true;
    new Thread(null, work, "myThread").start();
}
Runnable work = new Runnable() {
    @Override
    public void run() { 
        while (running) {
            //Doing work
        }
    }
};

我正在使用活动的 onPause 方法"暂停"我的线程,如下所示:

@Override
protected void onPause() {
    running = false;
    super.onPause();
}

所以我认为恢复它同样容易......

@Override
protected void onResume(){
    running = true;
    super.onResume();
}

但我的线程没有恢复。知道为什么吗?感谢任何帮助。

马库斯

我认为

所有答案都与您的运行变量有关,因为您无法在没有synchronized block的情况下从两个不同的Threads写入和读取变量,所以我发布了自己的答案:

package com.example.threadandtoast;
import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.widget.Toast;
public class MainActivity extends ActionBarActivity {
    public class MonitorObject{
           public boolean running = true;
           public String message = "";
           public boolean mustBePost = true;
    }
    Thread t;
    int threadNameCounter = 0; // i use this variable to make sure that old thread is deleted 
                               // when i pause, you can see it and track it in DDMS
    Runnable work = new Runnable() {
        boolean myRunning;
        @Override
        public void run() {
            synchronized(mSync) {
               myRunning = mSync.running;
            }
            while (myRunning) {
                runOnUiThread(new Runnable() {  // in order to update the UI (create Toast)
                @Override                       // we must switch to main thread
                public void run() { 
                    // i want to read the message so i must use synchronized block
                    synchronized(mSync) { 
                    // i use this variable to post a message just for one time because i am in an infinite loop
                    // if i do not set a limit on the toast i create it infinite times 
                      if(mSync.mustBePost){       
                          Toast.makeText(MainActivity.this, mSync.message, Toast.LENGTH_SHORT).show();
                          // the message post so i must set it to false
                          mSync.mustBePost = false;
                          // if i am going to pause set mSync.running to false so at the end of infinite loop 
                          //of thread he reads it and leaves the loop
                          if(mSync.message.equals("Main Activity is going to pause")){
                              mSync.running=false;            
                          }
                      }
                    }
                }
               });
            synchronized(mSync) {
               myRunning = mSync.running;
           }
         }
       }
    };
    final MonitorObject mSync = new MonitorObject();
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
    @Override
    protected void onPause() {
        super.onPause();
        synchronized(mSync) {
            // mSync.running = false; you can not set it here because 
            // it is possible for the thread to read it and exit the loop before he posts your message
            mSync.mustBePost=true;
            mSync.message = "Main Activity is going to pause";
        }    
    }
    @Override
    protected void onResume(){
       super.onResume();
       threadNameCounter++;
       synchronized(mSync) {
            mSync.running = true;
            mSync.mustBePost=true;
            mSync.message = "Main Activity is going to resume";
        } 
       t = new Thread(work,"My Name is " + String.valueOf(threadNameCounter));
       t.start();
    }
}

或者您可以使用以下代码:

public class MainActivity extends ActionBarActivity {
    Thread t;
    int threadNameCounter = 0; // i use this variable to make sure that old thread is deleted 
                               // when i pause, you can see it in DDMS
    String message = "";
    boolean isPost = false;
    Runnable work = new Runnable() {
        @Override
        public void run() {
            while (true) {
                runOnUiThread(new Runnable() {  
                @Override                       
                public void run() { 
                    if(!isPost){
                        Toast.makeText(MainActivity.this, message, Toast.LENGTH_SHORT).show();
                        isPost = true;
                        if( message.equals("Main Activity is going to pause")){
                            t.interrupt();
                        }
                    }
                }
               });
           if(Thread.currentThread().isInterrupted()){
               break;
           } 
         }
       }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
    @Override
    protected void onPause() {
        super.onPause();
        message = "Main Activity is going to pause";
        isPost = false;
    }
    @Override
    protected void onResume(){
       super.onResume();
       message = "Main Activity is going to resume";
       isPost = false;
       threadNameCounter++;
       t = new Thread(work,"My Name is " + String.valueOf(threadNameCounter));
       t.start();
    }
}

您还可以使用信号量或等待通知方法。

我把public String message = "";public boolean mustBePost = true;放到 mSync 对象中,但它是没有必要,因为只有main thread可以访问它们。

如果您有任何问题,请询问。

语句

running = false;将停止执行Thread,而不是暂停它。使用两个变量:一个用于停止当前Thread,另一个用于暂停和恢复Thread,如下所示:

boolean isThreadPause=false;
Runnable work = new Runnable() {    
    @Override
    public void run() { 
        while (running) {
            if (!isThreadPause) {
               // Doing work
            }
        }
    }
};

在活动的onPause事件中,将isThreadPause设置为 true ,在onResume事件中,将 isThreadPause 设置为 false

这是因为当while循环停止时,您的Runnable对象将停止。你可以试试这个:

Runnable work = new Runnable() {
    @Override
    public void run() { 
        while () {
          if(running){
            //Doing work
          }
        }
    }
};

最新更新