Android: Pause and resume a thread within an activity

落爺英雄遲暮 提交于 2020-01-04 09:14:13

问题


EDIT: I've found that what I'm describing below only occurs on my emulated device (Nexus 5, target api 19, 4.4.2 with Intel Atom (x86) cpu), but NOT on my physical device (HTC One)....

EDIT2: Edit1 was due to an IllegalStateException that I didnt catch. Added some code to check if the thread was already running before trying to start it. This combined with the accepted answer resolved my issue.

I have implemented an activty that starts a new thread in the activity's onCreate method, like this:

...

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
        }
    }
};

I'm "pausing" my thread with my activity's onPause method, like this:

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

So I thought that resuming it would be just as easy...¨

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

but my thread isn't resuming. Any ideas why? Thankful for any help.

Marcus


回答1:


All of the answers i think have some issues about your running variable because you can not write and read a variable from two different Threads without synchronized block so i post my own answer:

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();
    }

}

Or you can use this code:

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();
    }

}

you can also use semaphore or wait-notify approach.

i put public String message = ""; and public boolean mustBePost = true; in to mSync object but it is not necessary because only main thread have an access to them.

if you have any problem please ask.




回答2:


The statement running = false; will stop execution of the Thread, instead of pausing it. Use two variables: One for stopping current Thread, and another for pausing and resuming the Thread, as follow:

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

In the onPause event of the Activity, set isThreadPause to true, and in the onResume event, set isThreadPause to false.




回答3:


This is because your Runnable object stops when the while loop stops. You could try this:

Runnable work = new Runnable() {

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


来源:https://stackoverflow.com/questions/25959950/android-pause-and-resume-a-thread-within-an-activity

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!