Unable to set text in fragment - java

I am trying to call a function from my mainActivity to change a TextView in one of my fragments. I have read a couple posts on the best way of doing it but for some reason, none of them seem to work for me. I know the function is working because once a press the button the toast comes up but for some reason the text won't change. I was wondering what the issue could be, or if I am just missing an additional step.
here is the method being called in my mainActivity
public class MainActivity extends AppCompatActivity implements Tab1Fragment.OnCalcClickListener{
private static final String TAG = "MainActivity";
private SectionsPageAdapter mSectionsPageAdpater;
private ViewPager mViewPager;
Tab1Fragment tab1Fragment = new Tab1Fragment();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.d(TAG, "onCreate: Starting");
//initializing FragmentManager so the fragments can communicate
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.add(R.id.container, tab1Fragment);
fragmentTransaction.commit();
//declare sections page adapter
mSectionsPageAdpater = new SectionsPageAdapter(getSupportFragmentManager());
//Set up the view pager with the sections adapter
mViewPager = (ViewPager) findViewById(R.id.container);
setUpViewPager(mViewPager);
//create a tab layout object and set it's id to tabs (mainActivity.xml)
TabLayout tabLayout = (TabLayout) findViewById(R.id.tabs);
tabLayout.setupWithViewPager(mViewPager);
//
}
// create a sections page view adapter
private void setUpViewPager(ViewPager viewPager){
SectionsPageAdapter adapter = new SectionsPageAdapter(getSupportFragmentManager());
adapter.addFragment(new Tab1Fragment(), "Day");
adapter.addFragment(new Tab2Fragment(), "Info");
adapter.addFragment(new Tab3Fragment(), "Week");
viewPager.setAdapter(adapter);
}
//initialise calculator object
Calculator mainCalculator = new Calculator();
#Override
public void calculateClick(int to_calculate) {
switch (to_calculate){
case 1:
Toast.makeText(getBaseContext(),"working", Toast.LENGTH_SHORT).show();
mainCalculator.freqDay = mainCalculator.freqDay + 1;
mainCalculator.freqWeek = mainCalculator.freqWeek + 1;
mainCalculator.getTotalDay();
tab1Fragment.updateInfo();
break;
}
}
Here is the code for my fragment
public class Tab1Fragment extends Fragment implements
View.OnClickListener{
private static final String TAG = "Tab1Fragment";
//Establishing the buttons & Methods
Button btn1;
Button btn2;
TextView dayView;
OnCalcClickListener onCalcClickListener;
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.tab1_fragment, container, false);
//Connecting the buttons to the xml
btn1 = (Button) view.findViewById(R.id.btn_1);
btn1.setOnClickListener(this);
btn2 = (Button) view.findViewById(R.id.btn_2);
btn2.setOnClickListener(this);
dayView = (TextView) view.findViewById(R.id.total_Sales_Day);
return view;
}
//Onclick listener for buttons
public void setOnClickListener(View.OnClickListener listener) {
btn1.setOnClickListener(listener);
btn2.setOnClickListener(listener);
}
//method that will bring data back from activity and set the text
public void updateInfo(){
Toast.makeText(getContext(),"65", Toast.LENGTH_SHORT).show();
dayView.setText("test");
}

To make calls to methods from your fragment in the activity class you need something like this:
public static class MainActivity extends Activity
implements HeadlinesFragment.OnHeadlineSelectedListener{
...
public void onArticleSelected(int position) {
// The user selected the headline of an article from the HeadlinesFragment
// Do something here to display that article
ArticleFragment articleFrag = (ArticleFragment)
getSupportFragmentManager().findFragmentById(R.id.article_fragment);
if (articleFrag != null) {
// If article frag is available, we're in two-pane layout...
// Call a method in the ArticleFragment to update its content
articleFrag.updateArticleView(position);
} else {
// Otherwise, we're in the one-pane layout and must swap frags...
// Create fragment and give it an argument for the selected article
ArticleFragment newFragment = new ArticleFragment();
Bundle args = new Bundle();
args.putInt(ArticleFragment.ARG_POSITION, position);
newFragment.setArguments(args);
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
// Replace whatever is in the fragment_container view with this fragment,
// and add the transaction to the back stack so the user can navigate back
transaction.replace(R.id.fragment_container, newFragment);
transaction.addToBackStack(null);
// Commit the transaction
transaction.commit();
}
}
}
Here the activity is calling the updateArticleView method from the fragment, instead of your updateInfo method, but you will get the idea.
Also pay attention to the one-pane scenario, where you need to swap the content and push the arguments using a Bundle object.
See Deliver a Message to a Fragment for more details.

