Android AsyncLoader: Share objects between fragmentactivity/fragment - android

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.

Related

Blank fragment after activity recreated

I have an Activity with a ViewPager and TabLayout. I enabled "destroy activities" from Settings in my phone to simulate low memory.
I use getSupportFragmentManager because it's an Activity.
The first time I open the activity, I see my fragments. When I minimize my app and reopen it, I see the tabs but not the content. Inside fragments I call setRetainInstance(true).
Of course if I call super.onCreate(null); instead of super.onCreate(savedInstanceState); it's working fine because the activity is being recreated at all.
If I use FragmentStatePagerAdapter the content is ok but the menu displays duplicated items.
So please, don't suggest FragmentStatePagerAdapter (want all fragments visible), getChildFragmentManager (ViewPager is in an Activity), setRetainInstance (already using it).
public class SystemActivity extends LoadingActivity {
#BindView(R.id.pager)
ViewPager viewPager;
#BindView(R.id.tab_layout)
TabLayout tabLayout;
#BindView(R.id.toolbar)
Toolbar toolbar;
int[] ICONS = {
R.drawable.ic_tab_general,
R.drawable.ic_tab_details
};
int[] TEXTS = {
R.string.general,
R.string.details,
};
private CustomPagerAdapter customPagerAdapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
fetch();
}
protected void fetch() {
super.fetch();
final Long systemId = getIntent().getLongExtra(Constants.Intent.SYSTEM_ID, 0);
this.realm = Realm.getDefaultInstance();
this.call = ApiClientHelper.getInstance(this).getSystem(systemId);
call.enqueue(new ApiUICallback<System>(this) {
#Override
public void onError(int code, String message) {
System system = realm.where(System.class).equalTo("id", systemId).findFirst();
if (system == null) {
fail();
} else {
init(system);
}
}
#Override
public void onSuccess(System system) {
realm.beginTransaction();
realm.copyToRealmOrUpdate(system);
realm.commitTransaction();
init(system);
}
});
}
private void init(System system) {
setContentView(R.layout.activity_system);
ButterKnife.bind(this);
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setDisplayShowHomeEnabled(true);
customPagerAdapter = new CustomPagerAdapter(getSupportFragmentManager(), system);
viewPager.setOffscreenPageLimit(TEXTS.length);
viewPager.setAdapter(customPagerAdapter);
tabLayout.setupWithViewPager(viewPager);
tabLayout.setTabMode(TabLayout.MODE_SCROLLABLE);
CharSequence title = customPagerAdapter.getPageTitle(0);
getSupportActionBar().setTitle(title);
for (int i = 0; i < ICONS.length; i++) {
TabLayout.Tab tab = tabLayout.getTabAt(i);
tab.setCustomView(R.layout.tab_view);
((ImageView) tab.getCustomView().findViewById(R.id.icon)).setImageResource(ICONS[i]);
}
tabLayout.setOnTabSelectedListener(
new TabLayout.OnTabSelectedListener() {
#Override
public void onTabSelected(TabLayout.Tab tab) {
CharSequence title = customPagerAdapter.getPageTitle(tab.getPosition());
getSupportActionBar().setTitle(title);
hiddenKeyboard();
}
#Override
public void onTabUnselected(TabLayout.Tab tab) {
hiddenKeyboard();
}
#Override
public void onTabReselected(TabLayout.Tab tab) {
hiddenKeyboard();
}
}
);
}
private void hiddenKeyboard() {
View focus = getCurrentFocus();
if (focus != null) {
focus.clearFocus();
InputMethodManager keyboard = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
keyboard.hideSoftInputFromWindow(focus.getWindowToken(), 0);
}
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
finish();
return true;
default:
return super.onOptionsItemSelected(item);
}
}
class CustomPagerAdapter extends FragmentPagerAdapter {
private System system;
public CustomPagerAdapter(FragmentManager fm, System system) {
super(fm);
this.system = system;
}
#Override
public Fragment getItem(int position) {
Fragment fragment;
switch (position) {
case 0:
fragment = new SystemGeneralFragment();
break;
case 1:
fragment = new SystemDetailsFragment();
break;
default:
return null;
}
Bundle bundle = new Bundle();
bundle.putLong(Constants.Intent.SYSTEM_ID, this.system.getId());
fragment.setArguments(bundle);
return fragment;
}
#Override
public int getCount() {
return TEXTS.length;
}
#Override
public CharSequence getPageTitle(int position) {
return getResources().getString(TEXTS[position]);
}
}
}
And one of my fragments:
public class SystemGeneralFragment extends MyFragment {
#BindView(R.id.progress)
View progress;
#BindView(R.id.progress_background)
View progressBackground;
#BindView(R.id.progress_percentage)
TextView percentage;
protected Call call;
protected Realm realm;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRetainInstance(true);
realm = Realm.getDefaultInstance();
}
#Override
public void onDestroyView() {
if (this.call != null) {
this.call.cancel();
}
super.onDestroyView();
}
#Override
public void onDestroy() {
realm.close();
super.onDestroy();
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_system_general, container, false);
ButterKnife.bind(this, view);
System system = realm.where(System.class).equalTo("id", getArguments().getLong(Constants.Intent.SYSTEM_ID)).findFirst();
System.Status status = system.getStatus();
percentage.setText(String.format("%d%%", status.getProgress()));
setProgress(progress, status.getColor(getContext()));
setProgress(progressBackground, ContextCompat.getColor(getContext(), R.color.light_gray));
return view;
}
private void setProgress(View view, int color) {
GradientDrawable shape = new GradientDrawable();
shape.setCornerRadius(16);
shape.setColor(color);
if (Build.VERSION.SDK_INT >= 16) {
view.setBackground(shape);
} else {
view.setBackgroundDrawable(shape);
}
}
}

