AsyncTask runs on each page of the ViewPager - android

I have 3 Tabs like in the android development tutorial
Now what I want to do is very simple I use Fragments on each page. I want to show different content from a rss feed on each page.
The problem is when I go to the next tab it runs AsyncTask (which is in onCreateView) of the previous Fragment.
So you start on Page 1 it loads the content fine. Then when you go to Page 2 is runs the onCreateView of the Fragment of Page 1 again. And obviously gives an NullException. The point is it should not be running AsyncTask of Page 1 at all at that Page 2.
I don't think there is any example code needed if so tell me which part you need to see. Then I will edit my question.
AsyncTask inside a ListFragment :
public class MyAsyncTask extends AsyncTask<List<String>, Void, List<String>>
{
// List of messages of the rss feed
private List<Message> messages;
private volatile boolean running = true;
#SuppressWarnings("unused")
private WeakReference<NieuwsSectionFragment> fragmentWeakRef;
private MyAsyncTask(NieuwsSectionFragment fragment)
{
this.fragmentWeakRef = new WeakReference<NieuwsSectionFragment>(fragment);
}
#Override
protected void onPreExecute()
{
super.onPreExecute();
mProgress.show();
// progress.setVisibility(View.VISIBLE); //<< set here
}
#Override
protected void onCancelled()
{
Log.w("onCancelled", "now cancelled");
running = false;
}
#Override
protected List<String> doInBackground(List<String>... urls)
{
FeedParser parser = FeedParserFactory.getParser();
messages = parser.parse();
List<String> titles = new ArrayList<String>(messages.size());
for (Message msg : messages)
{
titles.add(msg.getTitle());
// Log.w("doInBackground", msg.getTitle());
}
return titles;
}
#Override
protected void onPostExecute(List<String> result)
{
super.onPostExecute(result);
mProgress.dismiss();
if (result != null)
{
PostData data = null;
listData = new PostData[result.size()];
for (int i = 0; i < result.size(); i++)
{
data = new PostData();
data.postTitle = result.get(i);
data.postThumbUrl = "http://igo.nl/foto/app_thumb/28991-Taxi-vast-na-poging-tot-nemen-van-sluiproute.jpg";
listData[i] = data;
Log.w("onPostExecute", "" + listData[i].postTitle);
}
adapter = new PostItemAdapter (getActivity(), android.R.layout.simple_list_item_1, listData);
setListAdapter(adapter);
adapter.notifyDataSetChanged();
}
}
}
It's called inside a method and that method is executed inside the onCreateView of the ListFragment :
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
startNewAsyncTask();
View rootView = inflater.inflate(R.layout.fragment_section_nieuws, container, false);
return rootView;
}
#SuppressWarnings("unchecked")
public void startNewAsyncTask()
{
MyAsyncTask asyncTask = new MyAsyncTask(this);
this.asyncTaskWeakRef = new WeakReference<MyAsyncTask>(asyncTask);
asyncTask.execute();
}
The LogCat :

Try using isAdded() before onPostExecute(). isAdded() returns true if the fragment is currently added to its activity.
http://developer.android.com/reference/android/app/Fragment.html#isAdded()
#Override
protected void postExecute(){
if(isAdded()){
//perform Display Changes
}
}

Move your
startNewAsyncTask();
to onActivityCreated()

I'm assuming your using FragmentPagerAdapter with your ViewPager.
To enable smooth animations, the ViewPager by default keeps the current fragment and the two neighbors in resumed state. So onCreateView is not the best place to start the AsyncTask.
Instead you need to create a custom listener interface. The fragments in the ViewPager should implement it, and call the new interface from the ViewPager's OnPageChangeListener.
Check out my answer to this question or you can read the whole tutorial here.

You're getting that exception because you're calling getActivity() too early. You should do it after onActivityCreated() (see this diagram)
Executing of onCreateView() in background is fine and actually is default behaviour. The thing is, ViewPager is optimised to load a content of neighbour non-visible pages in background to improve UX. You can do this:
mViewPager.setOffscreenPageLimit(2); (default value is 1) to load all 3 pages at once (1 is loading as currently visible and other 2 as optimisation). Or set it to 0 to disable this behaviour, but it's not the best idea.
In general, you should cash your loaded data and do not load it again by making your fragment's lifecycle methods as light as possible. Page limit of 2 is fine for 3 pages, but if you'll have for example 10 pages, limit of 9 is too much.

