Android Fragments Not Updating - android

I am trying to create a very simple Android application that uses a FragmentPagerAdapter to swipe between three fragments. Each of the fragments contains a single EditText and has the exact same code.
The desired behavior is that when the user updates the EditText, the new value is saved to the application instance. Then, once a new fragment is selected, that new fragment should show the saved value. For some reason this is not working.
I also want the focused fragment to show the saved data when the application resumes (comes back from background). This too does not work.
I am really confused as to why something as simple as this is so difficult!
Here is my code so far:
StackOverflowDemoApplication.java:
public class StackOverflowDemoApplication extends Application {
private ApplicationData applicationData;
// the index of the last fragment that was displayed
private int lastItem = 0;
#Override
public void onCreate() {
applicationData = new ApplicationData();
}
public ApplicationData getApplicationData() {
return applicationData;
}
public int getLastItem() {
return lastItem;
}
public void setLastItem(int lastItem) {
this.lastItem = lastItem;
}
}
MainActivity.java
public class MainActivity extends ActionBarActivity implements ActionBar.TabListener {
private static final String TAG = "MainActivity";
// the application instance
private StackOverflowDemoApplication application;
// the pager adapter
private SectionsPagerAdapter pagerAdapter;
// the view pager
private ViewPager viewPager;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Save the application instance.
application = (StackOverflowDemoApplication) getApplication();
// Set up the action bar.
final ActionBar actionBar = getSupportActionBar();
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
// Create the adapter that will return a fragment for each of the three
// primary sections of the activity.
pagerAdapter = new SectionsPagerAdapter(getSupportFragmentManager());
// Set up the ViewPager with the sections adapter.
viewPager = (ViewPager) findViewById(R.id.pager);
viewPager.setAdapter(pagerAdapter);
// For each of the sections in the app, add a tab to the action bar.
for (int i = 0; i < pagerAdapter.getCount(); i++) {
actionBar.addTab(
actionBar.newTab()
.setText(pagerAdapter.getPageTitle(i))
.setTabListener(this));
}
}
#Override
public void onTabSelected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) {
viewPager.setCurrentItem(tab.getPosition());
pagerAdapter.notifyDataSetChanged();
}
#Override
public void onTabUnselected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) {
}
#Override
public void onTabReselected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) {
}
public class SectionsPagerAdapter extends FragmentPagerAdapter {
private int NUM_ITEMS = 3;
public SectionsPagerAdapter(FragmentManager fragmentManager) {
super(fragmentManager);
}
#Override
public Fragment getItem(int position) {
// get the application data instance
ApplicationData data = application.getApplicationData();
switch (position) {
case 0:
return SecondFragment.newInstance(data);
case 1:
return FirstFragment.newInstance(data);
case 2:
return ThirdFragment.newInstance(data);
default:
return null;
}
}
#Override
public int getCount() {
return NUM_ITEMS;
}
public int getItemPosition(Object object) {
return POSITION_NONE;
}
#Override
public CharSequence getPageTitle(int position) {
switch (position) {
case 0:
return "FIRST FRAGMENT";
case 1:
return "SECOND FRAGMENT";
case 2:
return "THIRD FRAGMENT";
default:
return null;
}
}
}
#Override
public void onResume() {
// load the previous fragment
viewPager.setCurrentItem(application.getLastItem());
super.onResume();
}
#Override
public void onPause() {
// save the last fragment we used
application.setLastItem(viewPager.getCurrentItem());
super.onPause();
}
}
FirstFragment.java
public class FirstFragment extends Fragment {
private static final String TAG = "FirstFragment";
// the activity reference
private Activity activity;
// the application data
private ApplicationData data;
// the edit text
private EditText editText;
// are we currently loading data for this fragment?
private boolean loadingData = false;
public FirstFragment(ApplicationData data) {
super();
this.data = data;
}
public static FirstFragment newInstance(ApplicationData data) {
Log.e(TAG, "New instance called");
FirstFragment fragment = new FirstFragment(data);
return fragment;
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
Log.e(TAG, "Creating FirstFragment view");
// inflate the view
View view = inflater.inflate(R.layout.first_fragment_layout, container, false);
// get the activity instance
activity = getActivity();
// the textview
editText = (EditText) view.findViewById(R.id.textView);
editText.addTextChangedListener(textWatcher);
// update the ui from the data
updateUIFromData();
return view;
}
public void updateUIFromData() {
// we have started loading the data
loadingData = true;
// if there is data
if (null != data) {
// set the value
if (null != data.getStringValue()) {
editText.setText(data.getStringValue());
}
}
// done loading the data
loadingData = false;
}
private void updateDataFromUi() {
data.setStringValue(editText.getText().toString());
}
private TextWatcher textWatcher = new TextWatcher() {
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
// if we are not loading data
if (!loadingData) {
// update the data from the ui
updateDataFromUi();
}
}
#Override
public void afterTextChanged(Editable s) {
}
};
}