When you add the fragment set a tag to it like this:
MyFragment frag = new MyFragment();
frag.setArguments(getIntent().getExtras());
getSupportFragmentManager().beginTransaction().add(R.id.fragment_container, frag, "TAG").commit();
While updating the textview get the instance of fragment using findFragmentByTag()
MyFragment fragment = (MyFragment) getSupportFragmentManager().findFragmentByTag("TAG");
fragment.updateInfo();

Related

How can i show toolbar back button in fragments in android?

I am working on an android application where I have three fragments I want to show the back button on the toolbar of the fragments to go back to the previous fragments now how can I achieve that?? I am new to android please guide me.
public class SecondFragment extends Fragment {
Button button2;
private PageViewModel viewModel;
EditText editTextName, editTextEmail, editTextDesc;
public SecondFragment() {
// Required empty public constructor
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_second, container, false);
button2 = view.findViewById(R.id.next2);
editTextName = view.findViewById(R.id.edittextName);
editTextEmail = view.findViewById(R.id.edditextEmail);
editTextDesc = view.findViewById(R.id.edittexDesc);
viewModel = new ViewModelProvider(requireActivity()).get(PageViewModel.class);
button2.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if (editTextName.getText().toString().isEmpty() || editTextEmail.getText().toString().isEmpty() || editTextDesc.getText().toString().isEmpty())
{
editTextName.setError("Enter name");
editTextEmail.setError("Enter Email");
editTextDesc.setError("Enter Description");
}else {
// viewModel.setName(editTextName.getText().toString());
enterName(editTextName.getText().toString());
enterEmail(editTextEmail.getText().toString());
enterDesc(editTextDesc.getText().toString());
// viewModel.setEmail(editTextEmail.getText().toString());
// viewModel.setDescription(editTextDesc.getText().toString());
FragmentTransaction fragmentTransaction = getActivity().getSupportFragmentManager().beginTransaction();
Fragment NAME = new LastFragment();
fragmentTransaction.replace(R.id.container, NAME);
fragmentTransaction.commit();
}
}
});
return view;
}
this is the code of my fragment borther i have three fragments like this i need to add the back button on the toolbar of there three fragemtns
You can add a toolbar to your activity, which is the container for these fragments.
Then in your fragments you can do something like this:
private void setupToolbar() {
YourActivity yourActivity = (YourActivity) getActivity()
if(yourActivity != null) {
yourActivity.toolbar.setSkipVisibility(View.GONE) // Or View.VISIBLE
yourActivity.toolbar.setText() // Set some text
yourActivity.toolbar.setOnBackButtonClickListener{ yourActivity.onBackPressed() }
}
}
Follow the steps down below.
fragmentTransaction.replace(R.id.container, NAME);
fragmentTransaction.addToBackStack(null); //Add this line
fragmentTransaction.commit();
This will solve your issue. Thank you.

Button inside fragment overlap with next fragment's button