If I've understood your question right, I think you need unique content with each Fragment right?
Try using the varible arguments of the execute method. For example:
yourTask.execute(<some-unique-URL>, parameter, one-more-parameter);
In this way you can pass a unique URL per fragment form which you can get your content.
I feel you already have this. The doInBackground method has the List of URLs. You just need to pass that information in the execute method and utilize it in doInBackground.
Hope this helps!

It is normal that it runs the AsyncTask from the adjacent Fragments, since the ViewPager + PagerAdapter combo, works loading the current, previous and next Fragment.
You should focus the problem not to stop AsyncTask from running, but to let it run w/o throwing a NullPointerException.
The following should be called inside onCreateView()
adapter = new PostItemAdapter (getActivity(), android.R.layout.simple_list_item_1, myList);
setListAdapter(adapter);
And then, onPostExecute()
myList.clear();
myList.addAll(listData);
adapter.notifyDataSetChanged();

The ViewPager will create views for fragments in adjacent pages and destroy views for fragments which are not adjacent to current page. Thus, the onCreateView of page 1 will get called if you navigate from page1->page2->page3->page2. You can have the viewpager keep more pages in memory by using ViewPager.setOffscreenPageLimit.
The fragmentPagerAdapter retains the fragment objects. Only the views are destroyed. Thus, when viewpage recreates page1's view, the fragment object is the same. Hence, all the fields in the fragment will get retained.
As in most applications where there's no realtime data, it is not required not load the data every time the view of the fragment is created, you can store the data in the fragment object after loading. Then, before starting the AsyncTask in onCreateView/onActivityCreated, check if the data has been previously loaded or not.
class PageFragment {
private List<String> mData;
...
void onActivityCreated() {
if (data == null) { // OR if the data is expired
startAsyncTask();
} else {
updateViews();
}
}
void updateViews() {
// Display mData in views
}
class LoadDataTask extends AsyncTask<List<String>, ..., ...> {
...
void onPostExecute(List<String> result) {
PageFragment.this.mData = result;
PageFragment.this.updateViews();
}
}
I recommend that you use loaders for loading data for a fragment. For your purpose, you can configure a loader to load data only once.
This is a great tutorial on Loaders.
http://www.androiddesignpatterns.com/2012/07/loaders-and-loadermanager-background.html
In the tutorial, the loader is configured to return previous data immediately if available, and then fetch data in background and return it after fetching completes. Thus, the UI will get updated after fresh data gets downloaded but at the same time, it will show the previous data initially while the download happens.

You can use another activity - this activity will run asynctask and then move to your fragment related activity. In this way it should call only once.
In case you need to update Fragment UI using this AsyncTask then use a static method to call through AsyncTask.

Related

Wait for event when fragments fully initialized in FragmentPagerAdapter to setup them with data

I have an activity with collapsing AppBarLayout. In onCreate() method I am sending request to server to get some data. And depending what data I get - I need to dynamically in runtime choose what view to show to the user: 1. MyFragment1; or 2. TabLayout/ViewPager with FragmentPagerAdapter, which has two fragments in it. And I need to set some data to that fragments. But the issue is in next: I already have data and set it to fragments in my adapter, but fragment method onCreate is not yet called, and my layout is not initialized. That's how I get crash on populating data into layout view. So, how can I make somehow - fragment created and initialized it's fields first and only then setup it with data? Thanks.
private MenuFragment1 menu1Fragment1;
private MenuFragment3 menu1Fragment3;
private TabMenuAdapter adapter;
private void setupViewPager(ViewPager viewPager) {
menu1Fragment1 = new MenuFragment1();
menu1Fragment3 = new MenuFragment3();
adapter = new TabMenuAdapter(getSupportFragmentManager());
adapter.addFragment(menu1Fragment1, "Menu 1");
adapter.addFragment(menu1Fragment3, "Menu 2");
viewPager.setAdapter(adapter);
}
public onDataLoaded(String data)
{
//at this point, fragment is created, but it's View fields are NULL!!
menu1Fragment1.data = data;
}
#Layout(id = R.layout.content_shop_final)
public class ShopFinalTermsFragment extends BaseFragment {
private static final String SANS_SERIF_FAMILY_NAME = "sans-serif";
private static final String SANS_SERIF_MEDIUM_FAMILY_NAME = "sans-serif-medium";
private InfoModel InfoModel;
private RateModel RateModel;
#BindView(R.id.shop_final_nested_scroll_view)
NestedScrollView nestedScrollView;
#BindView(R.id.shop_final_pending_txt)
TextView pendingDurationTxt;
#BindView(R.id.shop_final_rate_cond_rv)
RecyclerView rateCondRv;
#BindView(R.id.shop_final_description_txt)
TextView descriptionTxt;
#Inject
ToolsManager toolsManager;
RateConditionsAdapter adapter;
private String getParams;
public static ShopFinalTermsFragment newInstance(String getParams, InfoModel shopInfoModel, RateModel RateModel) {
ShopFinalTermsFragment fragment = new ShopFinalTermsFragment();
Bundle args = new Bundle();
args.putString(SHOP_GET_PARAMS, shopGetParams);
args.putSerializable(INFO_MODEL_KEY, shopInfoModel);
args.putSerializable(MODEL_KEY, userCashbackRateModel);
fragment.setArguments(args);
return fragment;
}
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
this.GetParams = getArguments().getString(SHOP_GET_PARAMS);
this.InfoModel = (InfoModel) getArguments().getSerializable(INFO_MODEL_KEY);
this.RateModel = (RateModel) getArguments().getSerializable(RATE_MODEL_KEY);
}
}
#Override
protected void setupInOnCreateView() {
nestedScrollView.setVisibility(View.VISIBLE);
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
conditionsTxt.setTypeface(Typeface.create(SANS_SERIF_FAMILY_NAME, Typeface.BOLD));
} else {
conditionsTxt.setTypeface(Typeface.create(SANS_SERIF_MEDIUM_FAMILY_NAME, Typeface.NORMAL));
}
}
#Override
protected void inject() {
ShopsComponent shopsComponent = DaggerShopsComponent.builder()
.applicationComponent(((BaseActivity) getActivity()).getApplicationComponent())
.build();
shopsComponent.inject(this);
}
public void setupWithData(InfoModel InfoModel, RateModel RateModel) {
//THIS METHOD IS COLLED FROM ACTIVITY'S onDataLoaded(InfoModel InfoModel, RateModel RateModel) method
setupShopInformation(shopInfoModel);
setCashBackRateModel(userCashbackRateModel);
}
}
You are using the dependency in a wrong way. It's not the activity that should call setupWithData on a fragment but it should be a fragment getting data from the activity (or other storage) instead. This way you will break this dependency on the fragment lifecycle which ends up being uninitialized.
Get the data from the server, store it where you need to, and update the UI from your activity. At this point you either show MyFragment1 or your TabLayout/ViewPager. If it's a TabLayout or a ViewPager, all you do is creating fragments and adding the to the layout or a corresponding pager adapter. That's it. You don't set the data at this point.
Now when your inner fragments populate in the pager adapter, they will go through onAttach, onCreate, onStart and onResume lifecycle methods. onResume is a good place to load the data. You either access it directly from the fragment, or get it from your outbound activity - depends on what makes more sense for you. If you need an activity reference, you can access it via getActivity() method in the fragment.
So in the fragment's onResume you will have something like:
setupShopInformation((YourActivity) getActivity()).getShopInfoModel());
setCashBackRateModel((YourActivity) getActivity()).getUserCashbackRateModel());
Although it would be even better to have it stored in some state class. But that will be a separate question.
Good luck!

