Android,暂停和恢复处理程序回调

15

我有一个处理程序,我正在如下使用:

handler.postDelayed(Play, 1000);
当我的应用程序调用onPause()时,如果在此之前发生了某些情况,我需要暂停它并告诉它不要执行“postDelayed”,直到我恢复它。这是否可能,或者是否有另一种替代方法?我的问题是,当调用onPause()时,我会暂停音频(SoundManager),但如果在此之后调用handler.postDelayed,则音频将不会被暂停,并且将继续在后台播放我的应用程序。
@Override
public void onPause()
{
  Soundmanager.autoPause()
}

但是经过1000毫秒后的postDelayed会重新开始播放音频。

5个回答

20

你需要创建Handler的子类并按照以下方式实现暂停/恢复方法(然后只需在想要暂停消息处理时调用handler.pause(),在想要重新启动时调用handler.resume()):

class MyHandler extends Handler {
    Stack<Message> s = new Stack<Message>();
    boolean is_paused = false;

    public synchronized void pause() {
        is_paused = true;
    }

    public synchronized void resume() {
        is_paused = false;
        while (!s.empty()) {
            sendMessageAtFrontOfQueue(s.pop());
        }
    }

    @Override
    public void handleMessage(Message msg) {
        if (is_paused) {
            s.push(Message.obtain(msg));
            return;
        }else{
               super.handleMessage(msg);
               // otherwise handle message as normal
               // ...
        }
    }
    //...
}

2
没有运行方法。处理程序不是一个单独的线程(它在您的线程中运行)。 - CpnCrunch
1
对于任何查看此页面的人,请使用此替代方案而不是接受的答案。非常棒! - HaydenKai
1
一个很棒的解决方案。应该被接受的答案。这是我目前看到的实现此功能的最佳方式。 - Devansh Maurya
2
@CpnCrunch这个对于post(runnable)也适用吗? - Pierre
好的,所以不要在onPause中取消线程,这样做会使处理程序在恢复之前仅在时间耗尽时重新启动。 - Harsha
是的,它也适用于 post(runnable),但当我实现 dispatchmessage 时需要注意。但是,如果顺序很重要,您需要将 Stack 更改为 FIFO。 - Devel EWeb

14

你尝试过以下方法吗:

@Override
public void onPause()
{
  handler.removeCallbacks(Play);
  Soundmanager.autoPause()
}

Ger


2
是的,但如果我恢复它,回调被删除的声音从未开始播放,因此没有什么可以恢复。我仍然希望它恢复那个声音。(或者如果它还没有开始播放,就开始播放)。 - Hamid
4
你可以实现onResume方法,并在其中执行handler.postDelayed(Play, 1000)。其中的意思是在onResume被调用时,延迟1秒后执行Play方法。 - ggomeze
3
这是很久之前的事情了,自那以后我积累了相当丰富的Android经验。我会接受这个答案,因为它的正确性在于我应该在暂停时删除回调。 - Hamid

5

修改了CpcCrunch给出的答案。我使用dispatchMessage替换了handleMessage,因为前者对我有效而后者无效。注意:以下代码是用Kotlin编写的:

class CustomHandler: Handler() {

    var s = Stack<Message>()
    var is_paused = false

    @Synchronized
    fun pause() {
        is_paused = true
    }

    @Synchronized
    fun resume() {
        is_paused = false
        while (!s.empty()) {
            sendMessageAtFrontOfQueue(s.pop())
        }
    }

    override fun dispatchMessage(msg: Message?) {
        if (is_paused) {
            s.push(Message.obtain(msg))
            return
        } else {
            super.dispatchMessage(msg)
        }
    }
}

1
这解决了我数小时的挫败感。我不知道为什么我一开始没有向下滚动看到这个。 - Tooniis

0
public class YourActivity extends AppCompatActivity {

    private static boolean handlerflag=false;
    private Handler handler;
    private Runnable runnable;
    private int myind=0,index=0,count=0;

    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.your_activtiy);         
        //oncreate exe only
        handlerflag=true;
        handler = new Handler();
        startyourtime(0);
 }
  private void  startyourtime(int a) {

    myind=0;
    for (index=a; index<10 ;index++) {
            myind++;
            runnable=new Runnable() {
                count++;
                @Override
                public void run() {
                          //your code here
               }
            };handler.postDelayed(runnable, Constants.TIME_LIMIT * myind);

   }
    @Override
    protected void onPause() {
        super.onPause();
        handlerflag=false;
        handler.removeCallbacksAndMessages(null);
    }
    @Override
    protected void onResume() {
        super.onResume();
        if(!handlerflag)
        {
           startyourtime(count);

        }
    }
}

0

当我想要暂停/恢复队列中的Runnables时,我想到了一个CpnCrunch的替代方案。一旦连接并离线,就可以调用已经调用的方法,一旦在线,就恢复队列,所有的runnables都会被执行。

不要使用Handler,而是使用ExecutorService

public class ExecutorQueueService extends ThreadPoolExecutor {
    private Stack<Runnable> runnables = new Stack<>();
    private boolean paused = false;

    public ExecutorQueueService() {
        super(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>());
    }

    public synchronized void pause() {
        paused = true;
    }

    public synchronized void resume() {
        paused = false;
        while (!runnables.empty()) {
            execute(runnables.pop());
        }
    }

    public synchronized boolean isPaused() {
        return paused;
    }

    @Override
    public void execute(Runnable runnable) {
        if (paused) {
            runnables.push(runnable);
        } else {
            super.execute(runnable);
        }
    }
}

使用它类似于Handler,但是不要使用post(runnable),而是使用execute(runnable)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接