0

I have previously had my App working with just activities and am now working on converting to fragments in order to improve the UI.

Previously my Activity started an AsyncTask and passed in itself to be used as the Context when certain methods required it (not UI operations, but calls to shared preferences and content providers). I have now learnt that this approach can lead to undesirable outcomes if the Activity is destroyed and garbage collected, but it did compile and run fine.

I began this change because I wanted to make my loading screen behave better when the app was paused and stopped. I realised people frown on loading screens in Android but for me it is required as I have an operation that will take 20 seconds or so and that needs to be completed before the app will function.

So using this guide, I began improving my app.

In short the guide moves the AsyncTask into a Fragment that does not have an attached UI, with a separate Fragment for displaying the loading screen with ProgressBar. This means that the Fragment that spawns the AsyncTask does not have a Context, meaning I cant pass one in to the AsyncTask.

As I said before I have operations in the AsyncTask that require a Context object, so where can I get it from? Should I just pass in that data to the AsyncTask before I start?

James Ferretti
  • 171
  • 2
  • 15
  • The guide you link to handles this by passing the Activity in as a custom `ProgressListener` interface. Why can't you do the same? – Geobits Jul 18 '13 at 15:32

2 Answers2

2

As far as I know, the context is not a static property, so you actually need one object to retrieve it.

Thus, you can either go the "hack-way" as in this post:

Static way to get 'Context' on Android?

or you can follow Android guidelines and use a Service for your background loading. Remember that AsyncTask is an utility class designed to help in background operations that later need to communicate with the UI, so you should use AsyncTask in correlation with a UI object. If you, instead use a Service, then you got no problem, since the Service object itself is the context that you need.

Community
  • 1
  • 1
type-a1pha
  • 1,891
  • 13
  • 19
  • Great, I will create another service for this task. Although I now have a total of 7 services which seems excessive but I suppose thats another issue. – James Ferretti Jul 18 '13 at 15:28
  • If it is a problem you can merge them into a single Service and use a value in the intent's bundle to describe the action to do in the service. I forgot to mention...since you were using AsyncTask, maybe you want to give IntentService a try. It is the framework implementation of a Service which uses an AsyncTask as its worker thread. – type-a1pha Jul 18 '13 at 15:39
  • Having looked at this the same problem arises, assuming I want to start the service from the non-UI fragment I still need a context from which to create the Intent, as it is required in the constructor. Unless I can use one of the other intent constructors? – James Ferretti Jul 18 '13 at 16:39
  • Ok...can you explain better why you can't use Fragment.getActivity()? The Fragment that starts the AsyncTask/Service has to be attached to an Activity or a ContextWrapper object! – type-a1pha Jul 18 '13 at 16:47
  • This fragment is a non-UI fragment, that is it has no view and is not displayed. Read more about that [here](http://developer.android.com/guide/components/fragments.html#Adding) , scroll down to "Adding a fragment without a UI". Calling `getActivity()` returns null in this fragment. My next plan is to explicitly set the context when I instantiate the `Fragment` in my main activity. e.g.: `mInitFragment = new InitializeFragment(); mInitFragment.setProgressListener(this); mInitFragment.setContext(this); mInitFragment.startLoading();` – James Ferretti Jul 18 '13 at 16:55
  • It may also be sensible to pass in global context here? – James Ferretti Jul 18 '13 at 16:56
  • Then, since it has no UI, shouldn't you use a Service INSTEAD of a Fragment. There is a particular reason you want to use a Fragment as a mere background worker? You need a synchronized lifecycle? Either way, if you still want to use the Fragment, passing the activity is probably the easiest solution. – type-a1pha Jul 18 '13 at 17:03
0

If your AsyncTask is not handling any UI components you can use the parent Activity's context. So where you previously passed in this you'll now pass in getActivity(). Note, if you do have it changing the ui this will set you up for Null Pointer Exceptions.

adonal3
  • 268
  • 2
  • 8