App crashes while launching other fragment from existing fragment

I am using navigation drawer, Fragment_1 holds a listview which searches for gps location and then loads the adapter. The process works fine if I keep the Fragment_1 open till it loads fully. But if I try to open another fragment Fragment_2 while Fragment_1 is searching for location or loading adapter, the my app crashes. Fragment_2 holds textview and works fine if initiated seperately.
I am using following code to launch new fragments from drawer
Fragment mFragment;
FragmentManager mFragmentManager = getSupportFragmentManager();
mFragment = new Fragment_2();
mFragmentManager.beginTransaction()
.replace(R.id.frame_container,mFragment)
.commit();
You should do an Async task for loading the list. Before replacing current fragment just cancel the async task. Make sure that you check in onPostExecute if the task is not canceled.
Here you can find an example of loading data async into a recycler view: http://javatechig.com/android/android-recyclerview-example . Have a look at AsyncHttpTask. You can see data is taken and parsed on doInBackground and is displayed in onPostExecute. You also need to add the following to your code: enclose everything in onPostExecute in
if (!isCancelled()) {
/* your code here for setting list adapter */
}
override on detach:
#Override
public void onDetach() {
super.onDetach();
// don't update the UI if user go from this fragment
if (displayResultsAsyncTask != null && !displayResultsAsyncTask.isCancelled())
displayResultsAsyncTask.cancel(true);
}
So your code should look something like that:
public class YourFragment extends Fragment {
// declare an async task in your fragment
private AsyncTask displayResultsAsyncTask = null;
/* other data here */
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
/* your code for onCreate */
GetAndDisplayResults(); // call display results
}
public void GetAndDisplayResults() {
displayResultsAsyncTask = new AsyncTask<String, Void, Integer>() {
#Override
protected Integer doInBackground(String... params) {
Integer result = 0;
// get and parse data, also set result
return result;
}
#Override
protected void onPostExecute(Integer result) {
if (!isCancelled()) {
// if task wasn't stopped
if (result == 1)
SetYourList(); // set your list adapter based on results returned from doInBackground
}
}
}.execute();
}
#Override
public void onDetach() {
super.onDetach();
// don't update the UI if user go from this fragment
if (displayResultsAsyncTask != null && !displayResultsAsyncTask.isCancelled())
displayResultsAsyncTask.cancel(true);
}
}
The list used to save your data can be declared globaly and accesed from both doInBackground and onPostExecute or can be pased to onPostExecute as a param.
It looks like that you are trying to commit fragmentTransaction in one of the onCreate, onResume methods which is causing exception IllegalStateException: Can not perform this action after onSaveInstanceState due to activity state loss. Please check whether you are doing in these functions.
Hope this helps.

