[My condition]
Now in MainActivity, I create some Fragments in which there are some TextViews. And there's an asynchronous thread AsyncTask in MainActivity to obtain information from web. After AsyncTask finished obtaining it will update the text in TextViews mentioned above through callback method (The Fragment implements a OnInfoGotInterface and instanciate a method onInfoGot() in the interface. onInfoGot() will call the method setTextView() defined in the Fragment to update information).
[My problem]
When execute the program, I found that the time point when AsyncTask finishes get information from web precedes the time point when Fragment call onCreateView(). In another word, when AsyncTask call (OnInfoGotInterface)fragment.onInfoGot() to set the TextViews, the TextViews have not been instanciated yet (TextViews are instanciated in on CreateView() by rootView.findViewById() method). As a result, a NullPointerException showed up.
[I need a resolution]
Now I want to do like this: When AsyncTask finishes getting info from web and is going to call onInfoGot(), we stop it, and make it wait until the Fragment finish onCreateView(). After that we waken the AsyncTask and allow it update the fragment.
PS. Some suggest that I should call new AsyncTask.excute() after onCreateView() in the definition of Fragment. But here AsyncTask and Fragment are both created in MainActivity. They are two differnt task threads in MainActivity, one is used for showing data and the other is used for getting data from Web.
Could anyone give some advice? I would really appreciate it! Here is the code:
MainActivity.java:
public class MainActivity extends Activity{
private List<City> cityList;
private ViewPager mPager; /*ViewPager for show the page of city info*/
private ScreenSlidePagerAdapter mPagerAdapter; /* Adapter for the ViewPager,
* ScreenSlidePagerAdapter is a subclass of FragmentStatePagerAdapter*/
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_show_city);
cityList = new ArrayList<City>();
mPager = (ViewPager) findViewById(R.id.pager);
mPagerAdapter = new ScreenSlidePagerAdapter(getSupportFragmentManager());
mPager.setAdapter(mPagerAdapter);
init();
}
private void init(){
loadCities(); //Load cities from database into cityList
initFragments();
getCityInfo();
}
private void initFragments(){
mPagerAdapter.removeAllFragments();
for(City city: cityList){
PageFragment fragment = new PageFragment(city.getName());
mPagerAdapter.addFragment(fragment);
mPagerAdapter.notifyDataSetChanged();
}
}
private void getCityInfo(){
for(City city: cityList){
String cityName = city.getName();
obtainCityInfo(cityName);
}
}
private obtainCityInfo(String cityName){
String request = "http://example.abc.com/"
+ cityName + "&output=json";
new AccessWebServiceTask().execute(request, cityName);
}
private class AccessWebServiceTask extends AsyncTask<String, Void, CityInfo>{
@Override
protected CityInfo doInBackground(String... urls) {
String result = getWebContent(urls[0]); /*Access web through HTTP*/
String cityName = urls[1];
/*Transform the String result to a CityInfo object containing information of a city*/
CityInfo cityInfo = encodeJason(result, cityName);
return cityInfo;
}
protected void onPostExecute(CityInfo cityInfo){
OnCityGot(cityInfo);
}
}
public void onCityGot(CityInfo cityInfo){
if(cityInfo != null){
String cityName = cityInfo.getCityName();
/*Set the info field of a city object*/
cityList.getByName(cityName).setCityInfo(cityInfo);
mPagerAdapter.updateFragment(cityInfo);
}
}
}
ScreenSlidePagerAdapter.java
public class ScreenSlidePagerAdapter extends FragmentStatePagerAdapter{
private List<PageFragment> fragmentsList;
public ScreenSlidePagerAdapter(FragmentManager fm) {
super(fm);
fragmentsList = new ArrayList<PageFragment>();
}
public ScreenSlidePagerAdapter(FragmentManager fm, List<PageFragment> list){
super(fm);
fragmentsList = list;
}
@Override
public PageFragment getItem(int position) {
return fragmentsList.get(position);
}
@Override
public int getCount() {
return fragmentsList.size();
}
public void setFragmentsList(List<PageFragment> fragmentsList){
this.fragmentsList = fragmentsList;
notifyDataSetChanged();
}
public void addFragment(PageFragment f){
fragmentsList.add(f);
notifyDataSetChanged();
}
public void removeFragment(int position){
fragmentsList.remove(position);
notifyDataSetChanged();
}
public void removeAllFragments(){
fragmentsList.clear();
notifyDataSetChanged();
}
private PageFragment findFragmentByName(String cityName){
for(PageFragment fragment: fragmentsList){
if(fragment.getCityName().equals(cityName))
return fragment;
}
return null;
}
public void updateFragment(CityInfo cityInfo){
String cityName = cityInfo.getCityName();
OnCityInfoChanged fragment = (OnCityInfoChanged)findFragmentByName(cityName);
String population = cityInfo.getPopulation();
fragment.onCityInfoChanged(population);
notifyDataSetChanged();
}
}
PageFragment.java:
public class PageFragment extends Fragment implements OnCityInfoChanged{
private TextView cityNameText;
private TextView populationText;
String cityName;
String population;
public PageFragment(){}
public PageFragment(String cityName, String population){
this.cityName = cityName;
this.population = population
}
public PageFragment(CityInfo cityInfo){
this.cityName = cityInfo.getCityName();
this.population = cityInfo.getPopulation();
}
public PageFragment(String cityName){
this.cityName = cityName;
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState){
ViewGroup rootView = (ViewGroup) inflater.inflate(
R.layout.fragment_city_page2, container, false);
cityNameText = (TextView)rootView.findViewById(R.id.city_name);
populationText = (TextView)rootView.findViewById(R.id.population);
setCityName(cityName);
setPopulation(population)
return rootView;
}
public void setCityName(String name){
cityNameText.setText(name);
}
public void setPopulation(String population){
populationText.setText(population);
}
public String getCityName(){
return cityName;
}
@Override
public void onCityInfoChanged(String population) {
//setCityName(cityName);
setPopulation();
}
}