Android viewpager AsyncTask finish when page changed - android

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?

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

When you start the asynctask set the flag isRunning=true
when you are trying to jump from one fragment to other it mean
as per fragment lifecycle your are pausing and stoping your current fragment
so in onStop method of fragment you can check isRunning flag of asynctask is true if yes the
cancel the asyntask
its my logic hope it will help you to achieve your requirement

Related

OrientationChange handling Activity, Fragment, AsyncTask and DialogFragments?

Hi there I'm thinking about what is the correct and best way to handle Activity, Fragment, AsyncTask and DialogFragments together.
My current state is that I start my Activity and replace its ContentView with my Fragment, in which I got an EditText and one Button.
Tapping my Button executes an AsyncTasks which Requests random things and takes some time. Meanwhile I display a DialogFragment begging for patience.
Desired behavior is that, e.g. I rotate my screen my DialogFragment keeps being displayed for the time my AsyncTask is running. After that I want to show up a simple toast displaying the information I got from my HttpRequest.
Compact overview about how I thought it would work:
BaseFragment keeps a WeakReference to the Activity it's attached to
AsyncTask keeps a WeakReference to Fragment which exectures it
AsyncTasks onPreExecute() shows up the DialogFragment
AsyncTasks onPostExecute() dissmisses the DialogFragment
BaseFragment holds DialogFragment
Unfortunately this is not the way it works, on orientation change my DialogFragment keeps being displayed and no toast is showing up.
What am I doing wrong ?
public class BaseFragment extends Fragment{
private static final String TAG = BaseFragment.class.getSimpleName();
protected WeakReference<AppCompatActivity> mActivity;
private TemplateDialogFragment dialogFragment;
public WeakReference<AppCompatActivity> getAppCompatActivity(){ return mActivity; }
#Override
public void onAttach(Context context) {
if(!(context instanceof AppCompatActivity)) {
throw new IllegalStateException(TAG + " is not attached to an AppCompatActivity.");
}
mActivity = new WeakReference<>((AppCompatActivity) context);
super.onAttach(context);
}
#Override
public void onDetach() {
mActivity = null;
super.onDetach();
}
#Override
public void onStart() {
super.onStart();
showContent();
}
public void showContent(){
}
public void showDialog(String title, String content){
dialogFragment = new TemplateDialogFragment();
Bundle bundle = new Bundle();
bundle.putString(TemplateDialogFragment.DIALOG_TITLE, title);
bundle.putString(TemplateDialogFragment.DIALOG_MESSAGE, content);
dialogFragment.setArguments(bundle);
dialogFragment.show(getFragmentManager(), TemplateDialogFragment.FRAGMENT_TAG);
}
public void notifyTaskFinished(String result) {
dismissDialog();
if(mActivity != null && !mActivity.get().isFinishing()) {
Toast.makeText(mActivity.get().getApplicationContext(), result, Toast.LENGTH_LONG).show();
}
}
private void dismissDialog(){
if(dialogFragment != null && dialogFragment.isAdded()) {
dialogFragment.dismissAllowingStateLoss();
}
}
}
...
public class TemplateFragment extends BaseFragment {
private static final String TAG = TemplateFragment.class.getSimpleName();
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.test_fragment, container, false);
}
#Override
public void showContent() {
super.showContent();
Button startTask = (Button) getAppCompatActivity().get().findViewById(R.id.button0);
final BaseFragment instance = this;
startTask.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
CustomAsyncTask task = new CustomAsyncTask(instance);
EditText input = (EditText) getAppCompatActivity().get().findViewById(R.id.text0);
task.execute(input.getText().toString());
}
});
}
private static class CustomAsyncTask extends AsyncTask<String, Void, String> {
WeakReference<BaseFragment> weakBaseFragmentReference;
private CustomAsyncTask(BaseFragment fragment) {
weakBaseFragmentReference = new WeakReference<>(fragment);
}
#Override
protected void onPreExecute() {
super.onPreExecute();
weakBaseFragmentReference.get().showDialog("Executing", "Working on the request...");
}
#Override
protected String doInBackground(String... params) {
HttpURLConnection con = HttpUrlConnectionFactory.createUrlConnection("https://www.httpbin.org/bytes/" + (params[0] == null ? "1" : params[0]));
return HttpRequester.doGet(con).getResponseAsString();
}
#Override
protected void onPostExecute(String response) {
super.onPostExecute(response);
if(weakBaseFragmentReference.get() == null) {
return;
}
weakBaseFragmentReference.get().notifyTaskFinished(response);
}
}
}
*Edit:
After some time researching this theme I'm sure a Service is the best solution for most of my field of use. Also I used AsyncTaskLoaders a lot, because there is a smooth control of lifecycle....
Use progress bar instead of DialogFragment.
AsyncTask should only be used for tasks that take quite few seconds.
AsyncTask doesn't respect Activity lifecycle, and can lead to memory leaks.
Check some gotchas.
You can try AsyncTaskLoader to survive configuration changes.

