【问题标题】:removeCallbacks not stopping runnableremoveCallbacks 没有停止可运行
【发布时间】:2011-08-16 04:52:59
【问题描述】:

我从一个方法调用:

myHandler.postDelayed(mMyRunnableHide, 6000);

调用:

public Runnable mMyRunnableHide = new Runnable()
{

    public void run()
    {
        mTextDisplay.setText("");
        DisplayX();
    }
 };

如果点击屏幕上的按钮,我想停止可运行:

   Button next = (Button) findViewById(R.id.Breaction);
    next.setOnClickListener(new View.OnClickListener() {
        public void onClick(View view) {

            myHandler.removeCallbacks(mMyRunnableHide);

            mTextDisplay.setText("");
            DisplayX();
            }
        });   
    }

removecallbacks 不会停止可运行对象。我究竟做错了什么?我使用正确的方法吗?当用户单击按钮时,我只想让可运行对象“不运行”。

感谢您的帮助。

【问题讨论】:

  • @YekmerSimsek Runnable 类没有 stop() 方法。

标签: android runnable


【解决方案1】:

在我看来removeCallbacks(..) 只停止待处理 消息(可运行)。如果您的 runnable 已经开始,那么就没有停止它(至少不是这样)。

或者,您可以扩展 Runnable 类并为其提供某种终止开关,如下所示:

public class MyRunnable implements Runnable
{
   private boolean killMe = false;

   private void run()
   {
      if(killMe)
         return;

      /* do your work */
   }

   private void killRunnable()
   {
      killMe = true;
   }
}

这只会阻止它启动,但您可以偶尔检查killMe 并退出。如果您正在循环运行可运行文件(例如某种后台线程),您可以说:

while(!killMe) {
   /* do work */
}

希望对你有帮助

编辑我只是想发布关于此的更新。自从这篇原始文章以来,Google 提出了一个名为 AsyncTask 的出色类,它可以为您处理所有这些内容。任何阅读本文的人都应该仔细研究它,因为它是正确的做事方式。

你可以阅读它here

【讨论】:

  • 请务必将 killMe 标记为 volatile。否则,编译器很可能会将while(!killMe) 替换为while(true),因为它永远不会改变(据它所知)。
  • 错字,MyRunnable “实现” Runnable {...} 不是“扩展”
  • @AndyShulman volatile 变量在有多个线程访问同一个全局变量时最有用。 volatile 实际上是在说,“永远不要将此变量存储在寄存器中。始终从内存中读取它”。如果您的代码经常读取/更改变量并且必须跨线程保持准确,这将变得很重要。
  • @AndyShulman 你错了。 javac 和 java/dalvik vm 都不会像你声称的那样做。
  • @mtmurdock removeCallbacks 是同步的,从主线程调用时立即生效。主线程中不能有“已经开始”的回调同时运行。如果 Runnable 正在运行,那么按钮处理程序将永远无法运行,直到 Runnable 完成。如果一切都从主线程调用,则不需要标志。
【解决方案2】:

Handler.removeCallback 是同步的,并且可以很好地提供:

  1. 您始终在主线程中调用postDelayed
  2. 你总是在主线程中调用removeCallback
  3. 删除回调后,您不会再次调用postDelayed

因此,在您的情况下,removeCallbacks 是从在主线程中运行的按钮处理程序调用的。但是您没有在代码中显示您调用postDelayed 的位置。如果您从后台线程调用它,那就是您的问题所在。

如果您确定没有从后台线程调用这些方法中的任何一个,并且调用的顺序是正确的,那么由于配置更改(屏幕旋转等)的活动重新创建,您可能会无意中让未取消的任务保持活动状态)。始终确保在onDestroy 方法中再次调用removeCallbacks 以防止出现此类问题。

【讨论】:

    【解决方案3】:

    这是完成 mtmurdock 描述的另一种方法。此类将允许在您的 Runnable 定义为匿名内部类的任何类中编辑实例变量。

    package support;
    
    /**
    * Runnable that can be stopped from executing
    */
    public abstract class KillableRunnable implements Runnable{
    
    private boolean isKilled=false;
    
    /**
     * Instead of Overriding run(), override this method to perform a Runnable operation. 
     * This will allow editing instance variables in the class that this Runnable is defined
     */
    public abstract void doWork();
    
    //The handler that posts this Runnable will call this method. 
    //By default, check if it has been killed. doWork() will now be the method 
    //override to implement this Runnable
    @Override
    final public void run(){
        if(!isKilled){
            doWork();
        }
    }
    
    final public void kill(){
        isKilled=true;
    }
    }
    

    【讨论】:

    • Hmm.. 当doWork() 已经在运行并且你从其他线程调用kill() 时会发生什么? :-)
    【解决方案4】:

    我不认为 removeCallbacks(..) 只会停止挂起的消息 (Runnables) ,我认为 removeCallbacks(..) 不起作用有其他原因,但我不知道。因为 postDelayed(..) 和 removeCallbacks(..) 在同一个线程中

    【讨论】:

      【解决方案5】:

      以下内容对我有用。将其放在 onResume 中。

      mService= null;
      
      public void onServiceConnected(ComponentName name, IBinder service) {
              Log.i(TAG, "OnServiceConnected");
              ContadorFG.LocalBinder binder = (ContadorFG.LocalBinder) service;
              mService = binder.getService();
              connected = true;
              synchronized (lock){
                  lock.notifyAll();
              }
          }
      
      public void onResume() {
          super.onResume();
          loopDelayed();
      }  
      
      private void loopDelayed(){ 
          final Handler handler = new Handler();
          handler.postDelayed(new Runnable() {
              @Override
              public void run() {
                  if (mService != null) {
      
                      ----
                      ----
                      ----
      
                      return;
                  }else{
                      //auto call 
                      loopDelayed();
                  }
              }
          }, 10);
      
      }
      

      【讨论】:

        猜你喜欢
        • 2013-10-06
        • 2013-09-29
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多