Try to update view when fragment get visible to user as follows:
public class MyFragment extends Fragment
#Override
public void setMenuVisibility(final boolean visible) {
super.setMenuVisibility(visible);
if (visible) {
**//Get new data and update views here**
}
}

Check this tutorial, it might help you:
http://www.androidhive.info/2013/10/android-tab-layout-with-swipeable-views-1/
You don't have to call notifyDataSetChanged() inside tabSelected callback.

You should update your fragment datas in onResumer() like TextView or EditText ... etc. See example:
Oncreate....
TextView mtextview = rootview.findViewById....
#Override
public void onResume() {
if(do some thing){
mtextview.setText("It did something");
}
super.onResume();
}

Related

Retrive data from activity every time oncreateViwe of fragments

Activity
public class GroupesActivity extends BaseActivity {
SelectedBundle selectedBundle;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_groupes);
sectionsPagerAdapter = new GroupPagerAdapter(this, getSupportFragmentManager());
viewPager.setAdapter(sectionsPagerAdapter);
tabs.setupWithViewPager(viewPager);
}
private void getAllGroup() {
// api call retrive data
// send data using interface on response
// set data selectedBundle.onBundleSelect(isVisible,calanderModelList,groupModelList,eventModelList);
}
public void setOnBundleSelected(SelectedBundle selectedBundle) {
this.selectedBundle = selectedBundle;
}
public interface SelectedBundle {
void onBundleSelect(boolean isVisible, List<CalanderModel> calanderModelList, List<GroupModel> groupModelList, List<EventModel> eventModelList);
}
}
Frgment
public class FragmentOne extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View root = inflater.inflate(R.layout.fragment_all_groups_fragments, container, false);
// get data only once on oncreateview
((GroupesActivity) getActivity()).setOnBundleSelected(new GroupesActivity.SelectedBundle() {
#Override
public void onBundleSelect(boolean isVisible, List<CalanderModel> calanderModelListtt, List<GroupModel> groupModelList, List<EventModel> eventModelList) {
Log.e("retrive data","data")
}
});
return root;
}
}
GroupPagerAdapter
public class GroupPagerAdapter extends FragmentPagerAdapter {
#StringRes
private static final int[] TAB_TITLES = new int[]{R.string.tab_text_1, R.string.tab_text_2, R.string.tab_text_3};
private final Context mContext;
public GroupPagerAdapter(Context context, FragmentManager fm) {
super( fm);
this.mContext=context;
}
#NonNull
#Override
public Fragment getItem(int position) {
switch (position) {
case 0:
return new AllGroupsFragments();
case 1:
return new HostFragments();
case 2:
return new GuestFragments();
}
return null;
}
#Nullable
#Override
public CharSequence getPageTitle(int position) {
return mContext.getResources().getString(TAB_TITLES[position]);
}
#Override
public int getCount() {
return 3;
}
}
problem
i have three fragments in tabview when i swipe this obove fragment
and then come again in this fragmnet that interface not called and i'm
not getting data from activity
How to get that data again from its parent activity, i need to only
retrive that data from activity on each time of fragments oncreateView
Thanks in adavance ;)
Use setMenuVisibility() method in Fragment to fix the issue.
//In fragments
#Override
public void setMenuVisibility(final boolean isVisible) {
super.setMenuVisibility(isVisible);
if (isVisible) {
//visible to user- do ur stuff
((GroupesActivity) getActivity()).setOnBundleSelected(new
GroupesActivity.SelectedBundle() {
#Override
public void onBundleSelect(boolean isVisible, List<CalanderModel>
calanderModelListtt, List<GroupModel> groupModelList, List<EventModel>
eventModelList) {
Log.e("retrive data","data")
}
});
}
}
the following link may help if you face any issues:
How to determine when Fragment becomes visible in ViewPager