Main activity variable becoming null

In my main activity I have:
private DataManager mDataManager;
In the same activity I manage this variable following the lifecycle. These are the related methods:
public class MainActivity extends AppCompatActivity {
#Override
public void onStart() {
super.onStart();
mDataManager = new DataManager(this);
}
#Override
public void onResume() {
super.onResume();
mDataManager.connect(getIpAddress());
}
#Override
public void onPause() {
super.onPause();
mDataManager.disconnect();
}
#Override
public void onStop() {
super.onStop();
mDataManager = null;
}
#Override
public DataManager getDataManager() {
return mDataManager;
}
#Override
public void updateFragments() {
runOnUiThread(new Runnable() {
#Override
public void run() {
if (mLoading.isShowing())
mLoading.dismiss();
List<Fragment> allFragments = getSupportFragmentManager().getFragments();
if (allFragments == null || allFragments.isEmpty())
return;
for (Fragment fragment : allFragments)
if (fragment.isVisible())
((UpdatableFragment) fragment).updateView();
}
});
}
I have some fragments that use getDataManager() to update themselves with data, but sometimes, often when I do not use the application for a while I get a nullpointerexception because getDataManager() returned null. According to the activity lifecycle, the object should never be null or am I missing something?
EDIT: Initialization of the ViewPager
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main_activity);
Toolbar myToolbar = (Toolbar) findViewById(R.id.my_toolbar);
setSupportActionBar(myToolbar);
MainAdapter adapter = new MainAdapter(getSupportFragmentManager());
ViewPager viewPager = (ViewPager) findViewById(R.id.my_pager);
viewPager.setAdapter(adapter);
}
public class MainAdapter extends FragmentPagerAdapter {
MainAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int position) {
switch (position) {
case 0:
return FragmentX.newInstance();
case 1:
return FragmentY.newInstance();
case 2:
return FragmentZ.newInstance();
case 3:
return FragmentU.newInstance();
}
return null;
}
#Override
public int getCount() {
return 4;
}
}

Only the original thread that created a view hierarchy can touch its views. - Strange behavior