Endless adapter concept for view pager

Can any one please explain how to make endless adapter concept for view pager
I am currently using view pager to see my datas. On every 10th swipe of the view pager I need to hit the server and take dynamic response and need to update the viewpager. Obviously we need to use the endless adapter concept. But I was confused with the exact concept. Anyone please do the needful...
Thanks in advance...
I’ve implemented an endless ViewPager. I think it suits you needs. The request is simulated with a time delay ​​in the AsyncTask thread.
//ViewPagerActivity
public class ViewPagerActivity extends FragmentActivity {
private ViewPager vp_endless;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_endless_view_pager);
vp_endless = (ViewPager) findViewById(R.id.vp_endless);
vp_endless.setAdapter(new FragmentViewPagerAdapter(getSupportFragmentManager()));
}
}
//FragmentViewPagerAdapter
public class FragmentViewPagerAdapter extends FragmentStatePagerAdapter {
private List<CustomObject> _customObjects;
private volatile boolean isRequesting;
private static final int ITEMS_PER_REQUEST = 10;
public FragmentViewPagerAdapter(FragmentManager fragmentManager) {
super(fragmentManager);
_customObjects = HandlerCustomObject.INSTANCE._customObjects;
}
#Override
public Fragment getItem(int position) {
CustomFragment fragment = new CustomFragment();
fragment.setPositionInViewPager(position);
if (position == _customObjects.size() && !isRequesting)
new AsyncRequestItems().execute("www.test.com");
return fragment;
}
#Override
public int getCount() {
return Integer.MAX_VALUE;
}
public class AsyncRequestItems extends AsyncTask<String, Void, Void> {
#Override
protected Void doInBackground(String... urls) {
isRequesting = true;
//Fake request lag
try {Thread.sleep(2500);}
catch (InterruptedException e) {e.printStackTrace();}
for (int i = 0; i < ITEMS_PER_REQUEST; i++) {
_customObjects.add(new CustomObject());
}
return null;
}
#Override
protected void onPostExecute(Void aVoid) {
isRequesting = false;
}
}
}
//CustomFragment
public class CustomFragment extends Fragment {
private CustomObject _customObject;
private TextView tv_position;
private ProgressBar pb_loading;
private View root;
private int _positionInViewPager;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
root = inflater.inflate(R.layout.frament_endless_view_pager, container, false);
pb_loading = (ProgressBar) root.findViewById(R.id.pb_loading);
tv_position = (TextView) root.findViewById(R.id.tv_position);
_customObject = retrieveDataSafety();
if(_customObject != null) bindData();
else createCountDownToListenerForUpdates();
return root;
}
public void createCountDownToListenerForUpdates() {
new CountDownTimer(10000, 250) {
public void onTick(long millisUntilFinished) {
_customObject = retrieveDataSafety();
if(_customObject != null) {
bindData();
cancel();
}
}
public void onFinish() {}
}.start();
}
private CustomObject retrieveDataSafety() {
List<CustomObject> customObjects = HandlerCustomObject.INSTANCE._customObjects;
if(customObjects.size() > _positionInViewPager)
return customObjects.get(_positionInViewPager);
else
return null;
}
private void bindData() {
pb_loading.setVisibility(View.GONE);
String feedback = "Position: " + _positionInViewPager;
feedback += System.getProperty("line.separator");
feedback += "Created At: " + _customObject._createdAt;
tv_position.setText(feedback);
}
public void setPositionInViewPager(int positionAtViewPager) {
_positionInViewPager = positionAtViewPager;
}
}
//CustomObject
public class CustomObject {
public String _createdAt;
public CustomObject() {
DateFormat dateFormat = new SimpleDateFormat("HH:mm:ss");
_createdAt = dateFormat.format(new Date());
}
}
//HandlerCustomObject
public enum HandlerCustomObject {
INSTANCE;
public List<CustomObject> _customObjects = new ArrayList<CustomObject>();
}
Well, let's start from the beginning.
If you would like to have 'endless' number of pages you need to use some trick. E.g. you can't store endless number of pages in memory. Probably Android will destroy PageView everytime, when it isn't visible. To avoid destroying and recreating those views all the time you can consider recycling mechanism, which are used e.g. ListView. Here you can check and analyse idea how to implement recycling mechanism for pager adapter.
Moreover to make your UI fluid, try to make request and download new data before user gets to X0th page (10, 20, 30, 40...). You can start downloading data e.g when user is at X5th (5, 15, 25...) page. Store data from requests to model (it could be e.g. sqlite db), and user proper data based on page number.
It's just a brief of solution, but it's interesting problem to solve as well;)
Edit
I've started looking for inspiration and just found standalone view recycler implemented by Jake Wharton and called Salvage. Maybe it will be good start to create solution for your problem.