Can't change the tabItem ( program crashes ), when I delete one of my tabItems with code

I have an application in which I create TabItems dynamically and I add them to the TabLayout. I'll show you the code below. then I also have a mechanism that when a tabitem is created, the user can close it with a click of a button. NOW: the problem happens here. when the user deletes that tabitem and program automatically directs the user to another tab. I can no longer click on the other tabs that I created at the start of the application. I Can click on them, but the program closes with the error
java.lang.IllegalStateException: The application's PagerAdapter changed the adapter's contents without calling PagerAdapter#notifyDataSetChanged! Expected adapter item count: 4, found: 3 Pager
and all of this happens when I delete a tabitem with a code written for a click. below is my MainActivity.java code :
public class MainActivity extends AppCompatActivity implements ContactsFragment.CallBacks, UserDetailFragment.DetailCallBacks {
android.support.v7.widget.Toolbar toolbar;
public static List<Fragment> fragments = new ArrayList<>();
public static List<String> fragmentsTitle = new ArrayList<>();
ViewPager viewPager;
TabLayout tabLayout;
int tabposition_number;
public List<Fragment> getFragments() {
return fragments;
}
public List<String> getFragmentsTitle() {
return fragmentsTitle;
}
public void addToFragments(Fragment fragment) {
fragments.add(fragment);
}
public void addToFragmentsTitle(String title) {
fragmentsTitle.add(title);
}
public Fragment getFragmentsWithPosition(int position) {
return fragments.get(position);
}
public String getFragmentsTitleWithPosition(int position) {
return fragmentsTitle.get(position);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater menuInflater = new MenuInflater(this);
menuInflater.inflate(R.menu.top_main_menu,menu);
return super.onCreateOptionsMenu(menu);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
if(item.getItemId() == R.id.remove_tab) {
remove_tab_details(3);
}
return super.onOptionsItemSelected(item);
}
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main_page_drawer);
this.tabLayout = findViewById(R.id.tab_layout);
this.viewPager = findViewById(R.id.view_pager);
tabLayout.setupWithViewPager(viewPager);
SetUpViewPager(viewPager);
this.toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
NavigationView navigationView = findViewById(R.id.navigation_view);
navigationView.setItemIconTintList(null);
tabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener(){
#Override
public void onTabSelected(TabLayout.Tab tab) {
if(tab.getPosition() > 2) {
tabposition_number = tab.getPosition();
}
// viewPager.setCurrentItem(tab.getPosition());
if(tab.getPosition() == 1) {
toolbar.setBackgroundColor(ContextCompat.getColor(MainActivity.this,R.color.tab_contacts));
tabLayout.setBackgroundColor(ContextCompat.getColor(MainActivity.this,R.color.main_contacts));
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
getWindow().setStatusBarColor(ContextCompat.getColor(MainActivity.this,R.color.status_contacts));
}
} else if(tab.getPosition() == 2) {
toolbar.setBackgroundColor(ContextCompat.getColor(MainActivity.this,R.color.tab_register));
tabLayout.setBackgroundColor(ContextCompat.getColor(MainActivity.this,R.color.main_register));
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
getWindow().setStatusBarColor(ContextCompat.getColor(MainActivity.this,R.color.status_register));
}
} else {
toolbar.setBackgroundColor(ContextCompat.getColor(MainActivity.this,R.color.tab_signin));
tabLayout.setBackgroundColor(ContextCompat.getColor(MainActivity.this,R.color.main_signin));
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
getWindow().setStatusBarColor(ContextCompat.getColor(MainActivity.this,R.color.status_signin));
}
}
}
#Override
public void onTabUnselected(TabLayout.Tab tab) {
}
#Override
public void onTabReselected(TabLayout.Tab tab) {
}
});
viewPager.addOnPageChangeListener(new TabLayout.TabLayoutOnPageChangeListener(tabLayout));
}
public void SetUpViewPager(ViewPager viewPager) {
MyViewPagerAdapter Adapter = new MyViewPagerAdapter((getSupportFragmentManager()));
Adapter.AddFragmentPage(new SignInFragment(),"ورود");
Adapter.AddFragmentPage(new ContactsFragment(),"ارتباطات");
Adapter.AddFragmentPage(new RegisterFragment(),"ثبت نام");
Adapter.notifyDataSetChanged();
viewPager.setAdapter(Adapter);
}
#Override
public void create_user_detail_tab(UserObject userObject) {
MyViewPagerAdapter Adapter = new MyViewPagerAdapter(getSupportFragmentManager());
UserDetailFragment userDetailFragment = new UserDetailFragment();
Bundle bundle = new Bundle();
bundle.putString("name",userObject.getName());
bundle.putString("family",userObject.getFamily());
bundle.putString("email",userObject.getEmail());
userDetailFragment.setArguments(bundle);
Adapter.AddFragmentPage(userDetailFragment,userObject.getName());
viewPager.setAdapter(Adapter);
TabLayout.Tab tab = tabLayout.getTabAt(1);
tab.select();
}
#Override
public void delete_previous_tab(int tabposition_number) {
remove_tab_details(tabposition_number);
MyViewPagerAdapter myViewPagerAdapter = new MyViewPagerAdapter(getSupportFragmentManager());
myViewPagerAdapter.notifyDataSetChanged();
}
#Override
public void changeTabItem(boolean mustdelete) {
ContactsFragment contactsFragment = new ContactsFragment();
if(tabposition_number > 2 && mustdelete) {
contactsFragment.setTextView(tabposition_number,mustdelete);
TabLayout.Tab tab = tabLayout.getTabAt(1);
tab.select();
}
}
public class MyViewPagerAdapter extends FragmentPagerAdapter {
public MyViewPagerAdapter(FragmentManager manager) {
super(manager);
}
public void removeTabPage(int position) {
fragments.remove(position);
fragmentsTitle.remove(position);
MyViewPagerAdapter myViewPagerAdapter = new MyViewPagerAdapter(getSupportFragmentManager());
myViewPagerAdapter.notifyDataSetChanged();
myViewPagerAdapter.notifyDataSetChanged();
}
public void AddFragmentPage(Fragment frag,String title) {
MainActivity.this.addToFragments(frag);
MainActivity.this.addToFragmentsTitle(title);
MyViewPagerAdapter myViewPagerAdapter = new MyViewPagerAdapter(getSupportFragmentManager());
myViewPagerAdapter.notifyDataSetChanged();
}
public Fragment getItem(int position) {
return MainActivity.this.getFragmentsWithPosition(position);
}
public CharSequence getPageTitle(int position) {
return MainActivity.this.getFragmentsTitleWithPosition(position);
}
public int getCount() {
return fragments.size();
}
}
public void remove_tab_details(int tab_to_delete) {
// TabLayout.Tab tab = tabLayout.getTabAt(2);
// tab.select();
tabLayout.removeTabAt(tab_to_delete);
MyViewPagerAdapter Adapter = new MyViewPagerAdapter(getSupportFragmentManager());
Adapter.removeTabPage(tab_to_delete);
Adapter.notifyDataSetChanged();
}
}
and the code for UserDetailFragment ( which creates when the user click on one of the items in a listview fragment .
public class UserDetailFragment extends Fragment {
View view;
DetailCallBacks detailCallBacks;
public UserDetailFragment() {}
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
view = inflater.inflate(R.layout.user_detail_fragment,null);
return view;
}
#Override
public void onResume() {
super.onResume();
final Bundle bundle = getArguments();
String name = (String) bundle.get("name");
String family = (String)bundle.get("family");
String email = (String)bundle.get("email");
TextView nameFamilytv = view.findViewById(R.id.user_detail_name_and_family);
String nameAndfamily = name + " " + family;
nameFamilytv.setText(nameAndfamily);
TextView emailtv = view.findViewById(R.id.user_detail_email);
emailtv.setText(email);
Button closebtn = view.findViewById(R.id.detail_close_button);
closebtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
detailCallBacks.changeTabItem(true);
}
});
}
#Override
public void onAttach(Context context) {
super.onAttach(context);
detailCallBacks = (DetailCallBacks)context;
}
public interface DetailCallBacks {
public void changeTabItem(boolean mustdelete);
}
and last but not least : the code for that list item that creates dynamic tabs when user clicks on its items :
public class ContactsFragment extends ListFragment {
CallBacks callBacks;
View view;
public static int came_fromTabItem;
public static boolean do_delete;
public ContactsFragment() { }
ArrayList<UserObject> userObjects;
BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
userObjects = intent.getParcelableArrayListExtra(Intent_Service.SERVICE_PAYLOAD);
ArrayAdapter<UserObject> userObjectArrayAdapter = new UserArrayAdapter(context,0,userObjects);
setListAdapter(userObjectArrayAdapter);
}
};
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Intent intent = new Intent(getActivity(), Intent_Service.class);
getActivity().startService(intent);
LocalBroadcastManager.getInstance(getActivity().getApplicationContext()).
registerReceiver(broadcastReceiver,new IntentFilter(Intent_Service.SERVICE_MESSAGE));
}
public void setTextView(int position,Boolean mustDelete) {
came_fromTabItem = position;
do_delete = mustDelete;
}
#Override
public void onResume() {
super.onResume();
if(came_fromTabItem > 2 && do_delete) {
final Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
callBacks.delete_previous_tab(came_fromTabItem);
do_delete = false;
Toast.makeText(getActivity().getApplicationContext(),String.valueOf(came_fromTabItem),Toast.LENGTH_LONG).show();
}
}, 2000);
}
}
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
this.view = inflater.inflate(R.layout.fragment_contacts,null);
return this.view;
}
public void onListItemClick(ListView l, View v, int position, long id) {
UserObject userObject = userObjects.get(position);
callBacks.create_user_detail_tab(userObject);
}
public interface CallBacks {
public void create_user_detail_tab(UserObject userObject);
public void delete_previous_tab(int positions);
}
#Override
public void onAttach(Context context) {
super.onAttach(context);
this.callBacks = (CallBacks)context;
}
}
So... can anyone help me please? the problem is simple, why the error The application's PagerAdapter changed the adapter's contents without calling PagerAdapter#notifyDataSetChanged! Expected adapter item count: 4, found: 3 appears when a tabitem is removed, how can I solve it?
the problem occur because you delete a tab item and your pager still has 4 in item count , you have to make pager item count dynamic , and call notifyDataSetChanged() after you remove an item
here is an example
public class MyPagerAdapter extends FragmentPagerAdapter {
int nbrItem;
public ProfilPagerAdapter(FragmentManager fm,String token,Int nbrItem) {
super(fm);
this.nbrItem= nbrItem;
}
#Override
public Fragment getItem(int position) {
switch(position) {
case 0 :
new SignInFragment();
case 1 :
new ContactsFragment()
case 2 :
new RegisterFragment()
}
return null;
}
#Override
public int getCount() {
return nbrItem;
}
public void setNbrItem(int nbrItem) {
this.nbrItem= nbrItem;
}
now when you remove an item you will pass to new number of item to your adapater
getAdapter().setNbrItem(2);
getAdapter().notifyDataSetChanged();
I solved my Problem, But with a hack, you see the error was because: TabItems are counting and indexing from 0, but as my pages are dynamically creating, I set the
getCount() method of my FragmentPagerAdapter to return the ArrayList<Fragment> fragments size , with fragments.size() , on the other hand, the size of an ArrayList doesn't count 0. so for 3 elements, instead of 0 1 2, or number 2, it returns to number 3.
so back to business, I was compelled to add null to my ArrayList and one null to my ArrayList titles, so this way when I removed my last TabItem, program doesn't crash anymore, and to be more convenient, when a user closes all Tabs , everytime user opens ( adds ) a new tab, I call fragments.removeAll(Collections.singleton(null)); to clear every null element i have inserted, for the TabTitles Too .
anyway cheers you guys, I'm sure this would be a good tutorial for those who want to create such applications because I've included all of my codes. please give a thumbs up. thanks.

How to save dynamically added pages in viewpager Android

With the help of Vivek Pratap Singh and astuetz codes from following questions(Remove Fragment Page from ViewPager in Android and Android saving dynamically added viewpager's fragment while coming back from another activity and reopening app),
In my previous question in stack overflow I used inbuild method onDestroy, as it looks like it will save all the dynamically added fragments in viewpager.
But it's not happening, I am able to see only one intial static page(i.e. fragment) when I restart my app or navigate to another activity and come back to my activity containing the viewpager with fragments.Could any one please help me on this question.
Here is my source code for your reference:
public class MainActivity extends FragmentActivity implements TextProvider {
private Button mAdd;
private Button mRemove;
private ViewPager mPager;
int position;
private MyPagerAdapter mAdapter;
private ArrayList<String> mEntries = new ArrayList<String>();
#Override
public void onSaveInstanceState(Bundle bundle) {
super.onSaveInstanceState(bundle);
bundle.putInt("currenItem", mPager.getCurrentItem());
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mPager = (ViewPager) findViewById(R.id.pager);
if (savedInstanceState != null) {
mPager.setCurrentItem(savedInstanceState.getInt("currentItem", 0));
}
mEntries.add("page 1");
mAdd = (Button) findViewById(R.id.add);
mRemove = (Button) findViewById(R.id.remove);
mAdd.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View view) {
addNewItem();
}
});
mRemove.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View view) {
removeCurrentItem();
}
});
mAdapter = new MyPagerAdapter(this.getSupportFragmentManager(), this);
mPager.setAdapter(mAdapter);
mPager.setOffscreenPageLimit(3);
}
private void addNewItem() {
// int position = mPager.getCurrentItem();
mEntries.add("page ");
mAdapter.notifyDataSetChanged();
}
private void removeCurrentItem() {
int position = mPager.getCurrentItem();
if(position != 0){
mEntries.remove(position);
}else{
Toast.makeText(getApplicationContext(), "Sorry", Toast.LENGTH_LONG).show();
}
mAdapter.notifyDataSetChanged();
}
#Override
public String getTextForPosition(int position) {
return mEntries.get(position);
}
#Override
public int getCount() {
return mEntries.size();
}
private class MyPagerAdapter extends FragmentPagerAdapter {
private TextProvider mProvider;
private long baseId = 0;
public MyPagerAdapter(FragmentManager fm, TextProvider provider) {
super(fm);
this.mProvider = provider;
}
#Override
public Fragment getItem(int position) {
switch(position) {
case 0:
return FragmentOne.newInstance(mProvider.getTextForPosition(position));
case 1:
return FragmentTwo.newInstance(mProvider.getTextForPosition(position));
case 2:
return FragmentThree.newInstance(mProvider.getTextForPosition(position));
default: return FragmentOne.newInstance(mProvider.getTextForPosition(position));
}
}
#Override
public int getCount() {
return mProvider.getCount();
}
//this is called when notifyDataSetChanged() is called
#Override
public int getItemPosition(Object object) {
// refresh all fragments when data set changed
return PagerAdapter.POSITION_NONE;
}
#Override
public long getItemId(int position) {
// give an ID different from position when position has been changed
return baseId + position;
}
#Override
public void destroyItem(ViewGroup container, int position, Object object) {
}
/**
* Notify that the position of a fragment has been changed.
* Create a new ID for each position to force recreation of the fragment
* #param n number of items which have been changed
*/
public void notifyChangeInPosition(int n) {
// shift the ID returned by getItemId outside the range of all previous fragments
baseId += getCount() + n;
}
}
}

