Android fragment popBackStack and replace not removing view - android

I'm trying to learn to use fragments.
Suppose i have one activity, with 2 fragments - FragmentA and FragmentB.
In my activity i add the fragment, with what i thought was the ability to remove a fragment view when i press the back button:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_fullscreen);
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
mFragmentA = new FragmentA();
fragmentTransaction.add(R.id.fragment_container, mFragmentA).addToBackStack("fragA").commit();
}
and in my FragmentA's view, i have 2 buttons. one supposedly for going back, and one for replacing FragmentA with FragmentB.
So here's what FragmentA looks like:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_a_layout, null);
Button backButton = (Button) view.findViewById(R.id.frag_a_back);
backButton.setOnClickListener(new View.OnClickListener(){
#Override
public void onClick(View view) {
getFragmentManager().popBackStack("fragA", FragmentManager.POP_BACK_STACK_INCLUSIVE);
}
});
Button nextButton = (Button) view.findViewById(R.id.frag_a_next);
nextButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
FragmentTransaction ft = getFragmentManager().beginTransaction();
FragmentB fragB = new FragmentB();
ft.replace(R.id.fragment_container, fragB).commit();
}
});
container.addView(view);
return super.onCreateView(inflater, container, savedInstanceState);
}
Question:
When i go to fragmentB or if i press the back button, why does FragmentA's two buttons still show up on the screen? I want the back button to remove FragmentA. Is the fragment getting removed/detached but the view is not?
(i'm using FrameLayout for everything and i can see FragmentA view still there)
EDIT =============================
okay i realized there is a onDestroyView() method, but i'm not sure if it's the right way to remove my FragmentA's views?
it would require me to hold on to an instance of the parent view, and a reference var to my fragment layout view; and that way i can use the parent view to remove all views here

You don't need to do container.addView(view); explicitly. Just return the inflated View. The following changes might help.
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState);
View view = inflater.inflate(R.layout.fragment_a_layout, null);
Button backButton = (Button) view.findViewById(R.id.frag_a_back);
backButton.setOnClickListener(new View.OnClickListener(){
#Override
public void onClick(View view) {
getFragmentManager().popBackStack("fragA", FragmentManager.POP_BACK_STACK_INCLUSIVE);
}
});
Button nextButton = (Button) view.findViewById(R.id.frag_a_next);
nextButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
FragmentTransaction ft = getFragmentManager().beginTransaction();
FragmentB fragB = new FragmentB();
ft.replace(R.id.fragment_container, fragB).commit();
}
});
//container.addView(view);
return view;
}

Related

Fragment goes blank when returning from another activity

There are two activities in my app:
MainActivity (containing 3 fragments)
FragmentHome
FragmentOrders
FragmentAccount
AccountEditActivity
The code to set fragments in MainActivity is this:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
BottomNavigationView navigation = (BottomNavigationView) findViewById(R.id.navigation);
navigation.setOnNavigationItemSelectedListener(mOnNavigationItemSelectedListener);
// set Home as the default fragment
setFragment(FragmentMainHome.getInstance());
}
private void setFragment(Fragment fragment){
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.frame_layout, fragment);
transaction.commit();
}
The code for FragmentAccount is:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
rootView = inflater.inflate(R.layout.fragment_activity_main_account, container, false);
layout = rootView.findViewById(R.id.layout_fragment_main_account);
etName = (EditText) layout.findViewById(R.id.etNameLabelValue);
etEmail = (EditText) layout.findViewById(R.id.etEmailLabelValue);
etGender = (EditText) layout.findViewById(R.id.etGenderLabelValue);
etPhoneNumber = (EditText) layout.findViewById(R.id.etPhoneNumberLabelValue);
btnEditAccount = (ImageButton) layout.findViewById(R.id.btnEditAccount);
btnManageAddresses = (ImageButton) layout.findViewById(R.id.btnAccountManageAddresses);
btnManageAddresses.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
}
});
btnEditAccount.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
}
});
return rootView;
}
The code for FragmentOrders is:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
rootView = inflater.inflate(R.layout.fragment_activity_main_order_history, container, false);
layout = rootView.findViewById(R.id.layout_fragment_main_order_history);
lvOrders = (ListView) layout.findViewById(R.id.lvOrders);
tvNoOrdersFound = (TextView) layout.findViewById(R.id.tvNoOrdersFound);
final SwipeRefreshLayout pullToRefresh = rootView.findViewById(R.id.swipe_refresh_layout_order_history);
pullToRefresh.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
#Override
public void onRefresh() {
// load orders
pullToRefresh.setRefreshing(false);
}
});
lvOrders.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
}
});
return rootView;
}
and similar kind of code goes for FragmentHome
The Problem
I can move between fragments and the view works fine.
Now from Account fragment, I move to AccountEditActivity
I do some update there and come back to MainActivity by pressing hardware back button
FragmentHome is displayed fine but when I click on FragmentAccount, screen goes blank
Now, if I click on Home fragment and click FragmentAccount again, it displays fine.
What is wrong here?
better use viewpager in your activity to show the fragments
it's easy to manage while using viewpagers
have a look at the link
Fragments in viewpager
and in your case just move this code from onCreate to onResume
setFragment(FragmentMainHome.getInstance());
for understanding better have a look at the lifecycle of activity in android
Activity life cycle