Showing fragment after activity fetches data

I'm fetching data in my activity that is needed by several fragments. After the data is returned, I create the fragments. I was doing this via an AsyncTask, but it led to occasional crashes if the data returned after a screen rotation or the app is backgrounded.
I read up and thought the solution to this was instead using an AsyncTaskLoader. Supposedly it won't callback if your activity's gone, so those errors should be solved. But this now crashes every time because "Can not perform this action (add fragment) inside of onLoadFinished".
How am I supposed to handle this? I don't want my fragments to each have to fetch the data, so it seems like the activity is the right place to put the code.
Thanks!
Edit 1
Here's the relevant code. I don't think the problem is with the code per-se, but more of my whole approach. The exception is pretty clear I shouldn't be creating fragments when I am. I'm just not sure how to do this otherwise.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getSupportLoaderManager().initLoader(BREWERY_LOADER, null, this).forceLoad();
}
//================================================================================
// Loader handlers
//================================================================================
#Override
public Loader<Brewery> onCreateLoader(int id, Bundle args) {
int breweryId = getIntent().getIntExtra(EXTRA_BREWERY_ID, -1);
return new BreweryLoader(this, breweryId);
}
#Override
public void onLoadFinished(Loader<Brewery> loader, Brewery data) {
if (data != null) {
onBreweryReceived(data);
} else {
onBreweryError();
}
}
#Override
public void onLoaderReset(Loader<Brewery> loader) {
}
...
protected void onBreweryReceived(Brewery brewery) {
...
createFragments();
}
...
protected void createFragments() {
FragmentManager fm = getSupportFragmentManager();
//beers fragment
mBeersFragment = (BreweryBeersFragment)fm.findFragmentById(R.id.beersFragmentContainer);
if (mBeersFragment == null) {
mBeersFragment = new BreweryBeersFragment();
fm.beginTransaction()
.add(R.id.beersFragmentContainer, mBeersFragment)
.commit();
Bundle beersBundle = new Bundle();
beersBundle.putInt(BreweryBeersFragment.EXTRA_BREWERY_ID, mBrewery.getId());
mBeersFragment.setArguments(beersBundle);
}
}
Edit 2
My new strategy is to use an IntentService with a ResultReceiver. I null out callbacks in onPause so there's no danger of my activity being hit when it shouldn't be. This feels a lot more heavy-handed than necessary, but AsyncTask and AsyncTaskLoader neither seemed to have everything I needed. Creating fragments in those callback methods doesn't seem to bother Android either.
From the MVC (Model -- View -- Controller) viewpoint, both the Activity and its fragments are Controller, while it is Model that should be responsible for loading data. As to the View, it is defined by the layout xml, you can define custom View classes, but usually you don't.
So create a Model class. Model is responsible for what must survive a screen turn. (Likely, it will be a static singleton; note that Android can kill and re-create the process, so the singleton may get set to null.) Note that Activities use Bundles to send data to themselves in the future.

