0

I am working on an app in which i have two Fragments hosted in one Activity. The acitivity layout has a bottom bar which has buttons that switch the two fragments. In those fragments there are Threads that do some internet work and then update their layout.

Hieararchy:

  • Activity
    • Fragment 1
      • Thread 1
    • Fragment 2
      • Thread 2

The problem

The problem is that when, say Thread 1 starts doing some work, the user clicks the button to switch to Fragment 2, the Thread continues to run in the background, and when it is done with it's network task and tries to update the view (in the now not visible Fragment 1), the app crashes because getActivity() or getContext() now returns null.

EDIT: The thread uses getActivity() and getContext() a lot, not only for updating layout, but also for saving SharedPreferences, etc. I can add an inspection (if(!stopped) for example) to every line that uses Context, but i thought there is a better way than wrapping every step in an if condition.

So how do I kill either the Thread or Fragment completely? I don't need the background work running when the fragments are switched, I only need it to run when the fragment is visible.

I have tried both Thread.interrupt() and removing the fragment (instead of replacing) using getSupportFragmentManager.remove(Fragment fragment). Did not work.

Thanks in advance :)

  • So maybe check if `Fragment` is still visible or `getActivity() == null` before moving to the next part. – R. Zagórski Mar 06 '17 at 17:22
  • 1
    Are you by any chance catching the `InterruptException` inside the thread you're trying to terminate? – bbop99 Mar 06 '17 at 17:23
  • Ditto to what @Antonvb said, are you catching the interrupt exception and ignoring it? – Charlie Collins Mar 06 '17 at 17:25
  • Hello, i am only catching `InterruptedException` in certain parts of code where i need the thread to sleep. Eg.: `doWork; try{Thread.sleep(500);}catch(InterruptedException e){} doOtherWorkAfterSleeping();` – František Hlinka Mar 06 '17 at 17:52

1 Answers1

0

You may check in your thread whether getActivity() is null and in this case do not perform UI update. A better aprach would be to stop your download once a user switches to another fragment - how to do it depends on what HTTP client you are using. With HttpURLConnection it should suffice to call disconnect().

Instead of using Thread consider using AsyncTask which has support for being cancelled. For examples search SO, here is one: Ideal way to cancel an executing AsyncTask.

Community
  • 1
  • 1
marcinj
  • 48,511
  • 9
  • 79
  • 100
  • I would be wary of recommending AsyncTask, there are many well documented corner cases, and many better approaches, for example: http://blog.danlew.net/2014/06/21/the-hidden-pitfalls-of-asynctask/ – Charlie Collins Mar 06 '17 at 17:29
  • I agree, with AsyncTask you have to be carefull when rotating screen or when holding references, etc. – marcinj Mar 06 '17 at 17:42
  • Hello, thanks for advice, i don't want to use AsyncTask because i would need to check if it is canceled in every step, same problem. Please see the edit. – František Hlinka Mar 06 '17 at 17:49
  • @FrantišekHlinka I would advice you to do the checks. You say you update UI from your thread, you must then do it inside a handler on UI thread, because otherwise you would get exceptions. So all you have to do is to add a check ie. if (getActivity == null) return; at the top of this handler. Probaby, in the end you will reproduce AsyncTask, whether you like it or not. – marcinj Mar 06 '17 at 17:59
  • Why can't the download continue when the view is switched, and the UI updates be queued up for the next refresh (I would probably use a thread lock during view creation/restoration (onCreate/onResume) and do conditional view updates based on it's value or something. – samus Mar 06 '17 at 20:15