Button's onClick method modifying a global variable in Fragment

The code in my fragment is structured as follows:
public class FragmentScanQR extends Fragment {
...
private Button qrFromCameraBtn;
private View rootView;
...
public View onCreateView(final LayoutInflater inflater, final ViewGroup container, Bundle savedInstanceState) {
rootView = inflater.inflate(R.layout.qrsource, container, false);
qrFromCameraBtn = (Button)rootView.findViewById(R.id.qrViaCameraBtn);
qrFromCameraBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
rootView = inflater.inflate(R.layout.fragmenttab1, container, false);
}
});
return rootView;
}
The onCreateView method of fragment returns a value of type android.view.View. The qrFromCameraBtn button's onClick method modifies the same View variable. In the output, when I click on the botton, the layout doesn't change to R.layout.fragmenttab1 (which I wish to achieve) but remains the same. How can I do this?
If I understand what you need, you want to replace your first fragment with a new one. You can do that like so:
//Where Article fragment is your new fragment.
ArticleFragment newFragment = new ArticleFragment();
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();
Source: https://developer.android.com/training/basics/fragments/fragment-ui.html
If you want to just replace the layout,this link might help you.
Android - How to dynamically change fragment layout.
Just add the following code on button click method
qrFromCameraBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
RelativeLayout rl = (RelativeLayout) findViewById(R.id.about);
rl.removeAllViews();
rl.addView(View.inflate(myView.getContext(), R.layout.about, null));
}
});

Android relationships between fragments

I'm using some fragments programmatically in activity. There is one button in my first fragment and when i click to this button, it replaces to second fragment.My second fragment's background is 90% transparent, and when it starts, i can see button which is situated in first fragment, and it also works. I want to stop or do something, because i dont want to see first fragment features and use it.
First Fragment
public class RegistrationFirstFragment extends Fragment {
RegistrationSecondFragment rf;
ImageButton btnNewUser,btnNewAgent;
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
//return super.onCreateView(inflater, container, savedInstanceState);
View v =inflater.inflate(R.layout.fragment_registration_first,container,false);
rf = new RegistrationSecondFragment();
btnNewUser = (ImageButton)v.findViewById(R.id.btnNewUserRegistrationFirstFragment);
btnNewAgent = (ImageButton)v.findViewById(R.id.btnNewAgentRegistrationFirstFragment);
btnNewUser.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Toast.makeText(getActivity(), "Transaction completed succesfully", Toast.LENGTH_LONG).show();
FragmentManager fm = getFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
ft.replace(R.id.flRegistrationFirst, rf);
ft.commit();
}
});
return v;
}
}
Second Fragment
public class RegistrationSecondFragment extends Fragment {
RegistrationFirstFragment rtl;
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
rtl = new RegistrationFirstFragment();
//return super.onCreateView(inflater, container, savedInstanceState);
View v =inflater.inflate(R.layout.fragment_registration_second,container,false);
FragmentManager fm = getFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
// ft.replace(R.id.flRegistrationFirst, rf);
ft.remove(rtl);
ft.commit();
return v;
}
}
Main Activity
public class RegistrationActivity extends AppCompatActivity{
RegistrationFirstFragment fr;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_registration);
fr = new RegistrationFirstFragment();
FragmentManager fm = getSupportFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
ft.add(R.id.flRegistrationFragment,fr);
ft.commit();
}
}
You can put
FragmentManager fragmentManager = getFragmentManager();
fragmentManager.beginTransaction().replace(R.id.content_frame, fragment).commit();
(the parameter fragment would be an instance of your second fragment)
into your onClick(View view){...} method to change the fragment instead of adding it.
Next time code for understanding your problem btw ;)
Add to fragment layout android:clickable="true". Int his way fragment will catch event so the click will not be caught by "main fragment".
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:clickable="true" />
Give android:clickable="true" for Second Fragment root layout parent, when ever fragment opens It catches the click event of root and ignored previous click events.
Second One: If u use replace Fragment it's better than add fragment.
getActivity().getSupportFragmentManager().beginTransaction().replace
(R.id.YOUR_CONTAINER, 'FragmentObject').addToBackStack("TAG").commitAllowingStateLoss();