update listview from fragment within viewpager from main activity

COMPLETELY EDITED
Ok I will try to be more specific.
I'm developing a small app drawer. Therefore I need a way to let the user choose categories.
This is the main point of the question. If there is another better way than my approach please let me know.
So my try to implement this was to load all apps to an array list and save this to a service to make it available throuout the app. The loading of the apps is done by an asynctask.
MainActivity:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
packageManager = getPackageManager();
if ((AppDrawerService.getApps()) == null) {
apps = new ArrayList<ApplistItem>();
loadAppsToService();
} else {
//if Service already holds the data
manageViews();
}
}
private void loadAppsToService() {
LoadApplications loadApps;
loadApps = new LoadApplications(this);
loadApps.setOnLoadApplicationsFinishedListener(this);
loadApps.execute();
}
private void manageViews() {
FragmentManager fragmentManager = getSupportFragmentManager();
myViewPager = (ViewPager) findViewById(R.id.view_pager);
myViewPager.setAdapter(new ViewPagerAdapter(fragmentManager, this));
}
#Override
public void OnLoadApplicationsComplete(ArrayList<ApplistItem> apps) {
manageViews();
}
LoadApplications:
#Override
protected void onPostExecute(Object o) {
AppDrawerService.setApps(apps);
listener.OnLoadApplicationsComplete(apps);
super.onPostExecute(o);
}
ViewPagerAdapter:
#Override
public Fragment getItem(int position) {
Fragment category = null;
category = new AppListFragment()
return category;
}
#Override
public int getCount() {
pages = 5;
return pages;
}
AppListFragment:
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
if ((AppDrawerService.getApps()) == null) {
apps = new ArrayList<ApplistItem>();
} else {
apps = AppDrawerService.getApps();
}
v = getActivity().findViewById(android.R.id.list);
myApplist = (ListView) v;
applistAdapter = new ApplistAdapter(context, 0, apps);
myApplist.setAdapter(applistAdapter);
myApplist.setOnItemClickListener(this);
}
The problem which I have with this code is, that it alway populates only one Fragment with the applist. On first start the first fragment is populated with the apps but if you swipe two fragments to right and then one back to left, this fragment (the second) is populated. The impression which I have is that the
return new ApplistFragment();
from the ViewPager does actually not create an independent instance of the fragment. (At least I think so)
What I want is to show an undefined amount of Fragments which can all show different categories of the same list. So if possible I want to load the list only once and I want to reuse the Fragment code for every fragment since I don't want to restrict the max amount of categories.
My idea was to use the ApplistAdapter to filter the unwanted apps for every category but I really don't know.
Help is really really appreciated since I have no idea how to go along.
Thanks in advance.
I would change how this works all together. A few suggestions of the top of my head:
Download the data in the Service instead of the Activity and
persist it somewhere for example in a database.
You can use an Intent to tell the Service what you want to download and when to do it.
You can also use an IntentService instead of a Service.
IntentServices already handle each Intent in a separate worker
thread so you don't need an AsyncTask or anything like that in the
IntentService to perform the downloading.
Each Fragment should load the data from the database in onResume(). You
can use local broadcasts to inform the Fragments when the data
changed while they are being displayed.
If you don't give us more information it will be difficult to give you very specific advice.