Get fragment activity outside of Fragment.OnCreateView()

I have a Fragment with a TableLayout. The data in the table is from a SQLite db. The SQLite db is populated from a RESTful webservice in an AsyncTask in the MainActivity. The Fragment must wait for the task to complete before populating the table. The Fragment listens for the task onPostExecute() method to be called. When it is, the method onLoadAndStoreComplete in the Fragment is called. This all works.
What doesn't work is that I need the fragment activity in order to create new TableRows and TextViews in onLoadAndStoreComplete and I can't get it.
I've tried:
- making a class member fragmentActivity and assigning in onCreateView(), but by the time it gets to onLoadAndStoreComplete(), it is null.
- calling this.getActivity() again in onLoadAndStoreComplete(), but it returns null.
How do I get the fragment activity?
MyFragment.java:
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
fragmentActivity = this.getActivity(); // return value is valid
...
}
#Override
public void onLoadAndStoreComplete() {
fragmentActivity = this.getActivity(); // returns null
...
}
from MainActivity.java (extends ActionBarActivity)
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mainActivity = this;
setContentView(R.layout.activity_main);
Resources resources = getResources();
String[] tabTitleArray = { resources.getString(R.string.first_fragment),
resources.getString(R.string.second_fragment),
resources.getString(R.string.help_fragment) };
viewPager = (ViewPager) findViewById(R.id.pager);
actionBar = getSupportActionBar();
mAdapter = new TabsPagerAdapter(this.getSupportFragmentManager());
viewPager.setAdapter(mAdapter);
actionBar.setHomeButtonEnabled(false);
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
for (String tab_name : tabTitleArray) {
actionBar.addTab(actionBar.newTab().setText(tab_name).setTabListener(this));
}
// On swiping the ViewPager, select the respective tab
viewPager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
#Override
public void onPageSelected(int position) {
actionBar.setSelectedNavigationItem(position) ;// on changing the page, make respected tab selected
}
#Override
public void onPageScrolled(int arg0, float arg1, int arg2) {
}
#Override
public void onPageScrollStateChanged(int arg0) {
}
});
String url = "http://myrestfulwebservice";
Fragment secondFragment = mAdapter.getItem(SECOND_TAB);
new LoadAndStoreDataTask((OnLoadAndStoreCompleteListener)secondFragment).execute(url);
}
} // end OnCreate
TabsPagerAdapter.java
public class TabsPagerAdapter extends FragmentPagerAdapter {
public TabsPagerAdapter(FragmentManager fragmentManager) {
super(fragmentManager);
}
#Override
public Fragment getItem(int index) {
switch (index) {
case 0:
return new FirstFragment();
case 1:
return new SecondFragment();
case 2:
return new HelpFragment();
}
return null;
}
#Override
public int getCount() {
return 3; // get item count - equal to number of tabs
}
public static void setTabColor(TabHost tabhost) {
for(int i=0;i<tabhost.getTabWidget().getChildCount();i++) {
tabhost.getTabWidget().getChildAt(i).setBackgroundColor(Color.parseColor("#FF0000")); //unselected
}
tabhost.getTabWidget().getChildAt(tabhost.getCurrentTab()).setBackgroundColor(Color.parseColor("#0000FF")); // selected
}
}
I haven't tested this, but it seems to me that it would work.
Add a Context parameter to the constructor for both TabsPagerAdapter and MyFragment.
Something like this:
TabsPagerAdapter.java:
public class TabsPagerAdapter extends FragmentPagerAdapter {
private Context mCtx;
public TabsPagerAdapter(FragmentManager fragmentManager, Context context) {
super(fragmentManager);
mCtx = context;
}
#Override
public Fragment getItem(int index) {
switch (index) {
case 0:
return new FirstFragment(mCtx);
case 1:
return new SecondFragment(mCtx);
case 2:
return new HelpFragment(mCtx);
}
return null;
}
#Override
public int getCount() {
return 3; // get item count - equal to number of tabs
}
public static void setTabColor(TabHost tabhost) {
for(int i=0;i<tabhost.getTabWidget().getChildCount();i++) {
tabhost.getTabWidget().getChildAt(i).setBackgroundColor(Color.parseColor("#FF0000")); //unselected
}
tabhost.getTabWidget().getChildAt(tabhost.getCurrentTab()).setBackgroundColor(Color.parseColor("#0000FF")); // selected
}
}
MainActivity.java:
mAdapter = new TabsPagerAdapter(this.getSupportFragmentManager(), this);
MyFragment.java (do this in FirstFragment, SecondFragment, and HelpFragment):
public static class MyFragment extends Fragment {
private Context fragmentActivity ;
public MyFragment(Context context){
fragmentActivity = context;
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
//.........
return rootView;
}
#Override
public void onLoadAndStoreComplete() {
//do something with fragmentActivity
}
}
It seems the AsyncTask starts too early. suggest loading the db in onActivityCreated(), it's be called after onCreateView
#Override
public void onActivityCreated (Bundle savedInstanceState) {
//load your db here
}

