【问题标题】:Leak : Timer and TextWatcher泄漏:计时器和 TextWatcher
【发布时间】:2016-10-21 18:49:33
【问题描述】:

我正在开发一个editText 和一个recyclerView。 当我在 EditText 中写信时,我的 recyclerView 会更新。

我在 textWatcher 中放置了一个 Timer,以避免每次用户写信时都发送请求。

searchDestinationEt.addTextChangedListener(new TextWatcher() {
        @Override
        public void beforeTextChanged(final CharSequence s, final int start, final int count, final int after) {
            //There is nothing to do here
        }

        @Override
        public void onTextChanged(final CharSequence s, final int start, final int before, final int count) {
            if (timer != null) {
                timer.cancel();
            }
        }

        @Override
        public void afterTextChanged(final Editable s) {

            timer = new Timer();

            //we schedule this in order to avoid sending useless request.
            //We wait the user is finishing writing before sending requests
            timer.schedule(new TimerTask() {
                @Override
                public void run() {
                    ((Activity) context).runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            actionsListener.onDestinationSearch(s.toString());
                        }
                    });
                }
            }, DELAY_SEND_REQUEST);
        }
    });

它工作得很好,但leakcanary 说我在这部分代码中有泄漏。 有什么想法吗?

【问题讨论】:

标签: android memory-leaks timer textwatcher


【解决方案1】:
  1. 为什么您使用TimerTimerTask 进行延迟而不是重复的操作?最简单常用的方法是使用普通的HandlerpostDelayed()

    new Handler().postDelayed(new Runnable() {
        @Override
        public void run() {
           //do somthing here
        }
    }, DELAY_SEND_REQUEST);
    
  2. 发生泄漏是因为您正在启动一个引用您的上下文(片段或活动)的线程。在你的线程完成之前 - 它不会被垃圾收集。

这意味着,例如,如果用户键入内容并且您正在等待开始请求的时间,同时用户转动手机并发生方向更改 - 您的活动/片段将被重新创建 - 但旧的 (它启动了一个线程并且应该在线程完成时使用)没有消失并且仍然存在于内存中。

  1. 为什么要在 UI 线程上发出请求?它会阻止用户界面,你知道吗?我认为AsyncTask 可能更合适。

你应该怎么做? 将 Timer 替换为 Handler 并在工作线程中执行请求。关于泄漏,您有 2 个选项:

a) 什么都不做,因为您的活动/片段将被保留的时间非常短,并且在请求完成后将被 GCed。 (不推荐)

b) 利用 AsyncTask 并在 AsyncTask 的构造函数中传递上下文(您的侦听器)并将其存储为弱引用对象,如下所示:

private static class SomeWorkTask extends AsyncTask<Void,Void,Void>{

    private WeakReference<ActionsListenerWithContext> weakListener;

    public SomeWorkTask(ActionsListenerWithContext listener){
        this.weakListener = new WeakReference<>(listener);
    }

    @Override
    protected Void doInBackground(Void... voids) {
        //do some work here
        return null;
    }

    @Override
    protected void onPostExecute(Void aVoid) {
        if(weakListener.get() != null){
            weakListener.get().callYourCallbacks();
        }
    }
}

然后你就叫它

 new SomeWorkTask(listener).execute();

使用WeakReference 包装器是一种常见且推荐的做法。

【讨论】:

    【解决方案2】:

    很抱歉回复晚了,但是您是否尝试过像这样分隔 textwatcher ?: TextWatcher for more than one EditText

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-07-11
      • 2011-11-02
      • 1970-01-01
      • 2011-12-06
      • 2011-06-18
      相关资源
      最近更新 更多