Search code examples
androidandroid-asynctaskandroid-viewpagerandroid-listfragment

Android viewpager AsyncTask finish when page changed


I have view pager. My viewpager contains 3 fragments. In the first fragment I have an AsyncTask class. I parsed JSON with AsyncTask and I can show it in listview. (everything is ok)

I have one problem AsyncTask which I have in the first fragment does not finish when I go to the next fragments. When I am in the second fragment my AsyncTask is also running. How can I write code to cancel my AsyncTask when viewpager's page changed?

This is my source (this is the first fragment source; another fragment source is the same but the only difference is the Server Url):

public class StradaChefs1 extends Fragment {

public static CustomerStatistic stat;

private ConnectionDetector con;
private AlertDialogManager alert = new AlertDialogManager();

@SuppressLint("ClickableViewAccessibility")
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
        Bundle savedInstanceState) {

    View rootView = inflater.inflate(R.layout.strada_chefs_1, container,
            false);
    stat = new CustomerStatistic();

    con = new ConnectionDetector(getActivity());

    if (!con.isConnectingToInternet()) {
        alert.showAlertDialog(getActivity(),
                "You have not internet connection");
    } else {

        stat.execute("my urlllllllll"); // geo

    }

    return rootView;
}

public class CustomerStatistic extends AsyncTask<String, Void, String> {
    ProgressDialog pDialog;

    @Override
    protected void onPreExecute() {
        super.onPreExecute();

        pDialog = ProgressDialog.show(getActivity(), "Please Wait... ",
                "Loading... ");
        pDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);

        pDialog.setCancelable(false);
        pDialog.show();
    }

    @Override
    protected String doInBackground(String... params) {
        return Utils.getJSONString(params[0]);
    }

    @Override
    protected void onPostExecute(String result) {
        super.onPostExecute(result);

        try {

            JSONArray mainJson = new JSONArray(result);

            String first = mainJson.getString(0);

            JSONObject jobject = new JSONObject(first);
            String image = jobject.getString("image");
            String String_title = jobject.getString("title");
            String String_name = jobject.getString("name");
            String String_desc = jobject.getString("description");

            String second = mainJson.getString(1);

        } catch (JSONException e) {
            e.printStackTrace();
        }

        if (pDialog != null) {
            pDialog.dismiss();

            pDialog = null;
        }

    }

}

@Override
public void onResume() {
    Log.e("DEBUG", "onResume of HomeFragment");

    super.onResume();
}

@Override
public void onStop() {
    super.onStop();
    if (stat != null && stat.equals(AsyncTask.Status.RUNNING)) {
        stat.cancel(true);
        Toast.makeText(getActivity(), "finished", Toast.LENGTH_SHORT)
                .show();
    }

}
}

This is a viewpager java code

public class TabbedActivity1 extends Fragment {

private StradaChefs1 mfragment1;
private StradaChefs2 mfragment2;
private StradaChefs3 mfragment3;

private StradaChefs4 mfragment4;

SectionsPagerAdapter mSe;

public static final String TAG = TabbedActivity1.class.getSimpleName();


ViewPager mViewPager;
private ArrayList<Fragment> fragmentList;

public static TabbedActivity1 newInstance() {
    return new TabbedActivity1();
}

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
        Bundle savedInstanceState) {
    View v = inflater.inflate(R.layout.activity_item_one_1, container, false);

    mSe=new SectionsPagerAdapter(getChildFragmentManager());

    mViewPager = (ViewPager) v.findViewById(R.id.pager1);
    CirclePageIndicator circle=(CirclePageIndicator)v.findViewById(R.id.circleindicator1);
    mViewPager.setAdapter(mSe);
    circle.setViewPager(mViewPager);
    mfragment1 = new StradaChefs1();
    mfragment2 = new StradaChefs2();
    mfragment3 = new StradaChefs3();
    mfragment4 = new StradaChefs4();

    fragmentList = new ArrayList<Fragment>();
    fragmentList.add(mfragment1);
    fragmentList.add(mfragment2);
    fragmentList.add(mfragment3);
    fragmentList.add(mfragment4);

    mViewPager.setPageTransformer(false, new PageTransformer() {

        @Override
        public void transformPage(View page, float position) {
            page.setRotationY(position * -40);

        }
    });



    return v;
}


public class SectionsPagerAdapter extends FragmentPagerAdapter {

    public SectionsPagerAdapter(FragmentManager fm) {
        super(fm);
    }

    @Override
    public Fragment getItem(int position) {
        return fragmentList.get(position);
    }

    @Override
    public int getCount() {
        return 4;
    }

    @Override
    public CharSequence getPageTitle(int position) {

        return null;
    }
}

}

How can I solve this problem?


Solution

  • The FragmentPagerAdapter keeps additional fragments, besides the one shown, in resumed state, so you can't use onPause and onResume for starting/stopping the AsyncTask. The solution is to implement a custom OnPageChangeListener and create a new method for when the fragment is shown.

    1) Create LifecycleManager Interface The interface will have two methods and each ViewPager’s Fragment will implement it. These methods Are as follows:

    public interface FragmentLifecycle {
    
        public void onPauseFragment();
        public void onResumeFragment();
    
    }
    

    2) Let each Fragment implement the interface
    3) Implement interface methods in each fragment - in onPauseFragment stop the AsyncTask, in onResumeFragment start it
    4) Call interface methods on ViewPager page change You can set OnPageChangeListener on ViewPager and get callback each time when ViewPager shows another page

    5) Implement OnPageChangeListener to call your custom Lifecycle methods

    Listener knows the new position and can call the interface method on new Fragment with the help of PagerAdapter. I can here call onResumeFragment() for new fragment and onPauseFragment() on the current one.

    I need to store also the current fragment’s position (initially the current position is equal to 0), since I don’t know whether the user scrolled from left to right or from right to left. See what I mean in code:

    private OnPageChangeListener pageChangeListener = new OnPageChangeListener() {
    
        int currentPosition = 0;
    
        @Override
        public void onPageSelected(int newPosition) {
    
            FragmentLifecycle fragmentToShow = (FragmentLifecycle)pageAdapter.getItem(newPosition);
            fragmentToShow.onResumeFragment();
    
            FragmentLifecycle fragmentToHide = (FragmentLifecycle)pageAdapter.getItem(currentPosition);
            fragmentToHide.onPauseFragment();
    
            currentPosition = newPosition;
        }
    
        @Override
        public void onPageScrolled(int arg0, float arg1, int arg2) { }
    
        public void onPageScrollStateChanged(int arg0) { }
    };
    

    I didn't write the code. Full tutorial here