2

我有一个处理程序和一个可运行对象,可运行对象每 5 秒向屏幕发布一次祝酒词,代码如下:

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

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

handler.removeCallbacks(runnable);

当上述被调用时,Toast 停止显示,所以到目前为止一切都很好。当我离开我的活动去另一个活动时,toast 消息会继续显示,这就是我想要的,但是当我回到创建可运行对象的第一个活动并按下终止按钮时,它不会删除可运行对象。离开和回来时,我无法再删除 runnable。

我已经尝试使用几乎所有在 SO 上使用 Handlers 和 runnables 的示例,但没有什么能帮助我解决这个问题。

可能是当我离开我的 Activity 并返回它时,它会创建新的可运行对象和处理程序对象吗?如果是这样,为什么初始可运行文件会继续运行?

4

3 回答 3

2

在活动中保留长期引用是一种糟糕的形式。即使您旋转手机,它们也会很容易且经常被破坏和重新创建!发生的事情是,当重新创建 Activity 时,会创建一个新的 Runnable 和 Handler 对象,正如您所怀疑的那样。

为了在不求助于服务的情况下解决这个问题,我所做的是创建一个片段……我们称之为 StateFragment。

不给这个 Fragment 任何视图,所以它对用户是不可见的。它仅用于存储变量。创建活动后,如果活动尚不存在,请将其添加到活动中。最后,在Fragment 类本身中,在其onCreate 中,将RetainInstance 设置为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.



  }
}

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

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
于 2013-12-02T12:36:36.210 回答
1

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

于 2013-03-22T18:04:40.193 回答
1

尝试以下操作,它使用一个计时器类来显示你Toast每 5 秒从你的类启动 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();

                    }
            }
于 2013-03-23T01:57:11.990 回答