Home » Android » Why is my getActivity() null in this situation?

Why is my getActivity() null in this situation?

Posted by: admin November 1, 2017 Leave a comment

Questions:

I do not understand why my getActivity() that is around my runonUiThread is coming back null. Below is the code for where I am having the problem. I think it has something to do with where I place my onAttach method but I am not sure. Also please ingore all the comments as I will clean my code when this bug is fixed. Also note this is the java code for a fragment. Thank you.

 public void onAttach(Context context){
           super.onAttach(context);
           Activity a;
          if(context instanceof Activity)
          {
              a=(Activity) context;
          }

     }
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        // Inflate the layout for this fragment



        super.onActivityCreated(savedInstanceState);
        //setCont(R.layout.fragment_level_one);
       // return inflater.inflate(R.layout.fragment_level_one,container, false);

        View view = inflater.inflate(R.layout.fragment_level_one, container, false);

        //creating viewables and such
        viewer = (ViewGroup) view.findViewById(R.id.view_level);
        img = (ImageView) view.findViewById(R.id.imageView);
        failButton = (Button) view.findViewById(R.id.failureButton);
        countDownMain = (TextView) view.findViewById(R.id.countDownMain);
        countDownBeginText = (TextView) view.findViewById(R.id.countDownBeginText);
        beginButton = (Button) view.findViewById(R.id.beginButton);

        /*if (view != null) {
            ViewGroup parent = (ViewGroup) view.getParent();
            if (parent != null) {
                parent.removeView(view);
            }
        }
        try {
            view = inflater.inflate(R.layout.fragment_level_one, container, false);
        } catch (InflateException e) {

        }*/

        RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(150, 150);
        img.setLayoutParams(layoutParams);
        img.setOnTouchListener(new LevelOneFragment.ChoiceTouchListener());

        //begin random movement
        if(isAdded()) {
            startRandomButton(img);
        }
        else
        {
            Log.d("line 98 is", " is null");
        }

        //setting up button for failure CORRECT TO TAKE YOU TO THE MAIN MENU
        failButton.setOnClickListener(new View.OnClickListener(){
            public void onClick(View v){
                startActivity(new Intent(getActivity(), MainMenu.class));
            }
        });

        //setting countdown text to 3
        countDownBeginText.setText(":3");

        //begin countdown from three
        beginButton.setOnClickListener(new View.OnClickListener(){
            public void onClick(View beginT) {
                CountDownTimer countDownTimer = new CountDownTimer(3*1000, 3) {
                    @Override
                    public void onTick(long millisUntilFinished) {

                        countDownBeginText.setText(":" + millisUntilFinished/1000);
                        //add possible sound here every tick
                    }

                    @Override
                    public void onFinish() {
                        beginButton.setVisibility(View.INVISIBLE);
                        countDownBeginText.setVisibility(View.INVISIBLE);

                        //countdown from 60------- change parameters in count down timer to the time desired
                        CountDownTimer countDownTimer = new CountDownTimer(60*1000, 3) {
                            @Override
                            public void onTick(long millisUntilFinishedMain) {

                                countDownMain.setText(":" + millisUntilFinishedMain/1000);
                                //add possible sound here every tick
                            }

                            @Override
                            public void onFinish() {
                                Toast.makeText(getActivity(),"You lose", Toast.LENGTH_LONG).show();
                                //rest of text in method is trial

                                startActivity(new Intent(getActivity(), MainMenu.class ));

                            }
                        }.start();

                    }
                }.start();
            }
        });
        return view; //inflater.inflate(R.layout.fragment_level_one,container, false);
    }
    //getting screen size
    public static Point getDisplaySize(@NonNull Context context){

        Point point = new Point();
        WindowManager manager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
        manager.getDefaultDisplay().getSize(point);
        return point;
    }

    //randomly move
    public void randomMovement(ImageView img){
        //int   x = new Random().nextInt(getDisplaySize(getActivity()).x);
        //int   y = new Random().nextInt(getDisplaySize(getActivity()).y);

        if(isAdded()) {
            int   x = new Random().nextInt(getDisplaySize(getActivity()).x);
            int   y = new Random().nextInt(getDisplaySize(getActivity()).y);
            img.setY(y);
            img.setX(x);
        }
        else
            Log.d("Random mover is null", " is null");

    }

    //creating timer
    public void startRandomButton(final ImageView img){
        Timer timer = new Timer();
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                if(isAdded()){
                getActivity().runOnUiThread(new Runnable() { //best method in the entire world-- use when trying to update ui in the background
                   @Override
                    public void run() {
                        randomMovement(img);
                    }
                });}else{
                    Log.d("Fragment one", "Is null");}
            }
        }, 0, 5000);
    }