The signup page of my app is divided into three fragments. FragmentA, FragmentB and FragmentC which is attached to same activity. On clicking the next button which is present in FragmentA it will call FragmentB and same is for FragmentB and FragmentC. As I move forward the buttons of the previous fragment overlaps the current one. Below is my code. How can I avoid this situation?
MainActivity.class
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.signup_page);
init();
}
private void init() {
ViewPager2 viewPager = findViewById(R.id.signup_pager);
List<Fragment> fragmentList = new ArrayList<Fragment>();
FragmentA aFragment = new FragmentA();
FragmentB bFragment = new FragmentB();
fragmentList.add(aFragment);
fragmentList.add(bFragment);
SignupFragmentPagerAdapter signupFragmentPagerAdapter = new SignupFragmentPagerAdapter(this,fragmentList);
viewPager.setUserInputEnabled(false);
viewPager.setAdapter(signupFragmentPagerAdapter);
}
}
FragmentA.class
public class FragmentA extends Fragment {
EditText et_name;
Spinner sp_user_type;
Button bt_next;
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fraga,container,false);
et_name = view.findViewById(R.id.editTextTextPersonName);
sp_user_type = view.findViewById(R.id.user_spinner);
bt_next = view.findViewById(R.id.button8);
bt_next.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
FragmentB bFragment = new FragmentB();
FragmentManager manager = getParentFragmentManager();
FragmentTransaction transaction = manager.beginTransaction();
transaction.replace(R.id.frag_a, bFragment);
transaction.addToBackStack(null);
transaction.commit();
}
});
return view;
}
}
FragmentB.class
public class FragmentB extends Fragment {
Button bt_next;
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragb,container,false);
bt_next = view.findViewById(R.id.button9);
bt_next.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
FragmentC cFragment = new FragmentC();
FragmentManager manager = getParentFragmentManager();
FragmentTransaction transaction = manager.beginTransaction();
transaction.replace(R.id.frag_b, Fragment);
transaction.addToBackStack(null);
transaction.commit();
}
});
return view;
}
}
Cause of your problem:
You are making fragment transaction (from A to B) within Fragment A itself; and not through the placeholder of these fragments (which is in your case the ViewPager itself; So the MainActivity still sees that the ViewPager is at the first page and therefore shows Fragment A in the background.
You have two options to solve this:
First: Since you're disable page scrolling; I don't see any use to
the ViewPager .. so you can just have a fragment placeholder in the
main activity, and make fragment transaction on this placeholder.
Second: if you have a need to the ViewPager, instead of making
fragment transaction, you can use
viewPager.setCurrentItem(position) and set the position to the
target fragment according to the order you add them in the adapter.
You can do that from your fragment when you hit the button using:
((MainActivity)requireActivity()).myViewPager.setCurrentItem(position)

ListView of a Fragment (of a ViewPager inside a Fragment) that implements LoaderCallbacks<Cursor> is empty when I return back to it

The ListView inside of a Fragment that contains a ViewPager is empty when I return back to it. This ViewPager is inside of a Fragment because I'm using a Navigation Drawer Layout. I'll try to explain it in more details now:
I am using a Navigation Drawer layout and, consequently, using Fragments. In the main activity, in onCreate, I set the current Fragment with these lines of code:
#Override
protected void onCreate(Bundle savedInstanceState) {
/* More code */
currentFragment = new MainFragment();
FragmentManager fragmentManager = getSupportFragmentManager();
fragmentManager.beginTransaction().replace(R.id.layout_for_fragments, currentFragment).commit();
}
The MainFragment class contains a ViewPager that is initialized with these lines of code in the onCreateView():
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_main, container, false);
/* More code */
ViewPager viewPager = (ViewPager) rootView.findViewById(R.id.main_view_pager);
viewPager.setAdapter(new SimpleFragmentPagerAdapter(getActivity(), getActivity().getSupportFragmentManager()));
/* Code for Tablayout */
return rootView;
}
One of the Fragments of the SimpleFragmentPagerAdapter class is this one that implements LoaderManager.LoaderCallbacks
public class ExpensesFragment extends Fragment implements LoaderManager.LoaderCallbacks<Cursor> {
private ExpenseCursorAdapter mExpenseCursorAdapter;
private static final int EXPENSE_LOADER = 1;
public ExpensesFragment() {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_expenses, container, false);
ListView expensesListView = (ListView) rootView.findViewById(R.id.expenses_list_view);
mExpenseCursorAdapter = new ExpenseCursorAdapter(getContext(), null);
expensesListView.setAdapter(mExpenseCursorAdapter);
getLoaderManager().initLoader(EXPENSE_LOADER, null, this);
return rootView;
}
#Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
return new CursorLoader(/* arguments */);
}
#Override
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
mExpenseCursorAdapter.swapCursor(data);
}
#Override
public void onLoaderReset(Loader<Cursor> loader) {
mExpenseCursorAdapter.swapCursor(null);
}
}
On the first run, everything works fine. However, if I click on the navigation drawer menu, which I'm implementing this way, the ListView becomes empty:
public boolean onNavigationItemSelected(#NonNull MenuItem item) {
int id = item.getItemId();
if (id == R.id.nav_main) {
FragmentManager fragmentManager = getSupportFragmentManager();
fragmentManager.beginTransaction().remove(currentFragment).commit();
currentFragment = new MainFragment();
fragmentManager.beginTransaction().replace(R.id.layout_for_fragments, currentFragment).commit();
} else if (id == R.id.nav_blank) {
FragmentManager fragmentManager = getSupportFragmentManager();
fragmentManager.beginTransaction().remove(currentFragment).commit();
currentFragment = new BlankFragment();
fragmentManager.beginTransaction().replace(R.id.layout_for_fragments, currentFragment).commit();
}
drawer.closeDrawer(GravityCompat.START);
return true;
}
The problem also exists when I rotate the device. There is a difference though. When I use the Navigation Drawer menu, none of the methods of the LoaderManager.LoaderCallbacks are called, but when I rotate the device, onLoadFinished is called.
Anyway, the problem persists. Any ideias how to solve it?
Thanks in advance.
I have found the solution!
Basically, I made two mistakes.
The first one is about the rotation of the device.
When the device is rotated, the Activity is destroyed and onCreate is called again. In this case, I should't call new MainFragment(). So, I check if the savedInstanceState is null before I call it, like this:
if (savedInstanceState == null) {
currentFragment = new MainFragment();
FragmentManager fragmentManager = getSupportFragmentManager();
fragmentManager.beginTransaction().
replace(R.id.layout_for_fragments, currentFragment).commit();
}
The second one is about a fragment within a fragment. In this case, I can't simply call getSupportFragmentManager(). I should call getChildFragmentManager() instead and that's it!

Finding Displayed Fragment with ViewPager or FragmentPagerAdapter