AsynkTask within Fragment within a ViewPager

First of all, I am relatively new to android programming.
I am creating a ViewPager application with two Fragments. One of the Fragments requests data from a server and return a result to the main FragmentActivity. My problem is that this request to the server can take sometime, and I have been trying to get a ProgressDialog to appear with AsyncTask while the user waits for the data to be retrieved. Once I create the background thread to retrieve the data, I successfully execute some code in the onPostExecute() method and set some variables. However, the return statement that sends information back to the FragmentActivity is being executed before the background thread actually ends. I can't seem to figure out a way for the main thread to wait on the background thread. Using Asyctask's get() method results in the ProgressDialog from appearing. I have looked through a lot of posts in here, but can't seem to find an answer.
Anything helps.
Code below:
SplashScreen.java
public class SplashScreen extends FragmentActivity {
MainMenu mainMenu;
MapScreen mapScreen;
PagerAdapter pagerAdapter;
ViewPager viewPager;
List<LatLng> geoPoints;
private Context context;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
setContentView(R.layout.activity_splash_screen);
context = this;
initializePaging();
}
private void initializePaging()
{
mainMenu = new MainMenu();
mapScreen = new MapScreen();
pagerAdapter = new PagerAdapter(getSupportFragmentManager());
pagerAdapter.addFragment(mainMenu);
pagerAdapter.addFragment(mapScreen);
viewPager = (ViewPager) super.findViewById(R.id.viewPager);
viewPager.setAdapter(pagerAdapter);
viewPager.setOffscreenPageLimit(2);
viewPager.setCurrentItem(0);
viewPager.setOnPageChangeListener(new OnPageChangeListener()
{
#Override
public void onPageScrollStateChanged(int postion){}
#Override
public void onPageScrolled(int arg0, float arg1, int arg2){}
#Override
public void onPageSelected(int position)
{
switch(position){
case 0: findViewById(R.id.first_tab).setVisibility(View.VISIBLE);
findViewById(R.id.second_tab).setVisibility(View.INVISIBLE);
break;
case 1: findViewById(R.id.first_tab).setVisibility(View.INVISIBLE);
findViewById(R.id.second_tab).setVisibility(View.VISIBLE);
break;
}
}
});
}
//Called from onClick in main_mainu.xml
public void getDirections(View view)
{
InputMethodManager inputManager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
inputManager.hideSoftInputFromWindow(getCurrentFocus().getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);
try
{
geoPoints = mainMenu.getDirections(context);
mapScreen.plotPoints(geoPoints);
}
catch(Exception e)
{
Toast.makeText(getApplicationContext(), "Error! Invalid address entered.", Toast.LENGTH_LONG).show();
mainMenu.clear();
}
}
}
MainMenu.java
public class MainMenu extends Fragment {
String testString;
int testInt;
TextView testTV;
private TextView tvDisplay;
private EditText departure;
private EditText destination;
private Geocoder geocoder;
private List<Address> departAddress;
private List<Address> destinationAddress;
private List<LatLng> geoPoints;
private String departString;
private String destinationString;
private Address departLocation;
private Address destinationLocation;
private LatLng departurePoint;
private LatLng destinationPoint;
private Context contextMain;
private GetData task;
public MainMenu()
{
super();
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
View root = (View) inflater.inflate(R.layout.main_menu, null);
geoPoints = new ArrayList<LatLng>(2);
return root;
}
#Override
public void onViewCreated(View view, Bundle savedInstanceState)
{
departure = (EditText) getView().findViewById(R.id.depart_field);
destination = (EditText) getView().findViewById(R.id.destination_field);
tvDisplay = (TextView) getView().findViewById(R.id.textView1);
}
public List<LatLng> getDirections(Context context)
{
contextMain = context;
geocoder = new Geocoder(getActivity());
departString = departure.getText().toString();
destinationString = destination.getText().toString();
try
{
task = new GetData(new Callback(){
public void run(Object result)
{
//return geoPoints;
}
});
task.execute((Void[])null);
}catch(Exception e)
{
e.printStackTrace();
}
return geoPoints;
}
public void clear()
{
departure.setText("");
destination.setText("");
tvDisplay.setText("Enter departure point, and destination point");
}
private class GetData extends AsyncTask<Void, Void, List<List<Address>>>
{
Callback callback;
private ProgressDialog processing;
public GetData(Callback callback)
{
this.callback = callback;
}
#Override
protected void onPreExecute()
{
processing = new ProgressDialog(contextMain);
processing.setTitle("Processing...");
processing.setMessage("Please wait.");
processing.setCancelable(false);
processing.setIndeterminate(true);
processing.show();
}
#Override
protected List<List<Address>> doInBackground(Void...arg0)
{
List<List<Address>> list = new ArrayList<List<Address>>(2);
try
{
departAddress = geocoder.getFromLocationName(departString, 5, 37.357059, -123.035889, 38.414862, -121.723022);
destinationAddress = geocoder.getFromLocationName(destinationString, 5, 37.357059, -123.035889, 38.414862, -121.723022);
list.add(departAddress);
list.add(destinationAddress);
}catch(IOException e)
{
e.printStackTrace();
}
return list;
}
#Override
protected void onPostExecute(List<List<Address>> list)
{
departLocation = list.get(0).get(0);
destinationLocation = list.get(1).get(0);
departurePoint = new LatLng(departLocation.getLatitude(), departLocation.getLongitude());
destinationPoint = new LatLng(destinationLocation.getLatitude(), destinationLocation.getLongitude());
if(geoPoints.size() >= 2)
{
geoPoints.clear();
}
geoPoints.add(departurePoint);
geoPoints.add(destinationPoint);
callback.run(list);
processing.dismiss();
}
}
}
#Override
protected Object doInBackground(Void...arg0)
{
Object result = null;
try
{
departAddress = geocoder.getFromLocationName(departString, 5, 37.357059, -123.035889, 38.414862, -121.723022);
destinationAddress = geocoder.getFromLocationName(destinationString, 5, 37.357059, -123.035889, 38.414862, -121.723022);
}catch(IOException e)
{
e.printStackTrace();
}
return result;
}
You never set the value of result...

