I have an activity that hosts 2 tabs fragments. I fetch some data from database and based on that I want to update textviews inside my 2 tab fragments after AsyncTask finishes. However I get java.lang.NullPointerException at computing.gmit.ie.scorerapp.Team1Fragment.update(Team1Fragment.java:36) when I try to update the view inside the fragment. This is the code:
public class Tabs extends FragmentActivity implements ActionBar.TabListener {
private static final String SERVER_ROOT_URI_CYPHER = "xxxxxx";
private Map<String, List<String>> map = new HashMap<>();
ActionBar actionBar;
ActionBar.Tab tab1;
ActionBar.Tab tab2;
ViewPager viewPager;
private List<String> teamList;
// list of players team 1
private List<String> team1Players = new ArrayList<>();
// list of players team 2
private List<String> team2Players = new ArrayList<>();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_tabs);
viewPager = (ViewPager) findViewById(R.id.pager);
viewPager.setAdapter(new MyAdapter(getSupportFragmentManager()));
viewPager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
#Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
#Override
public void onPageSelected(int position) {
getActionBar().setSelectedNavigationItem(position);
}
#Override
public void onPageScrollStateChanged(int state) {
}
});
actionBar = getActionBar();
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
tab1 = actionBar.newTab();
tab1.setText("Tab 1 ");
tab1.setTabListener(this);
tab2 = actionBar.newTab();
tab2.setText("Tab 2");
tab2.setTabListener(this);
actionBar.addTab(tab1);
actionBar.addTab(tab2);
//execute async task here
TeamPlayer teamPlayer = new TeamPlayer();
teamPlayer.execute();
}
My adapter
class MyAdapter extends FragmentPagerAdapter {
MyAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int position) {
Fragment fragement = null;
if (position == 0) {
fragement = new Team1Fragment();
} else {
fragement = new Team2Fragment();
}
return fragement;
}
#Override
public int getCount() {
return 2;
}
}
My async task -->> null here
private class TeamPlayer extends AsyncTask<Void, Void, Void> {
Team1Fragment frg = new Team1Fragment();
#Override
protected Void doInBackground(Void... params) {
try {
getPlayersAndTeams(SERVER_ROOT_URI_CYPHER);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(Void aVoid) {
// title of the tabs
tab1.setText(teamList.get(0));
tab2.setText(teamList.get(1));
frg.update(); ------> null
}
}
My fragment
public class Team1Fragment extends Fragment {
TextView textView;
public Team1Fragment() {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_team1, container, false);
textView = (TextView) view.findViewById(R.id.tvTeam1Fragment);
return view;
}
public void update(){
textView.setText("HELLOOOO");
}
}
Team1Fragment frg = new Team1Fragment();
That's your problem. The only time you instantiate a new fragment when using it with a pager adapter is inside the getItem() method, never anywhere else. Please refer to the Android samples regarding fragments inside a pager with an actionbar. If you did that, make sure you implement everything correctly and then you can do async stuff.
Regarding your main problem:
If you want to update your fragment from an async task, attach your fragment to the task by reference and then update it, if its still attached to the activity.
Regarding the implementation:
If your task resides inside your activity, you notify your activity from within your fragments (use getActivity() inside onAttach() or onViewReady()), then the activity can start the task and attach the fragments to the tasks.
It's better to abstract the whole mechanism with interfaces, so the task doesn't really know about fragments, but about subscribers, which implement the interface TeamDataSubscriber (or something like that) and get the data. A setSubscribers(TeamDataSubscribers... subs) is needed, etc .you hopefully know that stuff.
Related
so i got one main activity that has a Tablayout and a ViewPager to present diffrent fragments.
when i move between the fragments with my Tablayout everything works good, but if i use a button to open fragment, when going back to the former fragment (by pushing the cancel button) the elements of the fragment i left staying on the screen (as in the picture).
i tried to use a method viewPager.setCurrentItem(0); in the fragment to go back to the homepage from the fragment instade of ft.replace(R.id.fragment_edit_reminder, new Main_Activity_fragment()).commit(); but it didn't moved back to my home fragment (with the repalce it does go back but as i saied the elements.
this is my main:
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final TabLayout tableLayout = findViewById(R.id.Tablayouting);
final ViewPager viewPager = findViewById(R.id.ViewPager);
PagerAdapter pagerAdapter = new
PagerAdapter(getSupportFragmentManager(),tableLayout.getTabCount());
viewPager.setAdapter(pagerAdapter);
tableLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
#Override
public void onTabSelected(TabLayout.Tab tab) {
viewPager.setCurrentItem(tab.getPosition());
}
#Override
public void onTabUnselected(TabLayout.Tab tab) {
}
#Override
public void onTabReselected(TabLayout.Tab tab) {
}
});
}
}
this is the fragment:
public class edit_reminder_fragment extends Fragment implements View.OnClickListener {
private Button cancelButton;
public edit_reminder_fragment() {
// Required empty public constructor
}
/**
* Use this factory method to create a new instance of
* this fragment using the provided parameters.
*
* #return A new instance of fragment edit_reminder_fragment.
*/
public static edit_reminder_fragment newInstance() {
edit_reminder_fragment fragment = new edit_reminder_fragment();
Bundle args = new Bundle();
fragment.setArguments(args);
return fragment;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
}
}
#RequiresApi(api = Build.VERSION_CODES.O)
public void onClick(View view)//TODO: make a utility method for switching fragments on the main_activity_fragment(see note).
{
switch (view.getId()) {//recognizing what button was pushed
case R.id.ButtonCancelReminder:
//region
FragmentTransaction ft = getFragmentManager().beginTransaction();
Main_Activity_fragment maf = new Main_Activity_fragment();
ft.replace(R.id.fragment_edit_reminder, maf).commit();
break;
//endregion
}
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_edit_reminder_fragment, container, false);
cancelButton = view.findViewById(R.id.ButtonCancelReminder);
cancelButton.setOnClickListener(this);
return view;
}
}
my pagerAdapted class:
public class PagerAdapter extends FragmentPagerAdapter {
//https://www.youtube.com/watch?v=HHd-Fa3DCng&ab_channel=MasterCoding
private int numOfTabs;
public PagerAdapter(FragmentManager fm, int numOfTabs) {
super(fm);
this.numOfTabs = numOfTabs;
}
#Override
public Fragment getItem(int position) {
switch (position) {
case 0:
return new Main_Activity_fragment();
case 1:
return new key_words_fragment();
case 2:
return new groups_and_points_fragment();
case 3:
return new Fragment_Past_Reminders();
case 4:
return new edit_reminder_fragment();
default:
return null;
}
}
#Override
public int getCount() {
return numOfTabs;
}
}
in the picture we see the home page fragment ,on it 3 buttons (cancel, save, Add a sub reminder) that stayed from a fragment that open when clicking on the ADD NEW REMINDER button (when clicking on cancel in the second fragment it's going back to the home page):
First, try the following as an adaper:
public class PagerAdapter extends
FragmentPagerAdapter {
private final ArrayList<Fragment> mFragments = new ArrayList<>();
private final ArrayList<String> mFragmentTitle = new ArrayList<>();
public PagerAdapter(FragmentManager mManager) {
super(mManager);
}
#Override
public Fragment getItem(int position) {
return mFragments.get(position);
}
#Override
public int getCount() {
return mFragments.size();
}
public void addFragment(Fragment fragment, String title) {
mFragments.add(fragment);
mFragmentTitle.add(title);
}
#Override
public CharSequence getPageTitle(int position) {
return mFragmentTitle.get(position);
}
public Fragment getFragment(int position) {
if (position < mFragments.size() && position >= 0) {
return mFragments.get(position);
}
return null;
}
}
Then in your MainActivity's onCreate, initialize the following:
mTabs = (TabLayout) findViewById(R.id.tabs);
mPager = (ViewPager) findViewById(R.id.view_pager);
mMainAdapter = new PagerAdapter( getSupportFragmentManager() );
setupContents();
Then the private method setupContents() as follows:
mMainAdapter.addFragment(new FragmentOne(), getResources().getString(R.string.tab_albums));
mMainAdapter.addFragment(new FragmentTwo(), getResources().getString(R.string.tab_songs));
mMainAdapter.addFragment(new FragmentThree(), getResources().getString(R.string.tab_playlists));
// you can add as many fragments as you wish
//just follow the previous method #mMainAdapter.addFragment
mPager.setAdapter(mMainAdapter);
mTabs.setupWithViewPager(mPager);
To get the current fragment:
public Fragment getCurrentFragment() {
return mMainAdapter.getFragment(mPager.getCurrentItem());
}
To check if the current fragment is FragmentOne:
private boolean isFragmentOne() {
return getCurrentFragment() instanceof FragmentOne;
}
I'm new to android programming and I can't find a way to switch between tab1 to tab2 in a TabLayout, when the user clicks a button located in the tab1.
It may be something very simple, but I am clueless in my first app.
I have tried the following at first:
TabLayout.Tab tab = tabLayout.getTabAt(1);
tab.select();
And it used to work, but I changed the code and, at some point, it just didn't work anymore.
I also triedtab.getCustomView().setSelected(true);, but I got NullPointerException. So I checked in a if statement if tab was null, and it wasn't.
And then I tried
tabLayout.setScrollPosition(1,0f,true);
ViewPager viewPager = new ViewPager(mainView.getContext());
viewPager.setCurrentItem(1);
But none of the solutions above worked for me.
Here is my code:
View view;
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
try {
view = inflater.inflate(R.layout.fragment_main, container, false);
Button GoB = view.findViewById(R.id.GoB);
final EditText USETV = view.findViewById(R.id.USETV);
final EditText commandEV = view.findViewById(R.id.CommandTV);
final SqlHelper db = new SqlHelper(getContext(), "myDatabase", null, 1);
GoB.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
try {
String a = "";
if (USETV.getText().toString().length() > 0) {
a += "USE " + USETV.getText().toString() + " ;";
}
a += commandEV.getText().toString();
String[][] c = db.SqlQuery(a);
LayoutInflater factory = getLayoutInflater();
View resultView = factory.inflate(R.layout.fragment_result, null);
TableLayout tableLayout = resultView.findViewById(R.id.ResultContainer);
tableLayout.removeAllViews();
View mainView = factory.inflate(R.layout.main_activity,null);
TabLayout tabLayout = mainView.findViewById(R.id.tabs);
if (c[0].length > 0 && c[1].length > 0) {
TabLayout.Tab tab = tabLayout.getTabAt(1);
//tab.select();
//tab.getCustomView().setSelected(true);
//tabLayout.setScrollPosition(1,0f,true);
//ViewPager viewPager = new ViewPager(mainView.getContext());
//viewPager.setCurrentItem(1);
//
// do some stuff
}
} catch (Exception e) {
showException(e);
}
}
});
} catch (Exception e) {
showException(e);
}
return view;
}
TabLayout and ViewPager belong to your Activity, so in your Fragment you have to call Activity function to switch tab
Here is an example:
public class MyActivity extends Activity {
private TabLayout mTabLayout;
private ViewPager mViewPager;
#Override
public onCreate(...) {
MyFrament myFragment = new MyFragment(this);
// Add fragment to Viewpager ...
// Attach ViewPager to TabLayout ...
}
public void switchTab(int index) {
// Check index ...
mViewPager.setCurrentItem(index);
}
}
then
public class MyFragment extends Fragment {
private Context mContext;
private Button mButton;
public MyFragment(Context context) {
mContext = context;
}
#Override
public View onCreateView(...) {
...
mButton.setOnClickListener(v->{
((MyActivity)mContext).switchTab(1);
});
...
}
}
Hope this help!
Try putting these two lines inside your button's handler :
ActionBar actionBar = (ActionBar)getActivity().getActionBar();
actionBar.setSelectedNavigationItem(1);
Right Click on your package name
new > activity > tabActivity click ok
Chose layout name whatever you want e.g (Example.java).
Select Navigation style is Action Bar Tabs(which is option 2) and click Finish
5.create two new Fragments
6.Go to the java file here Example.java
After open Example.java file paste the blow code in
SectionsPagerAdapter extends FragmentPagerAdapter
public SectionsPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int position) {
// getItem is called to instantiate the fragment for the given page.
// Return a PlaceholderFragment (defined as a static inner class below).
switch(position){
case 0:
return new Chats();
case 1:
return new Status();
case 2:
return new Call();
}
return PlaceholderFragment.newInstance(position + 1);
}
#Override
public int getCount() {
// Show 3 total pages.
return 3;
}
}
I have a TabLayout that uses a ViewPager to show different fragments in tabs. I want to call a method (beginGettingData() to be precise) on the fragments when they become visible to user. There are two solutions that I used (and searched about for two days) and the result is I still get exceptions regarding fragment not being attached to the activity.
The first method I used is with fragment's setUserVisibleHint(true). I did something like this:
#Override
public void setUserVisibleHint(boolean isVisibleToUser) {
if (isVisibleToUser) {
if (shouldGetData) {
beginGettingData();
}
}
}
This approach gave me the activity not attached exception and it is true. since this method is being called before fragment's onCreateView method.
So I thought of a second approach and I used ViewPager's addOnPageChangeListener and called beginGettingData method in onPageSelected method of the listener like this:
#Override
public void onPageSelected(int position) {
TabFragment fragment = mAdapter.getItem(position);
fragment.beginGettingData();
}
This works for me if the activity is started from another activity in my application. For example if my MainActivity uses startActivity to start my TabLayout activity. But the problem occurs when the activity is restarted in anyway. For example when the user presses home button, not come back to the application for a long time (which makes android system to kill the activity), and then return to the activity by opening the application again. Or a more simple example would be when the screen rotates. In these scenarios, the onPageSelected method is called before onCreateView (unlike when the activity is tarted fresh) and then again I get the activity not attached exception.
I know I can check that if the fragment is added to the activity or not, but problem is that for the first time, there will be no data to show the user and thus it is not an option for me to use. I MUST call beginGettingData() somehow when the fragment is shown to the user.
So what do you suggest me to do?
ps: this is my complete code of the activity that hosts the TabLayout and ViewPager
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_files);
mViewPagerOnChangePagelistener = new ViewPager.OnPageChangeListener() {
#Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
#Override
public void onPageSelected(int position) {
if (!mDataList.get(position)) {
getSupportFragmentManager().executePendingTransactions();
TabFragment fragment = mAdapter.getItem(position);
fragment.beginGettingData();
}
}
#Override
public void onPageScrollStateChanged(int state) {
}
};
mViewPager = (ViewPager) findViewById(R.id.files_list_view_pager);
setupViewpager(mViewPager);
mViewPager.setOffscreenPageLimit(1);
mTabLayout = (TabLayout) findViewById(R.id.files_list_tabs);
mTabLayout.setupWithViewPager(mViewPager);
mViewPager.addOnPageChangeListener(mViewPagerOnChangePagelistener);
mViewPager.post(new Runnable() {
#Override
public void run() {
mViewPagerOnChangePagelistener.onPageSelected(mViewPager.getCurrentItem());
}
});
}
private void setupViewpager(ViewPager viewPager) {
mAdapter = new ViewPagerAdapter(getSupportFragmentManager());
MediaFragment videoMediaFragment = new MediaFragment();
MediaFragment pictureMediaFragment = new MediaFragment();
Bundle videoMediaBundle = new Bundle();
Bundle pictureMediaBundle = new Bundle();
videoMediaBundle.putInt("media_type", MediaHelper.MEIDA_TYPE_VIDEO);
pictureMediaBundle.putInt("media_type", MediaHelper.MEDIA_TYPE_PHOTO);
videoMediaFragment.setArguments(videoMediaBundle);
pictureMediaFragment.setArguments(pictureMediaBundle);
mAdapter.addFragment(videoMediaFragment, "video");
mAdapter.addFragment(pictureMediaFragment, "picture");
viewPager.setAdapter(mAdapter);
}
private class ViewPagerAdapter extends FragmentPagerAdapter {
private final List<TabFragment> mFragmentList = new ArrayList<>();
private final List<String> mFragmentTitleList = new ArrayList<>();
public ViewPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public TabFragment getItem(int position) {
return mFragmentList.get(position);
}
#Override
public int getCount() {
return mFragmentList.size();
}
public void addFragment(TabFragment fragment, String title) {
mFragmentList.add(fragment);
mFragmentTitleList.add(title);
}
public CharSequence getPageTitle(int position) {
return mFragmentTitleList.get(position);
}
}
#Override
public void setMenuVisibility(final boolean visible) {
super.setMenuVisibility(visible);
if (visible) {
if(getActivity() != null){
if (shouldGetData) {
beginGettingData();
}
}
}
}
Try this ...
Is it possible to pass a data from fragment to fragment by swipe?
There are many articles teaching us how to pass the data from fragment to fragment, but most of the article or questions had implemented OnClickListener in their first fragment, which used to pass value to another fragment.
But my case is pass the data from two fragments without any button click and finally save them in different tables by clicking button in the last fragment. What can I do to achieve this??
The flow is Information >> WorkForce >>WorkDetailsTable and save them to different table by one button click.
I have tried to work it out but I get NULL value in SQLite. I think I have miss out a lot but have no idea. PLEASE help me...I've been stuck at here for more than two days...Thanks
Tab.java
public class Tab extends ActionBarActivity implements ActionBar.TabListener {
ViewPager Tab;
TabPagerAdapter TabAdapter;
ActionBar actionBar;
public static String name = null;
public static String subContractors = null;
// will be used for data communication
public static Force force_bean;;
public static Info info_bean;
public static Force getForce(){
return force_bean;
}
public static void setForce(Force force){
force_bean=force;
}
public static Info getInfo(){
return info_bean;
}
public static void setInfo(Info info){
info_bean=info;
}
final Activity mActivity = (Activity) this;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.tab1);
info_bean = new Info();
force_bean = new Force();
TabAdapter = new TabPagerAdapter(getSupportFragmentManager());
Tab = (ViewPager) findViewById(R.id.pager);
Tab.setOnPageChangeListener(
new ViewPager.SimpleOnPageChangeListener() {
#Override
public void onPageSelected(int position) {
actionBar = ((AppCompatActivity) mActivity).getSupportActionBar();
actionBar.setSelectedNavigationItem(position);
}
});
Tab.setAdapter(TabAdapter);
actionBar = ((AppCompatActivity) mActivity).getSupportActionBar();
//Enable Tabs on Action Bar
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
//Add New Tabs
actionBar.addTab(actionBar.newTab().setText("Information").setTabListener(this));
actionBar.addTab(actionBar.newTab().setText("Work Force").setTabListener(this));
actionBar.addTab(actionBar.newTab().setText("Work Details").setTabListener(this));
}
#Override
public void onTabSelected(ActionBar.Tab tab, android.support.v4.app.FragmentTransaction ft) {
}
#Override
public void onTabUnselected(ActionBar.Tab tab, android.support.v4.app.FragmentTransaction ft) {
}
#Override
public void onTabReselected(ActionBar.Tab tab, android.support.v4.app.FragmentTransaction ft) {
}
}
TabPagerAdapter.java
public class TabPagerAdapter extends FragmentStatePagerAdapter {
public TabPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int i) {
switch (i) {
case 0:
return Information.newInstance("name");
case 1:
return WorkForce.newInstance("SubCon");
case 2:
return WorkDetailsTable.newInstance();
}
return null ;
}
#Override
public int getCount() {
return 3; //No of Tabs you can give your number of tabs
}
Informmation.java
public class Information extends Fragment implements View.OnClickListener {
private Spinner spinner, spinner2, spinner3;
private static String a;
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
View info = inflater.inflate(R.layout.information, container, false);
dialog = new DateDialog();
spinner = (Spinner)info.findViewById(R.id.spinner);
addItemsOnSpinner();
a= spinner.getSelectedItem().toString();
return info;
}
public static Information newInstance(String a)
{
Information fragment=new Information();
Bundle bundle=new Bundle();
bundle.putString("a",a);
fragment.setArguments(bundle);
return fragment;
}
public void addItemsOnSpinner() {
List<String> list = new ArrayList<String>();
list.add("1 ");
list.add("2");
ArrayAdapter<String> adapter = new ArrayAdapter<String>(getActivity(), android.R.layout.simple_spinner_dropdown_item, list);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinner.setAdapter(adapter);
}
WorkForce.java
public class WorkForce extends Fragment {
private static EditText txt1;
private static String subCon;
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
View work = inflater.inflate(R.layout.workforce, container, false);
txt1 = (EditText) work.findViewById(R.id.editText);
subCon = txt1.getText().toString();
return work;
}
public static WorkForce newInstance(String subCon) {
WorkForce f = new WorkForce();
Bundle bundle = new Bundle();
bundle.putString("subCon", subCon);
f.setArguments(bundle);
return f;
}
}
WorkDetails.java
private com.example.project.project.API.InfoAPI ts;
private com.example.project.project.API.WorkDetailsAPI WD;
private com.example.project.project.API.WorkForceAPI WF;
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
View workDetails = inflater.inflate(R.layout.tableworkdetails, container, false);
getActivity().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
spinnerTra = (Spinner) workDetails.findViewById(R.id.spinner6);
addItemsOnSpinner();
Button btn1 = (Button)workDetails.findViewById(R.id.button2);
WD = new com.example.project.project.API.WorkDetailsAPI(getActivity());
ts = new com.example.project.project.API.InfoAPI(getActivity());
WF = new com.example.project.project.API.WorkForceAPI(getActivity());
a1 = spinnerTra.getSelectedItem().toString();
Bundle bundle = new Bundle();
final String name = bundle.getString("a");
final String subContractors = bundle.getString("subCon");
btn1.setOnClickListener(new View.OnClickListener() {
public void onClick(View arg0) {
add(name, subContractors);
}
});
return workDetails;
}
public void add(String name,String subContractors)
{
Toast.makeText(getActivity(),+name+subContractors, Toast.LENGTH_SHORT).show();
ts.insertTimeSheet(name);
WF.insertWorkForce(subContractors);
}
Note: My case is pass the data from two fragments without any button click and finally save them in different tables by clicking button in the last fragment.
If I understand your problem correctly, you are essentially implementing something a little bit like a "Wizard" where each step passes information to the next step as you swipe between the tabs or select them.
So in reality your problem is how to get the information out of a fragment when it is deselected and into a fragment when selected.
At the simplest level I would suggest your activity holds the "master" copy of all of the information and passes it into/takes it from each fragment in your tab pager adapter.
You would need some kind of "Domain" object to hold all the information you need to collect. Each tab would only update the bits of information it cares about..
public class WorkData {
string information;
string subCon;
... etc..
}
You add an instance of this to hold the master copy to your "tab" activity:
public class Tab extends ActionBarActivity implements ActionBar.TabListener {
...
WorkData workData = new WorkData();
...
I would then suggest a simple interface that each of your "tab" fragments implement; something like:
public interface DataUpdate {
void setData(WorkData data);
WorkData getData();
}
Each of your tab fragments would implement this interface, updating the WorkData as required..
public class WorkForce extends Fragment implements DataUpdate {
...
private WorkData workData; // this fragment's "copy" of the data
...
#Override
public WorkData getData() {
this.workData.subCon = this.subCon; // Assuming subcon has been updated.. else use txt1.getText();
return this.workData;
}
#Override
public void setData(WorkData workData) {
this.workData = workData;
// Update this page's views with the workData...
// This assumes the fragment has already been created and txt1 is set to a view
txt1.setText(workData.subCon);
this.subCon = workData.subCon; // Actually could just use subCon in workData, but be aware that workData actually points to the Activity's copy (kinda makes getdata redundant.. but I like symmetry and couldn't be bothered making lots of copies of the object).
}
Then you just need to add the code to pass the data backwards and forwards.. in your "Tab" activity which looks like...
#Override
public void onTabSelected(ActionBar.Tab tab, android.support.v4.app.FragmentTransaction ft) {
int position = tab.getPosition();
DataUpdate dataUpdate = (DataUpdate) TabAdapter.getItem(position);
// Pass the master workdata to the selected fragment
dataUpdate.setData(this.workData);
}
#Override
public void onTabUnselected(ActionBar.Tab tab, android.support.v4.app.FragmentTransaction ft) {
int position = tab.getPosition();
DataUpdate dataUpdate = (DataUpdate) TabAdapter.getItem(position);
// Update the master workdata from the unselected fragment
this.workData = dataUpdate.getData();
}
#Override
public void onTabReselected(ActionBar.Tab tab, android.support.v4.app.FragmentTransaction ft) {
// This might be pointless, but we'll do it anyway..
int position = tab.getPosition();
DataUpdate dataUpdate = (DataUpdate) TabAdapter.getItem(position);
// Pass the master workdata to the selected fragment
dataUpdate.setData(this.workData);
}
An important thing to notice here is that your TabPagerAdapter will create a new fragment every time you call getItem().. that will mean that we will never get any updates because each time we try to get the fragment it returns a new, empty fragment. We need to change this so that the fragments are still created when first asked for, but only created once so that we don't keep throwing away our work.
public class TabPagerAdapter extends FragmentStatePagerAdapter {
private static final int NUMBER_OF_TABS = 3;
private Fragment[] tabList = new Fragment[NUMBER_OF_TABS];
public TabPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int i) {
if (tabList[i] != null) {
// Return a tab we created earlier..
return tabList[i];
} else {
switch (i) {
case 0:
tabList[0] = Information.newInstance("name");
return tabList[0];
case 1:
tabList[1] = WorkForce.newInstance("SubCon");
return tabList[1];
case 2:
tabList[2] = WorkDetailsTable.newInstance();
return tabList[2];
}
}
return null ;
}
#Override
public int getCount() {
return NUMBER_OF_TABS;
}
Hope this helps. Good luck :-)
Although C James provides good tips to solve your problems, I would like to introduce another way without using implementing of interfaces. Please check below link out. If you use an event bus library such a http://square.github.io/otto/, you can easily pass data you want to share among fragments and even activities. Additionally, you can reduce a lot of code line since it only requires Sender(PUBLISHING), Receiver(Subscriber) while implementation of interfaces requires additional lines of code.
Here is a tutorial of Otto libarary.
http://www.vogella.com/tutorials/JavaLibrary-EventBusOtto/article.html
Hope it helps :)
I would more go the Observer Pattern way.
Each Fragments changes an POJO with is rendered in your Fragments in some way. You simply have to Observe the pojo in your Fragments. Changing Fragments will notify interested observers without knowing them.
I believe that's a much cleaner way to implement this.
Fragment A -> PojoInstance.setXY("foo");
Fragment A -> informs the Observers which e.b Informs Fragment B:
Fragment B will see the change tru the Observer.
Because ViewPagers or other Components will cache Fragments thats a way to get information in already created Fragments, even when their are not seen.
You could also try to use an EventBus where you pass the POJO around.
To transfer data from one fragment to another fragment when swipe is performed ,firstly you should get the view of the each fragment.here is the sample code that can help you out a bit.
write this code in Activity:
mviewpager.addOnPageChangeListener(new TabLayout.TabLayoutOnPageChangeListener(tabLayout));
mviewpager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
#Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
adapter = ((SOFragmentPagerAdapter) mviewpager.getAdapter());
//getting the view of fragments at positions
if(position==0)
{
View v = null;
Fragment1=(Fragment1)adapter.getFragment(position);
v=fragment1.getMyView();//this is how you get the view
ListView lv=(ListView)v.findViewById(R.id.lv_services);
ArrayAdapter<String> arrayAdapter=new ArrayAdapter<String>(SOListItemSelectedActivity.this,android.R.layout.simple_list_item_1,soRequestFragment.al_list_of_services);
lv.setAdapter(arrayAdapter);
}
if(position==1)
{
}
}
#Override
public void onPageSelected(int position) {
if(position==0)
{
View v = null;
soRequestFragment=(SORequestFragment)adapter.getFragment(position);
v=soRequestFragment.getMyView();
}
if(position==1)
{
}
}
#Override
public void onPageScrollStateChanged(int state) {
}
});
tabLayout.setOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
#Override
public void onTabSelected(TabLayout.Tab tab) {
mviewpager.setCurrentItem(tab.getPosition());
}
#Override
public void onTabUnselected(TabLayout.Tab tab) {
}
#Override
public void onTabReselected(TabLayout.Tab tab) {
}
});
and create a FragmentPagerAdapter as:
public class SOFragmentPagerAdapter extends FragmentPagerAdapter {
HashMap<Integer,Fragment> mPageReferenceMap;
int mNumOfTabs;
public SOFragmentPagerAdapter(FragmentManager fm,int mNumOfTabs) {
super(fm);
this.mNumOfTabs=mNumOfTabs;
mPageReferenceMap=new HashMap<Integer,Fragment>();
}
#Override
public Fragment getItem(int position) {
switch (position)
{
case 0:
Fragment1 fragment1=new tFragment1();
mPageReferenceMap.put(position,fragment1);
return fragment1;
case 1:
Fragment2 fragment2=new Fragment2();
mPageReferenceMap.put(position,fragment2);
return fragment2;
default:
return null;
}
}
public Fragment getFragment(int key) {
return mPageReferenceMap.get(key);
}
#Override
public int getCount() {
return 2;
}}
In Fragments add the getmyview() which will return the view of that fragment as:
public void getmyview()
{
return myview;//myview is fragment view which you will return in oncreateview method
}
Note: Viewpager execute onpagescroll first and get the position 0,1 and when you scroll ,views at position 1,2 will execute and page selected 0 will execute.
For tabselections: Tabunselected,Tabselected Tab reselected is the sequence of execution.
so write accordingly in the respective positions of fragments.
Hope this helps you.
I am trying to communicate between an activity and the fragment that sits on top of it, I want new data (image/text - retrieved from the db) to be passed into the frag every time an onclick occurs (onclick is in the activity). I made a simple interface to test (let me know if this is not suitable for images or if it is too slow or inefficient), and I am trying to have it included in my fragment so when an onclick occurs the fragment changes the image and the text.
Here is the simple interface code:
public interface FragmentCommunicator {
public void passDataToFragment(String someValue);
}
Here is the activity code:
public class RandomActivity extends FragmentActivity implements ActivityCommunicator {
//viewpager adapter
private PageAdapter mAdapter;
private ViewPager viewPager;
//interface through which communication is made to fragment
public FragmentCommunicator fragmentCommunicator;
//Buttons for yes, no, skip
Button btnYesRandom, btnNoRandom, btnSkipRandom;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_random);
//set buttons
btnYesRandom = (Button) findViewById(R.id.btnYesRandom);
// Initializing pager
viewPager = (ViewPager) findViewById(R.id.random_pager);
//calling bundle to attach data to fragment
Bundle bundle = new Bundle();
bundle.putString("edttext", "From Activity");
// set Fragmentclass Arguments
RandomFragment randFrag = new RandomFragment();
randFrag.setArguments(bundle);
//Setting up fragment
FragmentManager fm = getFragmentManager();
mAdapter = new PageAdapter(getSupportFragmentManager(), new UserUpVotesFragment(), randFrag, new UserDownVotesFragment());
viewPager.setAdapter(mAdapter);
// Here you would declare which page to visit on creation
viewPager.setCurrentItem(1);
viewPager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
public void onPageScrollStateChanged(int state) {}
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {}
public void onPageSelected(int position) {
// Check if this is the page you want.
if(position !=1) {
//swiping to the right
if(position == 0) {
Log.e("Swiping", "SWIPING TO THE Right BUT RESET ERR");
getIntent().removeExtra("edttext");
}
//swiping to the left
if(position == 2) {
Log.e("Swiping", "SWIPING TO THE left BUT RESET ERR");
}
// RandomFragment randomFrag = (RandomFragment) getFragmentManager().findFragmentById(R.id.fra);
viewPager.setCurrentItem(1);
}
}
});
btnYesRandom.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View arg0) {
if(fragmentCommunicator != null)
fragmentCommunicator.passDataToFragment("Hi from FragmentActivity");
}
});
}
Code for Fragment:
public class RandomFragment extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
//call data from activity bundle
String strtext = getArguments().getString("edttext");
View rootView = inflater.inflate(R.layout.fragment_random, container, false);
RelativeLayout random_frag_layout = (RelativeLayout) rootView.findViewById(R.id.random_frag_layout);
activityButton = (ImageView) rootView.findViewById(R.id.imagehere);
//setRetainInstance(true);
texthere = (TextView) rootView.findViewById(R.id.texthere);
texthere.setText(strtext);
return rootView;
}
//FragmentCommunicator interface implementation
public void passDataToFragment(String someValue){
activityAssignedValue = someValue;
Log.e("ACTIVITY", activityAssignedValue);
}
}
If you have only one fragment, then you can access it directly and send any data just via method: make your fragment a field and call your passDataToFragment() on it from activity.
To access an activity from fragment, call ((RandomActivity)getActivity()).activityMethod()
What is ActivityCommunicator?
If you wish to go down this route have your RandomActivity class implement the FragmentCommunicator interface, which should either be declared as an inner-public interface in the RandomFragment class say, or publicly (or package local) in its own file.