在离开并返回Activity时,删除处理程序回调会停止工作

时间:2013-03-22 17:56:31

标签: android handler runnable

我有一个处理程序和一个runnable,runnable每5秒向屏幕发布一次toast,这是代码:

Handler handler = new Handler();
Runnable runnable = new Runnable() {

    public void run() {

        Toast.makeText(getApplicationContext(), "DISPLAY MESSAGE" + walking, Toast.LENGTH_SHORT).show();
        handler.postDelayed(runnable, 5000);
    }
};

在同一个活动中,我可以通过按下kill按钮来删除回调,调用它:

handler.removeCallbacks(runnable);

当上面这个叫做Toast停止显示所以到目前为止一切都很好。当我离开我的活动去另一个活动时,toast消息会一直显示,这就是我想要的,但当我回到创建runnable的第一个活动并按下kill按钮时,它不会删除runnable。离开和回来时我无法再移除可运行的东西。

我尝试过使用几乎所有我在SO上使用Handler和runnables的例子,没有任何东西可以帮助我解决这个问题。

当我离开我的Activity并返回它时会创建新的runnable和handler对象吗?如果是这样,为什么初始runnable会继续运行?

3 个答案:

答案 0 :(得分:2)

在活动中保留长期参考资料是一种糟糕的形式。即使您旋转手机,它们也会轻松地经常被破坏和重新创建!发生的事情是重新创建Activity时,你怀疑有一个新的Runnable和Handler对象。

为了避免使用服务来解决这个问题,我所做的就是创建一个片段...让我们称之为StateFragment。

为此片段提供无视图,因此对用户不可见。它仅用于存储变量。创建活动后,如果活动尚未存在,请将其添加到活动中。最后,在Fragment类本身中,在onCreate中,setRetainInstance为true。

我承认这有点像黑客,但它是一种非常方便的方法,可以在创建和销毁活动时保留流程中的变量。在这种情况下,当Activity被销毁并重新创建时,片段可能会被保留,除非它已经在后台停留一段时间并由GC清理。下面是一些代码:

public class StateFragment extends Fragment{
  //add some variables here
  //these will not last long time!
  Handler handler;
  Runnable runnable;

  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    // Retain this fragment across configuration changes.
    setRetainInstance(true); //<--this is the important part!
        Handler = new Handler... etc.



  }
}

现在在您的Activity中,有一个类级变量来保留引用:

public Class MainActivity  extends FragmentActivity {
StateFragment sf;

然后在你的“onCreate”中你需要检查它是否存在,否则附上它:

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
sf=(StateFragment) getFragmentManager().findFragmentByTag("storage");
if (sf==null)
{
  sf=new StateFragment();
  getFragmentManager().beginTransaction().add(sf, "storage").commit();
}

总的来说,我发现活动的波动性是一个巨大的痛苦,并且拥有更持久的存储通常是一个很大的好处。现在您可以轻松地将Runnable引用为

sf.runnable

答案 1 :(得分:1)

您需要实现在后台运行的服务, 然后在按下按钮时终止服务。这是实现这一目标的最简单方法。

答案 2 :(得分:1)

尝试以下操作,每隔5秒显示一次Toast,就会使用一个计时器类 从你的类启动backhelper服务类:

public class BackHelper extends Service {   
        @Override
        public void onCreate() 
        {
            Log.i(TAG, "Service onCreate");
            super.onCreate();
                        Timer timer = new Timer();
                TimerTask updateProfile = new BackHelper(sock.this);
                    timer.scheduleAtFixedRate(updateProfile, 0, 5000);      
        }
        @Override
        public void onDestroy() {
            // TODO Auto-generated method stub
            Log.i(TAG, "Service onDestroy");
            super.onDestroy();
        }
        @Override
        public int onStartCommand(Intent intent, int flags, int startId) {
            // TODO Auto-generated method stub
            Log.i(TAG, "Service onstart");

            return Service.START_STICKY;
        }
        @Override
        public IBinder onBind(Intent arg0) {
            // TODO Auto-generated method stub
            Log.i(TAG, "Service onBind");
            return null;
        }
    public class sock extends TimerTask
        {
        @Override
            public void run()
            {
     Toast.makeText(getBaseContext(), "DISPLAY MESSAGE" + walking, Toast.LENGTH_SHORT).show();

                    }
            }