【问题标题】:Android: Pause and resume a thread within an activityAndroid:暂停和恢复活动中的线程
【发布时间】:2014-09-21 13:58:13
【问题描述】:

编辑:我发现我在下面描述的内容仅发生在我的模拟设备(Nexus 5、目标 api 19、4.4.2 和 Intel Atom (x86) cpu)上,但不在我的物理设备上(HTC一)....

EDIT2:Edit1 是由于我没有捕捉到的 IllegalStateException 引起的。添加了一些代码以在尝试启动线程之前检查线程是否已经在运行。这与接受的答案相结合解决了我的问题。

我已经实现了一个 Activity,它在 Activity 的 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();
}

但我的线程没有恢复。任何想法为什么?感谢您的帮助。

马库斯

【问题讨论】:

    标签: android multithreading android-activity


    【解决方案1】:

    我认为所有答案都与您的运行变量有关,因为您无法在没有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 可以访问它们。

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

    【讨论】:

    【解决方案2】:

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

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

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

    【讨论】:

      【解决方案3】:

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

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-03-24
        • 1970-01-01
        相关资源
        最近更新 更多