This is a very strange behavior and I don't know how to fix it.
I have an Activity as a Presenter (In a MVP Architecture).
When the activity starts, I attach a Fragment as a View. The fragment itself is very simple.
public class CurrentSaleFragment extends BaseFragment {
private MainMVP.SalesPresenterOps salesPresenterOps;
private SaleAdapter adapter;
private ListView lv;
#BindView(R.id.btn_sell)
FloatingActionButton btnAdd;
public static CurrentSaleFragment newInstance(){
CurrentSaleFragment fragment = new CurrentSaleFragment();
Bundle arguments = new Bundle();
arguments.putInt(LAYOUT_RES_ID, R.layout.fragment_quick_sale );
fragment.setArguments(arguments);
return fragment;
}
#Override
protected void init() {
super.init();
lv = (ListView)view.findViewById(R.id.lv_sale);
}
#OnClick(R.id.btn_sell)
public void addToSale(View view){
mPresenter.moveToFragment(SellProductFragment.newInstance());
}
#Override
public void onAttach(Context context) {
super.onAttach(context);
salesPresenterOps = (MainMVP.SalesPresenterOps)context;
}
#Override
public void onDetach() {
salesPresenterOps = null;
super.onDetach();
}
}
The BaseFragment from which this fragmend extends :
public class BaseFragment extends Fragment implements MainMVP.RequiredViewOps, View.OnClickListener,
LoaderRequiredOps{
protected View view;
protected MainMVP.PresenterOps mPresenter;
protected final static String LAYOUT_RES_ID = "layout_res_id";
#Override
public void showOperationResult(String message, final long rowId) {
Snackbar.make(view, message, Snackbar.LENGTH_LONG).setAction(
R.string.see, new View.OnClickListener() {
#Override
public void onClick(View v) {
onOperationResultClick(rowId);
}
}
).show();
}
#Override
public void showSnackBar(String msg) {
Snackbar.make(view, msg, Snackbar.LENGTH_SHORT).show();
}
#Override
public void showAlert(String msg) {}
protected void onOperationResultClick(long rowId){}
#Override
public void onAttach(Context context) {
super.onAttach(context);
mPresenter = (MainMVP.PresenterOps)context;
}
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
this.view = inflater.inflate(getArguments().getInt(LAYOUT_RES_ID), null);
init();
return view;
}
protected void addToClickListener(View ... params){
for (View v : params){
v.setOnClickListener(this);
}
}
protected void init() {
if (view != null){
ButterKnife.bind(this, view);
}
}
#Override
public void onDetach() {
mPresenter = null;
Log.d(getClass().getSimpleName(), "Fragment was detached");
super.onDetach();
}
#Override
public void onClick(View v) {}
#Override
public void onPreLoad() {
Dialogs.buildLoadingDialog(getContext(), "Loading...").show();
}
#Override
public void onLoad() {}
#Override
public void onDoneLoading() {
Dialogs.dismiss();
}
}
When I enter the method 'moveToFragment()' I just replace CurrentSaleFragment for a new Fragment:
protected void addFragment(BaseFragment fragment){
mView = fragment;
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_holder,
fragment, null).addToBackStack(null).commit();
}
Then the new fragment is attached:
public class SellProductFragment extends BaseFragment{
private ListView listView;
private ProductListAdapter adapter;
private MainMVP.SalesPresenterOps mSalesPresenter;
public static SellProductFragment newInstance(){
SellProductFragment fragment = new SellProductFragment();
Bundle arguments = new Bundle();
arguments.putInt(LAYOUT_RES_ID, R.layout.fragment_inventory);
fragment.setArguments(arguments);
return fragment;
}
private void reload(){
final Loader loader = new Loader(this);
loader.execute();
}
#Override
public void onAttach(Context context) {
super.onAttach(context);
mSalesPresenter = (MainMVP.SalesPresenterOps)context;
}
#Override
protected void init() {
super.init();
listView = (ListView)view.findViewById(R.id.lv_inventory);
reload();
FloatingActionButton button = (FloatingActionButton)view.findViewById(R.id.btn_add);
addToClickListener(button);
}
#Override
public void onLoad() {
adapter = new ProductListAdapter(getActivity().getApplicationContext(), R.layout.row_product_item,
mSalesPresenter.getProducts());
try{
updateListView();
}catch (Exception e){
Log.w(getClass().getSimpleName(), e.getMessage());
}
}
private void updateListView(){
if (adapter != null && listView != null){
listView.setAdapter(adapter);
}else{
throw new RuntimeException();
}
}
}
See that This fragment also extends from BaseFragment and implements LoaderRequiredOps. The interface is used to 'load' any data. It adds a dialog and updated the adapter when the loading is done:
public class Loader extends AsyncTask<Void, Void, Void> {
private LoaderRequiredOps presenter;
public Loader(LoaderRequiredOps presenter){
this.presenter = presenter;
}
#Override
protected void onPreExecute() {
super.onPreExecute();
presenter.onPreLoad();
}
#Override
protected Void doInBackground(Void... params) {
presenter.onLoad();
return null;
}
#Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
presenter.onDoneLoading();
presenter = null;
}
}
Now, when I try to execute the method reload() from the SellProductFragment i get the 'Only the original thread that created a view hierarchy can touch its views.'
This does not happen if the SellProductFragment is attached first instead of CurrentSaleFragment.
What is happening here?
Your Async Loader class calls the presenters method onLoad() from a background thread during doInBackground().
My guess is that in the onLoad() method of the presenter, a view is referenced.
In order to change the view at this point, post the view logic as a Runnable to the UI thread (you said your presenter is the activity, so this should be possible from the onLoad method).
#Override
public void onLoad() {
runOnUiThread(new Runnable() {
#Override
public void run() {
// Your ui code here...
}
});
// Rest of your code here...
}
For an unknown reason, an unidentified configuration allows to execute the setting of an adapter for a ListView on the doInBackground() method.
Moved it to onPostExecute() and now it's working

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?
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

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.

Categories

Resources