How to access ListFragment Adapter within a ViewPager

I have an app that downloads data which must be displayed within the fragments of a viewpager. I dont know how to call the ListFragment adaptername.notifyDataSetChanged() in the AsyncTask that does the data download.
For example say i am downloading the temperature forecast for the next seven days:
my app has the following structure:
MainActivity: Starts an AsyncTask to download the data in onCreate() and gives the user choice (button) of which day to look at. Clicking the button launches SecondActivity and passes the day index to the ViewPager (to set the current view).
SecondActivity: Contains a ViewPager that contains 7 of the same ListFragments (The list display the temperature over a period of 5 hours, so the list has 5 entries).
MyListFragment: when this loads it sets the adapter to display each temperature (If the data is downloaded) otherwise it sets the temperature to "loading..."
Now my problem is, if the user waits on the MainActivity until the data downloads they can then proceed to the ViewPager to see the ListFragment temperatures without problem. But if they try click a day and load the ViewPager before the download completes the fragments will forever just say "loading..."
I need a way that I can reload the adapter within the ListFragment from the onPostExecute() of my AsyncTask in MainActivity. To do this though i need to be able to actually access the ListFragment that the ViewPager is displaying. How do update the adapter onPostExecute()?
MainActivity:
protected void onCreate(Bundle savedInstanceState) {
...
new LoadData().execute();
}
protected class LoadData extends AsyncTask<String, Void, String> {
protected String doInBackground(String... params) {
//Download happens here
}
protected void onPostExecute(String result) {
//I need to tell the viewpager in SecondActivity to reload the ListFragment it is currently showing here
}
}
SecondActivity
private ViewPager mPager;
private PagerAdapter mPagerAdapter;
private int[] temperatureArray;
public void onCreate(Bundle savedInstanceState) {
...
Intent intent = getIntent();
int[] defaultTemps = {0, 0, 0, 0, 0};
temperatureArray = getIntArrayExtra("temps", defaultTemps);
mPager = (ViewPager) findViewById(R.id.pagerID);
mPager.setCurrentItem(intent.getIntExtra("page", 0));
mPagerAdapter = new MyPagerAdapter(getSupportFragmentManager());
mPager.setAdapter(mPagerAdapter);
}
private class ScreenSlidePagerAdapter extends FragmentStatePagerAdapter {
...
public Fragment getItem(int position) {
MyListFragment lf = new MyListFragment();
lf.setTemperatures(temperatureArray);
return lf;
}
}
I need a way to be able to refresh the current displayed fragment when i finish downloading in the AsyncTask.
I can suggest doing one of two things, not sure if these are best practices.
You can Have the AsyncTask send a broadcast with a unique action when it has finished loading the information. That would of course have to be done from OnPostExecute:
#Override
protected void onPostExecute(Void result) {
super.onPostExecute(result);
if (result != null) {
//_Do whatever action you normally do, like storing result to database.
//fire up the broadcast
Intent intent = new Intent(Home.ACTION_FEED_LOADING_FINISHED);
mContext.sendBroadcast(intent);
}
}
And then intercept that via a BroadcastReceiver on your Fragment's code.
private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action.equals(ACTION_FEED_LOADING_FINISHED)) {
//The AsyncTask Finished loading data
}
}
};
Once the event is received, since the BroadcastReceiver is in the Fragment, where the views are loaded, you can refresh your UI accordingly.
Or,
You can pass the View you want to refresh as a paremeter on your AsyncTask.
Imagine your AsyncTask class like this:
private static class getInternetStuffTask extends AsyncTask<String, Void, Void> {
Then you can create a custom constructor to receive the view as paremeter:
public getInternetStuffTask (final Context context, final ListView list) {
this.mContext = context;
this.mListView= list;
}
Then, during onPostExecute, when data is loaded, you can simply set the adapter to the ListView directly form the AsyncTask.
You're touching on two different problems. First, use a Service for downloading. Services are there for long running operations (like a download) that live outside an Activity's lifecycle.
Second, to communicate between Activities and Fragments you'll want to use an callback interface. The link provided is to the docs which do an excellent job of explaining and providing samples.

Categories

Resources