泄漏:计时器和文本观看器



我正在从事EditText和RecyClerview的工作。当我用dedittext编写字母时,我的回收库已更新。

我将计时器放入文本观看器中,以避免每次用户写信时发送请求。

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的一个以上的iDittext

  1. 为什么使用TimerTimerTask进行延迟而不是重复的动作?最简单的方法是仅使用postDelayed()的常规Handler

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

这意味着,例如,如果用户键入某些内容,并且您正在等待一段时间开始请求,并且用户转动电话和方向更改会发生 - 您的活动/片段将被重新创建 - 但是旧的(启动线程并在完成线程后应使用的)未消失,并且仍然存在于内存中。

  1. 为什么在UI线程上执行请求?它阻止了UI,您知道吗?我认为AsyncTask可能更合适。

你该怎么办?用处理程序替换计时器,然后在工作线程中执行请求。关于泄漏您有2个选项:

a)什么都不做,因为保留您的活动/片段的时间很小,并且在请求完成后将被gced。(不建议)

b)使用异步和在异步的构造函数中,通过上下文(您的侦听器)并将其存储为弱参考对象,例如:

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包装器是一种常见且推荐的做法。

最新更新