Fragments the right way

I'm trying out some fragments right now. I've got a fragment with a button and when I click that button I switch to another fragment. Now when I push on the back button I return to the first fragment that's good. Now when I click again on that button a new fragment is started. So I always start a new fragment. I think thats not the way it needs to be done. Is there a better way to for example resume the already created fragment?
My code:
public static class PlaceholderFragment extends Fragment{
public PlaceholderFragment() {
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_main, container, false);
Button test = (Button)rootView.findViewById(R.id.button);
test.setOnClickListener(new OnClickListener()
{
#Override
public void onClick(View view)
{
Log.d("Test", "Button clicked.");
TestFrag newFragment = new TestFrag();
FragmentTransaction transaction = getFragmentManager().beginTransaction();
transaction.replace(R.id.container, newFragment);
transaction.addToBackStack(null);
transaction.commit();
}
});
return rootView;
}
}
public static class TestFrag extends Fragment {
public TestFrag() {
Log.d("Test","New fragment");
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_main2, container, false);
return rootView;
}
}
When you use the fragment transaction you can specify a tag for the fragment
fragmentTransaction.add(R.id.main_fragment, newFragment, fragTag);
fragmentTransaction.commit();
Then later you can find a fragment by tag from the fragmentManager
newFragment = fragMan.findFragmentByTag(fragTag);
if newFragment then is null you should create the Fragment since it wasnt found by the tag
Thanks to Joakim:
fragmentTransaction.add(R.id.main_fragment, newFragment, fragTag); fragmentTransaction.commit();
Then later you can find a fragment by tag from the fragmentManager
newFragment = fragMan.findFragmentByTag(fragTag); if newFragment then is null you should create the Fragment since it wasnt found by the tag. If the tag isn't null you can just add and commit the new one.

tabview with fragments in android

Hi I am creating tabview by extending fragments in one of my tab i have a button when I click that I need to move to another screen but in same tab it is displaying next screen but along with the previous screen what should I do so that I can view only one screen in the tab this is my code below
public class Tab1Fragment extends Fragment {
LinearLayout mLayout;
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
if (container == null) {
return null;
}
LinearLayout theLayout = (LinearLayout)inflater.inflate(R.layout.tab_frag1_layout, container, false);
// Register for the Button.OnClick event
Button b = (Button)theLayout.findViewById(R.id.button1);
b.setOnClickListener(new View.OnClickListener() {
void onContentChanged () {}
#Override
public void onClick(View v) {
Fragment mFragment = new third_fragment_view();
android.support.v4.app.FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.replace(R.id.container, mFragment);
ft.addToBackStack(null);
ft.commit();
//ft.add(R.id.container, mFragment);
}
});
return theLayout;
}
}
Have you tried the code google posted for handling fragment tab activities? It works very well:
http://developer.android.com/reference/android/app/TabActivity.html

Categories

Resources