Variable value is not increment after sliding

I have build a slide.
I have a ViewPage Activity that call a fragment every time that i swip to left or to right.
My question is:
I have a variable int that in the initial state have the value 6 (week_of_year). When i slide to right is call a new fragment and the variable is not increment as i intend. The variable is only increment in the the second slide.
For example: 6 -> 6 -> 7 -> 8 instead of 6 -> 7 -> 8 -> And i don't have ideia why this happens.
Here is my code:
ViewPage Activity
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_screen_slide);
/**
* Instantiate a ViewPager and a PagerAdapter
*/
date = Calendar.getInstance();
mPager = (ViewPager)findViewById(R.id.pager);
mPagerAdapter = new ScreenSlidePagerAdapter(getSupportFragmentManager());
mPager.setAdapter(mPagerAdapter);
mPager.setOnPageChangeListener(new OnPageChangeListener() {
#Override
public void onPageSelected(int arg0) {
if(itemOld < arg0){//right
auxFront = auxFront + 1;
oldStartWeek = oldStartWeek + auxFront;
auxFront=0;
}
else if(itemOld > arg0){//left
auxBack = auxBack - 1;
oldStartWeek = oldStartWeek + auxBack;
auxBack=0;
}
}
#Override
public void onPageScrolled(int arg0, float arg1, int arg2) {
}
#Override
public void onPageScrollStateChanged(int arg0) {
}
});
}
#Override
public void onBackPressed(){
if(mPager.getCurrentItem()==0){
super.onBackPressed();
}else{
mPager.setCurrentItem(mPager.getCurrentItem()-1);
}
}
/**
* A simple pager adapter that represents 5 ScreenSlidePageFragment objects, in sequence
*/
private class ScreenSlidePagerAdapter extends FragmentStatePagerAdapter{
public ScreenSlidePagerAdapter(FragmentManager fm){
super(fm);
}
#Override
public ScreenSlidePageFragment getItem(int position) {
/**
* Pass values from ViewPage activity to Fragment
*/
ScreenSlidePageFragment f = new ScreenSlidePageFragment();
Bundle args = new Bundle();
if(position == 0){
oldStartWeek = date.get(Calendar.WEEK_OF_YEAR);
args.putInt("START_WEEK", oldStartWeek);
f.setArguments(args);
return f;
}
else if(position != 0){
args.putInt("START_WEEK", oldStartWeek);
f.setArguments(args);
itemOld = mPager.getCurrentItem();
return f;
}
return f;
}
#Override
public int getCount() {
return NUM_PAGES;
}
}
}
Fragment that is call in each slide--------------------------------------------
public class ScreenSlidePageFragment extends Fragment implements
AdapterView.OnItemClickListener {
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
Toast.makeText(getActivity(), "week....." +getArguments().getInt("START_WEEK"), Toast.LENGTH_LONG).show(); //show the correct value
headerWeek.setText(" Week Number: "+getArguments().getInt("START_WEEK",0)); //But is not change corretly in the text view ?????
Thanks for your help and time.
To see why this happens in your ViewPager, you can Log the onCreate, onPause, onResume, etc methods for each fragment. What happens is that the first two fragments are actually created about the same time. So the second fragment is created before it actually displays in a ViewPager, so by the time the user scrolls to the second fragment, there is often old data there.
My solution to this is a little hacky. Note that instead of displayDialog() you would do whatever you needed to update the view when the user is present.
#Override
public void onResume() {
super.onResume();
fragmentActive = true;
if (userVisible()){
displayDialog();
}
else{
recursiveWait();
}
}
private void recursiveWait(){
new WaitAndDoXTask(1000, new DoXListener() {
#Override
public void doX() {
Log.d(TAG, "doX");
if (userVisible()){
displayDialog();
}
else if (fragmentActive){
recursiveWait();
}
}
}).execute();
}
private boolean userVisible(){
boolean vis = getUserVisibleHint();
Log.d(TAG, "user visible = " + vis);
return vis;
}
#Override
public void onPause() {
super.onPause();
Log.d(TAG, "onPause");
fragmentActive = false;
}
Here is the WaitAndDoXTask:
public class WaitAndDoXTask extends AsyncTask<Void, Void, Void>{
DoXListener mListener;
private int mTimeToWait;
/** This class will wait for the set time then do what is put into the listener.
*
*
* Run like this:
* new WaitAndDoXTask(1000, new DoXListener() {
*
* #Override
* public void doX() {
* // TODO Auto-generated method stub
*
* }
* }).execute();
**/
public WaitAndDoXTask(int timeToWait, DoXListener listener){
super();
mTimeToWait = timeToWait;
mListener = listener;
}
public interface DoXListener{
public void doX();
}
#Override
protected Void doInBackground(Void... params) {
try {
Thread.sleep(mTimeToWait);
} catch (InterruptedException e) {
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(Void result) {
if (mListener!=null){
mListener.doX();
}
}
}
Alternatively, if you could set up your Fragment with some Adapter and get notified via onDataSetChanged that might work better.

Android AsyncLoader: Share objects between fragmentactivity/fragment

I have a problem regarding with FragmentActivity and mutltiple Fragments inside a ViewPager.
In the FragmentActivity an object is loaded, with a AsyncTask which is used in all the other fragments. I have used the android:configChanges="orientation|keyboardHidden|keyboard" "hack" to make sure the object is only loaded once, even during a screen rotation.
However, now I would to like to display more infromation in landscape modus in one of the Fragments, so now that hack doesn't work.
I've tried implementing a AsyncLoader and the FragmentRetainInstanceSupport from the Android samples. But none of the things work:
1 - I can't get the FragmentRetainInstanceSupport get to work within the ViewPager, when I follow the sample code the onCreate() method isn't called in the worker-fragment
2 - The AsyncLoader crashes during a screen rotation...
Here is my code in which I (tried to) implement the AsyncLoader:
public class TeamActivity extends SherlockFragmentActivity implements LoaderManager.LoaderCallbacks<Response<Team>> {
ViewPager mPager;
PageIndicator mIndicator;
FragmentPagerAdapter mAdapter;
private final int MENU_FOLLOW = Menu.FIRST;
private final int MENU_UNFOLLOW = Menu.FIRST + 1;
Team team = null;
static int team_id;
public Team getTeam(){
return team;
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
team_id = this.getIntent().getIntExtra("index", 0);
Log.d("Teamid",""+team_id);
getSupportLoaderManager().initLoader(0, null, this);//.forceLoad();
//getSupportLoaderManager().getLoader(0).startLoading();
//new getTeam().execute();
}
#Override
public boolean onPrepareOptionsMenu(Menu menu) {
if(team != null) {
team.getNaam();
SharedPreferences keyValues = this.getSharedPreferences("teams_follow", Context.MODE_PRIVATE);
MenuItem menuItem_volg = menu.findItem(MENU_FOLLOW);
MenuItem menuItem_delete = menu.findItem(MENU_UNFOLLOW);
if(keyValues.contains(String.valueOf(team.getStartnummer()))) {
menuItem_volg.setVisible(false);
menuItem_delete.setVisible(true);
} else {
menuItem_volg.setVisible(true);
menuItem_delete.setVisible(false);
}
}
return super.onPrepareOptionsMenu(menu);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
menu.add(0,MENU_UNFOLLOW,Menu.NONE, R.string.ab_verwijderen)
.setIcon(R.drawable.ic_action_delete)
.setVisible(false)
.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
menu.add(0,MENU_FOLLOW,Menu.NONE, R.string.ab_volgen)
.setIcon(R.drawable.ic_action_star)
.setVisible(false)
.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
return super.onCreateOptionsMenu(menu);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
Utils.goHome(getApplicationContext());
break;
case MENU_FOLLOW:
Utils.addFavoTeam(getApplicationContext(), team);
invalidateOptionsMenu();
break;
case MENU_UNFOLLOW:
Utils.removeFavoteam(getApplicationContext(), team.getID());
invalidateOptionsMenu();
break;
}
return super.onOptionsItemSelected(item);
}
class TeamFragmentAdapter extends FragmentPagerAdapter implements TitleProvider {
ArrayList<Fragment> fragments = new ArrayList<Fragment>();
ArrayList<String> titels = new ArrayList<String>();
public TeamFragmentAdapter(FragmentManager fm) {
super(fm);
fragments.add(new TeamInformatieFragment());
titels.add("Informatie");
fragments.add(new TeamLooptijdenFragment());
titels.add("Routetijden");
}
#Override
public Fragment getItem(int position) {
return fragments.get(position);
}
#Override
public int getCount() {
return fragments.size();
}
#Override
public String getTitle(int position) {
return titels.get(position);
}
}
private class getTeam extends AsyncTask<Void, Void, Void> {
private ProgressDialog progressDialog;
Response<Team> response;
protected void onPreExecute() {
progressDialog = ProgressDialog.show(TeamActivity.this,
"Bezig met laden", "Team wordt opgehaald...", true);
progressDialog.setCancelable(true);
progressDialog.setOnCancelListener(new OnCancelListener() {
public void onCancel(DialogInterface dialog) {
cancel(true);
Utils.goHome(TeamActivity.this);
}
});
}
#Override
protected Void doInBackground(Void... arg0) {
if(!isCancelled())
response = api.getTeamByID(team_id);
return null;
}
#Override
protected void onPostExecute(Void result) {
if(Utils.checkResponse(TeamActivity.this, response)) {
setContentView(R.layout.simple_tabs);
team = response.getResponse();
mAdapter = new TeamFragmentAdapter(getSupportFragmentManager());
mPager = (ViewPager)findViewById(R.id.pager);
mPager.setAdapter(mAdapter);
mIndicator = (TabPageIndicator)findViewById(R.id.indicator);
mIndicator.setViewPager(mPager);
invalidateOptionsMenu();
progressDialog.dismiss();
}
}
}
public static class AppListLoader extends AsyncTaskLoader<Response<Team>> {
Response<Team> response;
public AppListLoader(Context context) {
super(context);
}
#Override public Response<Team> loadInBackground() {
response = api.getTeamByID(team_id);
return response;
}
#Override public void deliverResult(Response<Team> response) {
if (isReset()) {
return;
}
this.response = response;
super.deliverResult(response);
}
#Override protected void onStartLoading() {
if (response != null) {
deliverResult(response);
}
if (takeContentChanged() || response == null) {
forceLoad();
}
}
#Override
protected void onStopLoading() {
// Attempt to cancel the current load task if possible.
cancelLoad();
}
#Override
protected void onReset() {
super.onReset();
// Ensure the loader is stopped
onStopLoading();
response = null;
}
}
private ProgressDialog progressDialog;
#Override
public Loader<Response<Team>> onCreateLoader(int arg0, Bundle arg1) {
progressDialog = ProgressDialog.show(TeamActivity.this,
"Bezig met laden", "Team wordt opgehaald...", true);
progressDialog.setCancelable(true);
progressDialog.setOnCancelListener(new OnCancelListener() {
public void onCancel(DialogInterface dialog) {
finish();
}
});
return new AppListLoader(this);
}
#Override
public void onLoadFinished(Loader<Response<Team>> loader, Response<Team> response) {
//Log.d("Loader", "Klaar");
if(Utils.checkResponse(TeamActivity.this, response)) {
team = response.getResponse();
setContentView(R.layout.simple_tabs);
mAdapter = new TeamFragmentAdapter(getSupportFragmentManager());
mPager = (ViewPager)findViewById(R.id.pager);
mPager.setAdapter(mAdapter);
mIndicator = (TabPageIndicator)findViewById(R.id.indicator);
mIndicator.setViewPager(mPager);
invalidateOptionsMenu();
progressDialog.dismiss();
}
}
#Override
public void onLoaderReset(Loader<Response<Team>> arg0) {
//Utils.goHome(this);
}
}
Fragment (example):
public class TeamInformatieFragment extends SherlockFragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Team team = ((TeamActivity)this.getActivity()).getTeam();
//ERROR ON NEXT LINE AFTER SCREEN ROTATION:
getSherlockActivity().getSupportActionBar().setTitle(team.getNaam());
View view = inflater.inflate(R.layout.team_informatie, container, false);
return view;
}
}
The method is called from the fragments (with getActivity().getTeam()) but after a screen rotation getTeam() returns null;
I think the fragments are calling getTeam() too fast, before the variable team has been initialized(?)
Can you please help me?
Thank you!
This is probably not what you want to hear, but I recommend getting rid of
android:configChanges="orientation|keyboardHidden|keyboard"
It's an ugly hack, and a lot of the newer SDK elements like Loaders will break if you don't handle configuration changes correctly. Let Android handle the config changes, and design your code around that.

Categories

Resources