Reputation: 2311
I'm trying to learn Android development and am still trying to wrap my head around how the framework works and how to properly extend all these classes.
My goal is this: An Activity
that has a ViewPager
that cycles through five ListFragment
s. The data being bound to each ListFragment
is coming from a web API, which is called using an AsyncTask
.
My problem is that whenever I switch to a new fragment, the MyListFragment.newInstance()
is called again, which calls the AsyncTask
every time. I'm trying to have the AsyncTask
called once, the first time the ListFragment
is loaded, to cut down on the web calls and save the page state. Eventually I want to do a "Pull down to refresh" type thing, which would mean not reloading the data when I switch a page.
I've been following this guide on Android Developers to try to make this happen. What I ended up with is this:
public class MainActivity extends FragmentActivity {
MyPagerAdapter mMyPagerAdapter;
ViewPager mViewPager;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mMyPagerAdapter = new MyPagerAdapter(getSupportFragmentManager());
mViewPager = (ViewPager) findViewById(R.id.pager);
mViewPager.setAdapter(mMyPagerAdapter);
}
public class MyPagerAdapter extends FragmentPagerAdapter {
public static final int NUM_PAGES = 5;
public MyPagerAdapter(FragmentManager fm) {
super(fm);
}
@Override
public Fragment getItem(int i) {
return MyListFragment.newInstance(getPageTitle(i).toString());
}
@Override
public int getCount() {
return NUM_PAGES;
}
@Override
public CharSequence getPageTitle(int position) {
String[] titles = getResources().getStringArray(R.array.thing_sort_titles);
return titles[position];
}
}
public static class MyListFragment extends ListFragment {
public static final String ARG_CATEGORY = "category_title";
ArrayList<HashMap<String, String>> mylist;
public MyListFragment() {
mylist = new ArrayList<HashMap<String, String>>();
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
Bundle args = getArguments();
URI url = new URI("http://api.remotesite.com/" + args.getString(ARG_CATEGORY));
new MyListAsyncTask().execute(url);
}
static MyListFragment newInstance(String category) {
MyListFragment f = new MyListFragment();
Bundle args = new Bundle();
args.putString(ARG_CATEGORY, category);
f.setArguments(args);
return f;
}
private class MyListAsyncTask extends AsyncTask<URI, Integer, ArrayList<HashMap<String, String>>> {
protected ArrayList<HashMap<String, String>> doInBackground(URI... uris) {
try {
JSONArray json = JSON.getJSONfromURL(uris[0]);
for (int i = 0; i < json.length(); i++) {
HashMap<String, String> map = new HashMap<String, String>();
JSONObject obj = json.getJSONObject(i)
map.put("title", obj.getString("title"));
map.put("author", obj.getString("author"));
map.put("id", obj.getString("id"));
mylist.add(map);
}
} catch (Exception ex) {
}
return mylist;
}
protected void onPostExecute(ArrayList<HashMap<String, String>> list) {
ListAdapter adapter = new SimpleAdapter(
getActivity(),
mylist,
R.layout.list_item,
new String[] { "title", "author" },
new int[] { R.id.text_title, R.id.text_author }
);
MyListFragment.this.setListAdapter(adapter);
}
}
}
}
I tried doing an array of ListFragment
s in the FragmentPagerAdapter
, and only call MyListFragment.newInstance
if that index was null, but it didn't end up changing anything.
Upvotes: 2
Views: 1068
Reputation: 40168
Please try to use setOffscreenPageLimit
to resolve your issue.
If you use it it will cache your fragment and it would not be called again.
Upvotes: 1
Reputation: 39836
I'll suggest you use the Loaders (http://developer.android.com/guide/components/loaders.html) for your case.
The loaders are quite clever on that regard that it automatically deliver back to the calling component the same data as before if you use the same ID.
for example:
Fragment position 0 calls initLoader(0, null, this);
then Fragment position 1 calls initLoader(1, null, this);
and so on....
that way whenever initLoader(1
<< id is called the second (3rd, 4th) time, it will not execute the web call and directly deliver the same result that was delivered on the 1st call.
Upvotes: 1