How to save state of Fragments in ViewPager when orientation changes

I have an application that Implements ActionBarSherlock, it's mainly composed of
ViewPager with different content of fragments (for each page), with ViewPager indicator.
Here is my onCreate Method of the Activity that extends SherlockFragmentActivity
// Assume that tabs,sources,types are string arrays e.g. tabs = ["tab1","tab2","tab3"]
// types = ["listview","listview","webview"]
// according to the type of each tab, the type of content of the fragment associated to that tab is determined (e.g. WebView or ListView)
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
super.setContentView(R.layout.main);
srcContext = getBaseContext();
srcActivity = SaudiActivity.this;
int selectPos = 0;
Intent sender = getIntent();
FragmentPagerAdapter mAdapter = new NewsListAdapter(
getSupportFragmentManager());
ViewPager pager = (ViewPager) findViewById(R.id.pager);
pager.setAdapter(mAdapter);
TabPageIndicator indicator = (TabPageIndicator) findViewById(R.id.indicator);
indicator.setViewPager(pager);
pager.setOffscreenPageLimit(tabs.length);
pager.setCurrentItem((tabs.length - 1));
currentPosition = (tabs.length - 1);
indicator.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
#Override
public void onPageSelected(int position) {
currentPosition = position;
if ((type[position] == "listview" || type[position]
.equals("listview")) && loaded[position] == false) {
loaded[position] = true;
getNews(listViews[position], position);
}
}
#Override
public void onPageScrolled(int position, float positionOffset,
int positionOffsetPixels) {
}
#Override
public void onPageScrollStateChanged(int state) {
}
});
getSupportActionBar().setCustomView(R.layout.logo);
getSupportActionBar().setDisplayShowCustomEnabled(true);
getSupportActionBar().setDisplayHomeAsUpEnabled(false);
getSupportActionBar().setDisplayShowTitleEnabled(false);
getSupportActionBar().setDisplayShowHomeEnabled(false);
Context ctx = getSupportActionBar().getThemedContext();
SourcesAdapter adapter = new SourcesAdapter(ctx,
R.layout.navigation_list_item, src_name, icons, src_value);
}
Here are my News List Adapter (that creates the fragments),
public static class MyViewHolder {
public TextView title;
public ImageView icon;
}
class NewsListAdapter extends FragmentPagerAdapter {
public NewsListAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int position) {
return new NewsFragment(MyActivity.this, position);
}
// This is the number of pages -- 5
#Override
public int getCount() {
return tabs.length;
}
// This is the title of the page that will apppear on the "tab"
public CharSequence getPageTitle(int position) {
return tabs[position];
}
}
public List<NewsItem> NewsItems;
Finally here's my NewsFragment:
public static class NewsFragment extends Fragment {
private int position;
public NewsFragment() {
}
public NewsFragment(Context ctx, int pos) {
this.position = pos;
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = null;
if (type[position].equals("listview")) {
// Put a ListView in the Fragment
} else {
// Put a WebView in the Fragment
}
return view;
}
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
}
}
Let the fragment handle it's state by overriding onSaveInstanceState and placing the necessary values into outState. Recover that state in onCreateView using savedInstanceState. Also I'm pretty sure that if you're using Actionbarsherlock fragments need to extend SherlockFragment rather than Fragment.

Categories

Resources