How to avoid Runnable callback leak?

1k views Asked by At

I have codes below that will execute a callback from another thread when I finish the activity. So how to avoid to call the callback or the codes in the callback when the activity has been finished?

public static interface Callback{
    public void onCallback();
}

class ActivityA {
    TextView tv = ...;
    Handler handler = ...;
    public void onClick(View v) {
        Business.callThread(new Callback() {

            @Override
            public void onCallback() {
                handler.post(new Runnable(){
                    public void run(){
                        tv.setText("xxxx");
                    }
                });
            }
        });
    }
}

class Business {
    public static void callThread(final Callback listener) {
        new Thread(new Runnable() {

            @Override
            public void run() {
                try {
                    Thread.sleep(5000); //sleep 5s;
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                listener.onCallback();
            }
        }).start();
    }
}
1

There are 1 answers

8
R. Zagórski On

Garbage collector counts references to objects. However, there are couple of reference types. Useful in your case is WeakReference:

Weak reference objects, which do not prevent their referents from being made finalizable, finalized, and then reclaimed.

Create runnable as a class with constructor:

static class CallbackRunnable implements Runnable {
    WeakReference<Callback> listener;

    public CallbackRunnable(Callback listener) {
        this.listener = new WeakReference<Callback>(listener);
    }

    @Override
    public void run() {
        try {
            Thread.sleep(5000); //sleep 5s;
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        if (listener.get() == null) {
            return;
        }
        listener.get().onCallback();
    }
}

then call listener like:

if (listener.get() == null) {
    return;
}
listener.get().onCallback();

callThread method implementation:

public static void callThread(final Callback listener) {
    new Thread(new CallbackRunnable(listener)).start();
}