【问题标题】:Stop handler after the fragment has been destroyed片段被销毁后停止处理程序
【发布时间】:2015-06-28 17:14:30
【问题描述】:

我有一个Fragment,它设置一个ListView 并创建一个Handler 以定期更新Listview。但是,看起来HandlerFragment 被销毁后仍在运行。

以下是代码。

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {

    //boilerplate code

    final Handler handler = new Handler();
    handler.post(new Runnable() {
        @Override
        public void run() {
            assignAdapter();
            handler.postDelayed(this, 15000);
        }
    });

    return v;
}

Fragment 销毁后更新ListView 会导致应用程序崩溃。当Fragment 被破坏时,如何使Handler 停止?我也想知道如果应用暂停对Handler 有什么影响。

【问题讨论】:

    标签: android listview android-fragments android-lifecycle fragment-lifecycle


    【解决方案1】:

    你需要像这样实现处理程序

    private Handler myHandler;
    private Runnable myRunnable = new Runnable() {
        @Override
        public void run() {
            //Do Something
        }
    };
    
    @Override
    public void onDestroy () {
    
        mHandler.removeCallbacks(myRunnable);
        super.onDestroy ();
    
    }
    

    【讨论】:

      【解决方案2】:

      您需要在片段中存储对您的处理程序和可运行的引用,然后当片段被销毁时,您需要从可运行的处理程序中删除回调。

      private Handler mHandler;
      private Runnable mRunnable;
      
      @Override
      public View onCreateView(LayoutInflater inflater, ViewGroup container,
                               Bundle savedInstanceState) {
      
          //boilerplate code
      
          mRunnable = new Runnable() {
              @Override
              public void run() {
                  assignAdapter();
                  handler.postDelayed(this, 15000);
              }
          };
      
          mHandler = new Handler(mRunnable);
          mHandler.post();
      
          return v;
      }
      
      @Override
      public void onDestroy() {
          mHandler.removeCallbacks(mRunnable);
          super.onDestroy();
      }
      

      【讨论】:

      • 我放在onDetach()中。
      • 实施已被超时更改,但仍然有效。您只需将其更改为 handler = new Handler(); handler.post(runnable);
      【解决方案3】:

      另一种停止处理程序的方法是使用WeakReference 到片段:

      static final class UpdateUIRunnable implements Runnable {
      
              final WeakReference<RouteGuideFragment> weakRefToParent;
              final Handler handler;
      
              public UpdateUIRunnable(RouteGuideFragment fragment, Handler handler) {
                  weakRefToParent = new WeakReference<RouteGuideFragment>(fragment);
                  this.handler = handler;
              }
      
              public void scheduleNextRun() {
                  handler.postDelayed(this, INTERVAL_TO_REDRAW_UI);
              }
      
              @Override
              public void run() {
                  RouteGuideFragment fragment = weakRefToParent.get();
      
                  if (fragment == null || fragment.hasBeenDestroyed()) {
                      Log.d("UIUpdateRunnable", "Killing updater -> fragment has been destroyed.");
                      return;
                  }
      
                  if (fragment.adapter != null) {
                      try {
                          fragment.adapter.forceUpdate();
                      } finally {
                          // schedule again
                          this.scheduleNextRun();
                      }
                  }
              }
          }
      

      其中fragment.hasBeenDestroyed() 只是片段的mDestroyed 属性的getter:

      @Override
      public void onDestroy() {
          super.onDestroy();
          mDestroyed = true;
      }
      

      【讨论】:

      • 这是在更新视图时避免 NPE 错误的有效方法 :) 干得好
      【解决方案4】:

      有人发布了另一个类似的问题,问题是由于ChildFragmentManager 中的错误引起的。基本上,当ChildFragmentManagerActivity 分离时,它的内部状态会中断。看看original answer here

      【讨论】:

        【解决方案5】:

        使用Rxjava,更好

        subscription = Observable.timer(1000, TimeUnit.MILLISECONDS)
                    .subscribeOn(Schedulers.io())
                    .observeOn(AndroidSchedulers.mainThread())
                    .subscribe(aLong -> whatToDo());
        
        private void whatToDo() {
           System.out.println("Called after 1 second");
        }
        

        然后在ondestroy()方法调用

        RxUtils.unsubscribe(subscription);
        

        【讨论】:

        • 如何更好?你需要详细说明
        • @RodolfoAbarca Rxjava 提供了许多内置函数,如 skip、subscribeOn、observeOn 和许多其他可能被证明有用的函数,因此它更好。请检查 Rxjava。
        猜你喜欢
        • 1970-01-01
        • 2012-03-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-05-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多