Below is my log cat the place I am getting that null reference is right inside my startRandomButton() method:

                                                                       [ 10-22 14:34:13.423 15104:15141 D/         ]
                                                                       SurfaceInterface::setAsyncMode: set async mode 1
10-22 14:34:13.429 15104-15141/name.inserttitlenameD/EGL_emulation: eglMakeCurrent: 0x9bb040c0: ver 3 0 (tinfo 0x9bb03290)
10-22 14:34:13.448 15104-15141/name.inserttitlename D/EGL_emulation: eglMakeCurrent: 0x9bb040c0: ver 3 0 (tinfo 0x9bb03290)
10-22 14:34:13.453 15104-15141/name.inserttitlename D/EGL_emulation: eglMakeCurrent: 0x9bb040c0: ver 3 0 (tinfo 0x9bb03290)
10-22 14:34:13.474 15104-15141/name.inserttitlename I/chatty: uid=10083(u0_a83) RenderThread identical 2 lines
10-22 14:34:15.124 15104-15141/name.inserttitlename D/EGL_emulation: eglMakeCurrent: 0x9bb040c0: ver 3 0 (tinfo 0x9bb03290)
10-22 14:34:17.606 15104-15141/name.inserttitlenameD/EGL_emulation: eglMakeCurrent: 0x9bb040c0: ver 3 0 (tinfo 0x9bb03290)
10-22 14:34:17.628 15104-15141/name.inserttitlename I/chatty: uid=10083(u0_a83) RenderThread identical 1 line
10-22 14:34:17.638 15104-15141/name.inserttitlename D/EGL_emulation: eglMakeCurrent: 0x9bb040c0: ver 3 0 (tinfo 0x9bb03290)
10-22 14:34:18.272 15104-15141/name.inserttitlename D/EGL_emulation: eglMakeCurrent: 0x9bb040c0: ver 3 0 (tinfo 0x9bb03290)
10-22 14:34:18.467 15104-15141/name.inserttitlename D/EGL_emulation: eglMakeCurrent: 0x9bb040c0: ver 3 0 (tinfo 0x9bb03290)
10-22 14:34:18.480 15104-15141/name.inserttitlename D/EGL_emulation: eglMakeCurrent: 0x9bb040c0: ver 3 0 (tinfo 0x9bb03290)
10-22 14:34:18.487 15104-15141/name.inserttitlename D/EGL_emulation: eglMakeCurrent: 0x9bb040c0: ver 3 0 (tinfo 0x9bb03290)
10-22 14:34:20.156 15104-16453/com.example.name.inserttitlename D/Fragment one: Is null
10-22 14:34:25.157 15104-16453/com.example.name.inserttitlename D/Fragment one: Is null
10-22 14:34:50.161 15104-16453/com.example.name.inserttitlename I/chatty: uid=10083(u0_a83) Timer-1 identical 5 lines

complete fragment.java

Answers:

First of all, I see you invoke super.onActivityCreated from onCreateView.

Second, isAdded() is false doesn’t mean getActivity() is null. There is also mAdded variable inside this method.

Third, if you have some timer, CountDownLatch – you should unsubscribe or stop it in either onStop or onDestroy callbacks to prevent memory leaks.

Forth, use Handler#postDelayed to post some action that should be done later on UI thread.

Questions:
Answers:

remove this line: super.onActivityCreated(savedInstanceState);. That line is not needed as you already defined the state of the fragment .hence the super class variant is not needed. Also do not get the context reference from onAttach, do it in onActivityCreated. Only that life cycle method garantees that the context is actually available.

Questions:
Answers:

Welcome to multithreading. First you check that fragment is added and its activity reference is not null (as getActivity().runOnUiThread was not crashed), then you are trying to call getActivity() again hoping it is not null still. But it can be perfectly modified in between, before you call getActivity() second time.

Working solution here would be to store the activity reference in WeakReference<Activity> then call its get() method to work with Activity checking that it does not become null.

Another solution would be to store getActivity() result into some variable, but that could lead to leaks, when removing the Activity is impossible.