Android 泄漏:计时器和文本监视程序

Android 泄漏:计时器和文本监视程序,android,memory-leaks,timer,textwatcher,Android,Memory Leaks,Timer,Textwatcher,我正在做一个editText和一个recyclerView。 当我在编辑文本中写信时,我的recyclerView会更新 我在textWatcher中设置了一个计时器,以避免每次用户写信时都发送请求 searchDestinationEt.addTextChangedListener(new TextWatcher() { @Override public void beforeTextChanged(final CharSequence s, final int

我正在做一个editText和一个recyclerView。 当我在编辑文本中写信时,我的recyclerView会更新

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

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说我在这部分代码中有漏洞。
有什么想法吗?

很抱歉回复晚了,但您是否尝试过这样分离textwatcher

  • 为什么要使用
    Timer
    TimerTask
    进行延迟而非重复的操作?最简单也是最常见的方法是只使用常规的
    处理程序
    postDelayed()

  • 发生泄漏是因为您正在启动一个引用了您的上下文(片段或活动)的线程。在线程完成之前,它不会被垃圾收集

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

  • 为什么要在UI线程上执行请求?它会阻塞用户界面,你知道吗?我认为
    AsyncTask
    可能更合适
  • 你该怎么办? 将计时器替换为处理程序,并在工作线程中执行请求。关于泄漏,您有两种选择:

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

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

    @oiZo Thx,我会试试的。但这并不能解释为什么会有泄漏:/。
    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();