I have a main activity that extents ActionBarActivity and implements ActionBar.TabListener
public class MainActivity extends ActionBarActivity implements ActionBar.TabListener {
SectionsPagerAdapter mSectionsPagerAdapter;
ViewPager mViewPager;
View mView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 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.
mSectionsPagerAdapter = new SectionsPagerAdapter(getSupportFragmentManager());
// Set up the ViewPager with the sections adapter.
mViewPager = (ViewPager) findViewById(R.id.pager);
mViewPager.setAdapter(mSectionsPagerAdapter);
// When swiping between different sections, select the corresponding
// tab. We can also use ActionBar.Tab#select() to do this if we have
// a reference to the Tab.
mViewPager.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
#Override
public void onPageSelected(int position) {
actionBar.setSelectedNavigationItem(position);
}
});
// For each of the sections in the app, add a tab to the action bar.
for (int i = 0; i < mSectionsPagerAdapter.getCount(); i++) {
// Create a tab with text corresponding to the page title defined by
// the adapter. Also specify this Activity object, which implements
// the TabListener interface, as the callback (listener) for when
// this tab is selected.
actionBar.addTab(
actionBar.newTab()
.setText(mSectionsPagerAdapter.getPageTitle(i))
.setTabListener(this));
}
}
}
When a button is clicked on one of the fragments controlled by MainActivity, I have to create an intent and start another activity:
public void goToHighScore(View view) {
Intent intent = new Intent(this, DisplayScoreActivity.class);
//TextView nView = (TextView) mViewPager.getChildAt(2).findViewById(R.id.label);
TextView nView = (TextView) findViewById(R.id.label);
String highScore = nView.getText().toString();
intent.putExtra(HIGH_SCORE, highScore);
startActivity(intent);
}
However the "highScore" value is always the one equal to the fragment proceeding it?
All answers are appreciated. Thank you for bearing with me.
-Paul T.
You can get the current fragment by:
Fragment currentFragment = mSectionsPagerAdapter.getItem(mViewPager.getCurrentItem());
Update your fragment to get the score:
Class CustomFragment extends Fragment{
private TextView nView;
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
nView = view.findViewById(R.id.label);
}
public String getScore(){
return nView.getText().toString();
}
}
And function will look like:
public void goToHighScore(View view) {
Intent intent = new Intent(this, DisplayScoreActivity.class);
Fragment currentFragment = mSectionsPagerAdapter.getItem(mViewPager.getCurrentItem());
String highScore = currentFragment.getScore();
intent.putExtra(HIGH_SCORE, highScore);
startActivity(intent);
}
However, I will suggest you to handle the onClick event in your fragment to provide better encapsulation. Update your fragment as follows:
Class CustomFragment extends Fragment{
private TextView nView;
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
nView = view.findViewById(R.id.label);
Button button = (Button)findViewByid(R.id.button)
button.setOnClickListener(new View.OnClickListener(){
public void onClick(View v){
String highScore = nView.getText().toString()
intent.putExtra(HIGH_SCORE, highScore);
startActivity(intent);
}
});
}
}
By doing this your Fragment can be attached to different activity without functionality broke down.

Removing a fragment not working

I want to remove a fragment and show a toast when I click a textView. My code shows the toast, but doesn't remove the fragment.
My method:
public void hide(View view) {
My_frag myFrag= new My_frag();
FragmentTransaction transaction = getSupportFragmentManager()
.beginTransaction();
transaction.remove(myFrag);
transaction.commit();
Toast.makeText(getApplicationContext(), "Hello", Toast.LENGTH_LONG)
.show();
}
My_frag class:
public class My_frag extends android.support.v4.app.Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.my_frag_layout, container, false);
}
}
At some point you must create and add the Fragment correct? You are re-creating the fragment in your hide(...) method so you are trying to remove something that has never been added. Sure you may have added an instance, but not the instance you are trying to remove.
Instead, create a global variable Fragment fragToRemove in your Activity. When you create the fragment (that is where ever you do transaction.add(fragToRemove = new My_Frag);) you will hold an instance. then change your transaction.remove(myFrag) to transaction.remove(fragToRemove) and it should work just fine.
Take the instance of Fragment Transaction other than that was taken while adding fragment to activity and call remove method on that and pass the same instance of Fragment which was used at the time.
Example:
public class MainActivity extends AppCompatActivity {
FragmentTransaction fragmentTransaction;
BlankFragment blankFragment;
Button b;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
b = (Button) findViewById(R.id.activity_button);
fragmentTransaction = getSupportFragmentManager().beginTransaction();
blankFragment=new BlankFragment(); //Fragment instance
fragmentTransaction.add(R.id.main_layout,blankFragment).commit();
b.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.remove(blankFragment).commit(); //created different
}
});
}
In the same way you can do in fragments also and can also remove fragment X on the click of component of fragment X.

Categories