Search code examples
androidandroid-studiofragmenthandler

Android Studio - How to stop handler.postDelayed from a fragment?


Description:

Investigating for a while, I came to find next line code:

handler.removeCallbacksAndMessages(null);

I've tried it and it couldn't solve my problem. This is the error I get:

java.lang.IllegalStateException: Fragment fragment_languages{f33796} not attached to a context.
at androidx.fragment.app.Fragment.requireContext(Fragment.java:696)
    at androidx.fragment.app.Fragment.getResources(Fragment.java:760)
    at com.example.ui.INICIO.CATEGORIAS.LANGUAGES.fragment_languages.fillRecycler4(fragment_languages.java:173)
    at com.example.ui.INICIO.CATEGORIAS.LANGUAGES.fragment_languages.access$200(fragment_languages.java:21)
    at com.example.ui.INICIO.CATEGORIAS.LANGUAGES.fragment_languages$3.run(fragment_languages.java:61)
    at android.os.Handler.handleCallback(Handler.java:789)
    at android.os.Handler.dispatchMessage(Handler.java:98)
    at android.os.Looper.loop(Looper.java:164)
    at android.app.ActivityThread.main(ActivityThread.java:6694)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:769)

I am calling three handlers that loads items into three different recycler views and at different times (this is because, if i load them without waiting, app crashes for using so much memory or something like that).

Problem:

A "troll" user can just get into my app,then get into this fragment in which I have my 4 handlers and press back button once he gets in and this will crash my app too. That's why I want to stop handlers (when pressing back button).

What can I do to repair this error?

What you need to know:

My fragment with handlers is inside an activity (of course). The back button is in the activity (not in the fragment).

"Fragment languages" JAVA code:

father p = new father();

fillRecycler1();

    p.handler.postDelayed(new Runnable() {
        @Override
        public void run() {
            fillRecycler2();
        }
    },1500);

    p.handler.postDelayed(new Runnable() {
        @Override
        public void run() {
            fillRecycler3();
        }
    },2500);

    p.handler.postDelayed(new Runnable() {
        @Override
        public void run() {
            fillRecycler4();
        }
    },3500);

Activity (with back button) Code:

@Override
public void onBackPressed(){
    if(p.contador == 0){
        Intent intent = new Intent(categorias.this, MainActivity.class);
        finish();
        startActivity(intent);

        p.handler.removeCallbacksAndMessages(null);

        p.contador++;

        p.handler.postDelayed(new Runnable(){
            @Override
            public void run(){
                p.contador = 0;
            }
        },500);
    }
}

Edit (father class java code):

public class father{

public int contador = 0;
public String aux = null;

public Handler handler = new Handler();

public Window window;

}

Solution

  • You can just skip method call if fragment's view is destroyed (fragment destroyed or it is in backstack). There is getView() method

    handler.postDelayed(new Runnable() {
        @Override
        public void run() {
            if(getView() != null){
                fillRecycler2();
            }
        }
    },1500);
    

    If you use hide/show methods of FragmentTransaction you can use isVisible() method of Fragment, because hidden fragments view is View.GONE (not null)