0

So I have a Thread 'ThreadDemo' in a Fragment which does some calculations and uses getActivity().runOnUiThread() to update a TextView. It works fine but when I exit the application, it gives NPE on getActivity(). From what I know about threads in android, they should be stopped when Activity is destroyed but here, for some reason, it continues and is unable to find the activity as i have closed it. Here is my Thread code inside my Fragment-

 public class ThreadDemo implements Runnable {


           int hour, minute, second, day=0;


           public void run() {
               while((196-day)>=0) {

                   Calendar cal = Calendar.getInstance();
                    day = cal.get(Calendar.DAY_OF_YEAR);
                    hour = cal.get(Calendar.HOUR_OF_DAY);
                    minute = cal.get(Calendar.MINUTE);
                    second = cal.get(Calendar.SECOND);

                    try {
**NPE here**             getActivity().runOnUiThread(new Runnable() {

                            @Override
                            public void run() {
                                ....
                            }
                        });
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }                   
              }
           }


        } 

and here is the LogCat-

06-07 12:05:28.903: E/AndroidRuntime(19834): FATAL EXCEPTION: Thread-5858
06-07 12:05:28.903: E/AndroidRuntime(19834): java.lang.NullPointerException
06-07 12:05:28.903: E/AndroidRuntime(19834):    at com.example.mapsapiv2demo.Fragment3$ThreadDemo.run(Fragment3.java:59)
06-07 12:05:28.903: E/AndroidRuntime(19834):    at java.lang.Thread.run(Thread.java:856)

NOTE: I tried to manually stop the thread in onPause method but it seems like stop() method is deprecated for threads and is not recommended. Know what I'm doing wrong or any suggestions for a workaround? I'm aware of something like asynctask but I'm a beginner so I would like to avoid that for now. Thanks for your help.

Chintan Trivedi
  • 748
  • 1
  • 8
  • 21

3 Answers3

0

Simply make a check inside your loop:

if(shouldStop) {
    break;
}
Warpzit
  • 27,966
  • 19
  • 103
  • 155
  • Thanks @Warpzit, I tried to check if activity is destroyed or not by getactivity().isDestroyed() but turns out it requires minimum api level 17 and mine is 11. Please do clarify if you meant something else or I'm doing something wrong in checking. – Chintan Trivedi Jun 07 '13 at 07:03
  • Override onDestroy() in your activity, set a flag on your thread and check against it. See my answer for an example – britzl Jun 07 '13 at 07:07
0

Stopping a thread is not as trivial as it may seem. Read more here. I would recommend that you set a flag in your thread when the activity is destroyed and check against this flag if you should break out of the loop in the thread. Example:

public class YourActivity extends Activity {

    private YourThread thread;

    @Override
    public void onStop() {
        super.onStop();
        thread.stopNow();
    }   
}

public class YourThread extends Thread {

    private boolean stopNow = false;

    public void stopNow() {
        stopNow = true;
    }

    public void run() {
        while(someCondition && !stopNow) {
            // do something
            if(!stopNow) {
                getActivity().runOnUiThread(...)
            }
        }
    }

}

You could also take a look at switching to a AsyncTask, call cancel() on it and in your loop in doInBackground() check isCancelled().

Community
  • 1
  • 1
britzl
  • 10,132
  • 7
  • 41
  • 38
  • Nice idea, it works properly now. But why do i need to manually stop a thread? I thought threads were stopped on destroying the activity that starts it and that's one of the differences between a service and a thread. – Chintan Trivedi Jun 07 '13 at 07:15
  • 1
    @user2328317 that is ok, but please use onStop() instead of onDestroy(). onDestroy is only called when system is low on cpu/memory while onStop is used every time the activity is closed. See more here: http://stackoverflow.com/a/4449988/969325 – Warpzit Jun 07 '13 at 07:20
  • Warpzit is correct. It was all that talk about destroy that made me use onDestroy()=. onStop() is the correct place in the activity – britzl Jun 07 '13 at 07:29
  • Btw, where did you read that threads are stopped when the activity is destroyed. I've never heard of this, and frankly, it doesn't make sense. – britzl Jun 07 '13 at 07:31
  • Learned a new thing today then, thanks. I have now been able to stop my thread successfully by using britzl's advice, but I've used onPause since it's a fragment and I don't want it to run when the fragment is not on screen. – Chintan Trivedi Jun 07 '13 at 07:46
0

Activity

 private Thread thread;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        thread = new Thread(new ThreadDemo());
        thread.start();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        thread.interrupt();
    }

Runnable

class ThreadDemo implements Runnable {


        int hour, minute, second, day = 0;


        public void run() {
            while ((196 - day) >= 0 && !Thread.currentThread().isInterrupted()) {

                Calendar cal = Calendar.getInstance();
                day = cal.get(Calendar.DAY_OF_YEAR);
                hour = cal.get(Calendar.HOUR_OF_DAY);
                minute = cal.get(Calendar.MINUTE);
                second = cal.get(Calendar.SECOND);

                try {
                    getActivity().runOnUiThread(new Runnable() {

                        @Override
                        public void run() {

                        }
                    });
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                    Thread.currentThread().interrupt();
                }
            }
        }


    }
Jiang Qi
  • 4,450
  • 3
  • 19
  • 19