Set landscape orientation for fragment in Single Activity Architecture - android

How to achieve to lock screen orientation for only one Fragment in Single Activity Architecture (only one Activity for whole app)?
Is there better solution than specify requested orientation in each Fragment?
I'm trying to avoid putting activity?.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED to each unrelated Fragment

Let me start by saying that #madlymad has the right idea, and you should create a BaseFragment class if you haven't already.
However if for some reason you can't or don't want to, you can instead set the orientation in the Fragment's onAttached(), onCreate() or onCreateView()
activity?.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
and then reset in their respective counterparts onDetached(), onDestroy() or onDestroyView()
activity?.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED
This will ensure that you only get different orientation in the correct fragment.

Add below line where you want to fragment in Landscape Mode:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
// Inflate the layout for this fragment
//ADD BELOW LINE
getActivity().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
view = inflater.inflate(R.layout.fragment_dashboard, container, false);
return view;
}
If you add above code in fragment then all fragment are show in Landscape mode. But You want to a single fragment. so in Other Fragment add below code
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
// Inflate the layout for this fragment
//ADD BELOW LINE
getActivity().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
view = inflater.inflate(R.layout.fragment_inventory, container, false);
return view;
}
Note: No need to add Orientation in manifest.xml

I would extend the Fragment and create a BaseFragment for all my fragments. At this base fragment I would use the activity?.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_SENSOR
public abstract class BaseFragment extends Fragment {
#Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
if(isVisibleToUser) {
Activity a = getActivity();
if(a != null)
a.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR);
}
}
}
For the specific locked fragment I would just use the activity?.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE.
public class LandscapeFragment extends BaseFragment {
#Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
if(isVisibleToUser) {
Activity a = getActivity();
if(a != null)
a.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
}
}
}
The only change you would now have is to make all your fragments extend the BaseFragment instead of Fragment, but this can be beneficial in other shared features as well.
I am not familiar with Kotlin but Kotlin code may be like this:
abstract class BaseFragment : Fragment() {
override fun setUserVisibleHint(isVisibleToUser : Boolean){
super.setUserVisibleHint(isVisibleToUser)
if(isVisibleToUser) {
getActivity()?.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR)
}
}
}
class LandscapeFragment : BaseFragment() {
override fun setUserVisibleHint(isVisibleToUser : Boolean) {
super.setUserVisibleHint(isVisibleToUser)
if(isVisibleToUser) {
getActivity()?.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE)
}
}
}

If it is activity you can specify in manifest file only for activity tag.
In case for fragment in activity means i guess you can you below code
getActivity().setRequestedOrientation(
ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
in activity i.e write a method by passing boolean if true PORTRAIT else LANDSCAPE and call it from fragment. I mean if the activity contains different fragments which requires different orientations.

Orientation attribute is per activity so you can declare the orientation for only the activity that contains the fragment so that it is in landscape and the rest of the activities will remain as they are.
Use the following code line in the fragment where you want a specific (in this case portrait) orientation.
getActivity().setRequestedOrientation(
ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
If you want to have an orientation in a fragment, that is based on the way the user holds his device, then use the following code line.
getActivity().setRequestedOrientation(
ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);

<activity
android:name=".user_interface.activities.MainActivity"
android:screenOrientation="landscape"
android:theme="#style/MyMaterialTheme"/>

I had the same scenarios as yours, I call all my fragments from my Activity. Which way i can have the code in one place.
int id = item.getFragmentId();
if (id == R.id.nav_camera) {
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
} else {
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
}
// Here you can have your fragment calls
getSupportFragmentManager().beginTransaction().replace(
R.id.content_main,
new YourFragmentForId(),
NotificationFragment.class.getSimpleName())
.commit();
I still think this is the best way to do it.

Related

how to access fragments elements in MainActivity()?

In my project, I want to set visibility of fragments buttons from MainActivity. But the problem is, it gives NullPointerException(). I also maked listBtn & gridBtn as static. I used below code :
FirstFragment fragment = (FirstFragment)getSupportFragmentManager().findFragmentById(R.id. <frameLayout Id>);
main_page_fragment.listBtn.setVisibility(View.GONE);
main_page_fragment.gridBtn.setVisibility(View.GONE);
You cannot access to your fragment view from Activity class because activity uses its own view (ex: R.layout.activity_main). Rather you can set visibility in your corresponding fragment class which will do the same job.
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.details, container, false);
Button listBtn = (Button)view.findviewById(R.id.listBrn);
Button gridBtn = (Button)view.findviewById(R.id.gridBrn);
listBtn.setVisibility(View.GONE);
gridBtn.setVisibility(View.GONE);
return view;
}
Fragment onCreateView callback is called after onCreate method of activity, so i think you have tried to get access from it. That views will be accessible only after onResumeFragments callback is called, you should perform your actions with fragments there.
Another tip is that you strongly should not call views of fragments directly like you did or via static reference to views that's the worst. You should avoid such dependencies on fragments inner implementation. Instead of it, better is create some method like setInitialState (the name depends on your business logic) and just call it from activity.
So result code:
In activity:
private FirstFragment fragment;
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//init fragment here
}
#Override
protected void onResumeFragments() {
super.onResumeFragments();
fragment.setInitialState();
}
In fragment:
//this will be called on fragment #onResume step, so views will be ready here.
public void setInitialState() {
listBtn.setVisibility(View.GONE);
gridBtn.setVisibility(View.GONE);
}
If you add your fragments dynamically from MainActivity like so:
YourFragment fragment = new YourFragment();
FragmentManager fragmentManager = getSupportFragmentManager();
fragmentManager.beginTransaction()
.replace(R.id.fragmentContainer, fragment, YOUR_TAG)
.commit();
Then you can define method in your fragment like so:
public void hideButtons()
{
yourBtn.setVisibility(View.GONE);
}
And call it from activity:
fragment.hideButtons();
I struggle with this for several hours and I found a much simpler solution.
Inside the fragment, simply make a public function (outside the on create view method) with the behavior that you want.
fun hideElement() {
binding.button.visibility = View.GONE
}
And then in main activity access to the fragment and call the function.
binding.bottomNavigation.setOnNavigationItemSelectedListener {
when (it.itemId){
R.id.someFragment -> someFragment.hideElement()
}
}

How to listen when a fragment is on the screen

What I need is exactly an onResume method (as it works for activities) for a specific fragment. I'm adding the fragment (let's say fragment A) to the back stack, and opening another fragment (fragment B) (again adding to back stack) from fragment A. I want to update toolbar when fragment B is closed and fragment A is on screen again. I expect onCreateView to get called but it's not getting called when I pop fragment B. I also tried adding an OnBackStackChangedListener to fragment A but then I cannot track which fragment is on the screen when the back stack changes.
So my question is how to make onCreateView get called when I turn back to fragment A. And if this is not a good practice, how else can I track this event?
Edit
I'm showing new fragments with this code:
getSupportFragmentManager().beginTransaction()
.add(R.id.content, fragment)
.addToBackStack(tag)
.commit();
Should I change it somehow to make onCreateView get called? Since I'm adding new fragment B on existing fragment A (I can even click on a button which is in fragment A when B is on the screen), when I pop fragment B, nothing changes with fragment A's situation.
Override this method in the Fragment and check the boolean value
#Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
//Log.e("setUserVisibleHint", "isVisibleToUser " + isVisibleToUser);
}
Put the code that you need to be executed whenever the fragment becomes visible/is hidden in this method, according to the isVisibleToUser boolean value
Did you try OnBackStackChangedListener this way?
public class BlankFragment2 extends Fragment {
public BlankFragment2() {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
getFragmentManager().addOnBackStackChangedListener(new FragmentManager.OnBackStackChangedListener() {
#Override
public void onBackStackChanged() {
if(getFragmentManager()==null)
return;
Fragment fr = getFragmentManager().findFragmentById(R.id.container)//id of your container;
if (fr instanceof BlankFragment2) {
//On resume code goes here
}
}
});
return inflater.inflate(R.layout.fragment_blank_fragment2, container, false);
}
}
I hope this solution will works.
1) Put/call addOnBackStackChangedListener on your Activity
getSupportFragmentManager().addOnBackStackChangedListener(backStacklistener);
2) Define backStacklistener inside your Activity
FragmentManager.OnBackStackChangedListener backStacklistener = new FragmentManager.OnBackStackChangedListener() {
public void onBackStackChanged() {
FragmentManager manager = getSupportFragmentManager();
if (manager != null) {
Fragment fragment = manager.findFragmentById(R.id.fragment);
if(fragment instanceof OutboxFragment) {
OutboxFragment currFrag = (OutboxFragment) fragment;
currFrag.onFragmentResume();
}
}
}
};
3) Provide a method on your fragment that you want to be triggered. In this case I create method named onFragmentResume()
public void onFragmentResume() {
MainActivity activity = (MainActivity) getActivity();
activity.showFab();
// or do another thing here
}
Good luck!

How to know if a Fragment already called onCreateView()

We all know that when using ViewPager with Fragment and FragmentPagerAdapter we get 3 Fragment loaded: the visible one, and both on each of its sides.
So, if I have 7 Fragments and I'm iterating through them to see which 3 of them are the ones that are loaded, and by that I mean onCreateView() has already been called, how can I determine this?
EDIT: The Fragment doesn't have to be the one that the ViewPager is showing, just that onCreateView() has already been called.
Well logically, this would be a reasonable test if onCreateView has been called:
myFragment.getView() != null;
Assuming you a have a reference to all of the fragments in the pager iterate, them and check if they have a view.
http://developer.android.com/reference/android/app/Fragment.html#getView()
Update
The above answer assumes that your fragments always create a view, and are not viewless fragments. If they are then I suggest sub classing the fragment like so:
public abstract class SubFragment extends Fragment
{
protected boolean onCreateViewCalled = false;
public boolean hasOnCreateViewBeenCalled()
{
return onCreateViewCalled;
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup Container, Bundle state){
onCreateViewCalled = true;
return null;
}
}
Just bear in mind that further sub classes will have to call super or set the flag themselves should they override onCreateView as well.
I added an interface to Fragment. Looks like:
protected OnCreateViewCallback createViewCallback = null;
public void setCreateViewCallback(OnCreateViewCallback createViewCallback) {
this.createViewCallback = createViewCallback;
}
public interface OnCreateViewCallback {
void onCreateView();
}
In my onCreateView():
//initialize your view.
if (createViewCallback != null) {
createViewCallback.onCreateView();
createViewCallback = null;
}
return mainView;
From my activity:
if (ocrFragment.getView() == null) {
ocrFragment.setCreateViewCallback(new MainScreenFragment.OnCreateViewCallback() {
#Override
public void onCreateView() {
ocrFragment.ocrImage(picture, false);
}
});
} else {
ocrFragment.ocrImage(picture, false);
}
If you are trying to perform something after onCreateView is called, use onViewCreated:
Called immediately after onCreateView(LayoutInflater, ViewGroup,
Bundle) has returned, but before any saved state has been restored in
to the view. This gives subclasses a chance to initialize themselves
once they know their view hierarchy has been completely created. The
fragment's view hierarchy is not however attached to its parent at
this point.
public void onViewCreated(View view, Bundle savedInstanceState) {
MyActivity myActivity = (MyActivity) getActivity();
MyActivity.newAsyncTask(mPar);
}
You could also check for Fragment.isVisible() because a Fragment is in visible state when it's in the offscreen page limit of a ViewPager.
Edit: But it just really depends on what you really want to achieve with your question. Perhaps some kind of update to all UIs in your Fragments when their UI is ready?
EDIT:
Just another addition, you could listen to onViewCreated() and set a flag. Or notify your Activity and do further work (getActivity() will return your Activity at this point). But really, better state what you want to accomplish with your question.

Setting the orientation for only 1 fragment in my activity while the rest is in portrait

My app needs to be in portrait mode so I set it in the manifest by:
android:screenOrientation="portrait"
But I just recently added another fragment (FragA) that just looks and functions 10x better in landscape. Is there something I can put inside of my FragA to just make that fragment in landscape while retaining the rest of the app in portrait or by doing this will I have to add something to my other fragments to keep them retained as portrait?
Use the following code line in the fragment where you want a specific (in this case portrait) orientation.
getActivity().setRequestedOrientation(
ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
If you want to have a orientation in a fragment, that is based on the way the user holds his device, then use the following code line.
getActivity().setRequestedOrientation(
ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
Hope, this will give you the intended solution.
In each of your fragments, set the requested orientation.
Reference doc: http://developer.android.com/reference/android/content/pm/ActivityInfo.html
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Fragment locked in portrait screen orientation
getActivity().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
// Fragment locked in landscape screen orientation
getActivity().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
// Fragment screen orientation normal both portait and landscape
getActivity().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
}
Orientation attribute is per activity so you can declare the orientation for only the activity that contains the fragment so that it is in landscape and the rest of the activities will remain as they are.
So I'm dealing with this issue now. We have only portrait mode application (for now). But there is one fragment that needs to be in landscape. We are using single Activity approach so the accepted answer will not help me.
The fastest solution I could think of is this one.
private var swappingOrientation = false
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
if(savedInstanceState == null) {
swappingOrientation = true
activity?.apply {
requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE
}
}
}
override fun onDestroy() {
super.onDestroy()
if(!swappingOrientation) {
activity?.apply {
requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
}
}
swappingOrientation = false
}
You hold the information if you are swapping orientation or not in swappingOrientation variable. At the beggining when the fragment is created it will change orientation, only when there is no saved state. And orientation is changed back again only when it is not being currently changed.
This is a super quick solution and it can produce screen blinking when you return to previous fragment. I also did not fully test it so it can have other issues, so keep that in mind.
First Fragment:
#Override
public void onResume() {
super.onResume();
getActivity().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
}
Second Fragment:
#Override
public void onResume() {
super.onResume();
getActivity().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
}
This is old question but answering this just incase anyone wanted the solution as the OP needed. The simple way to achieve this is as follows.
public class LandscapeFragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
getActivity().setRequestedOrientation(
ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
}
#Override
public View onDestroyView() {
super.onDestroyView();
getActivity().setRequestedOrientation(
ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
}
Then extend this LandscapeFragment from any of your fragment to which you want to launch it in landscape mode.
ok after i almost blew my head off this worked for me with jetpack navigation components fragments
so this is the base fragment class
abstract class BaseFragment : Fragment(){
var rotated = false
fun rotate() {
val currentOrientation = activity?.resources?.configuration?.orientation //this is diffrent from Configuration.ORIENTATION_LANDSCAPE
Log.e("currentOrientation--->",currentOrientation.toString())
if (currentOrientation != null) {
if (currentOrientation != Configuration.ORIENTATION_LANDSCAPE) {
activity?.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE
}else{
rotated=true
}
}else{
//impossible
activity?.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE
}
}
override fun onDestroyView() {
super.onDestroyView()
if (rotated)
activity?.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED
}
}
and i put this in any fragment i wish it to be landscaped
override fun onStart() {
super.onStart()
rotate()
}

Fragment gets initialized twice when reloading activity with tabs when orientation changes

I have a problem reloading an activity with tabs and fragments when I change the orientation of my device.
Here's the situation:
I have an activity which has 3 tabs in the action bar. Each tab loads a different fragment in a FrameLayout in main view. Everything works fine if I don't change the orientation of the device. But when I do that Android tries to initialize the currently selected fragment twice which produce the following error:
E/AndroidRuntime(2022): Caused by: android.view.InflateException: Binary XML file line #39: Error inflating class fragment
Here's the sequence of steps that produce the error:
I load the activity, select tab nr 2. and change the orientation of the device.
Android destroys the activity and the instance of the fragment loaded by tab nr 2 (from now on, 'Fragment 2'). Then it proceeds to create new instances of the activity and the fragment.
Inside Activity.onCreate() I add the first tab to the action bar. When I do that, this tab gets automatically selected. It may represent a problem in the future, but I don't mind about that now. onTabSelected gets called and a new instance of the first fragment is created and loaded (see code below).
I add all the other tabs without any event being triggered, which is fine.
I call ActionBar.selectTab(myTab) to select Tab nr 2.
onTabUnselected() gets called for the first tab, and then onTabSelected() for the second tab. This sequence replaces the current fragment for an instance of Fragment 2 (see code below).
Next, Fragment.onCreateView() is called on Fragment 2 instance and the fragment layout gets inflated.
Here is the problem. Android Calls onCreate() and then onCreateView() on the fragment instance ONCE AGAIN, which produces the exception when I try to inflate (a second time) the layout.
Obviously the problem is Android is initializing the fragment twice, but I don't know why.
I tried NOT selecting the second tab when I reaload the activity but the second fragment gets initialized anyway and it is not shown (since I didn't select its tab).
I found this question: Android Fragments recreated on orientation change
The user asks basically the same I do, but I don't like the chosen answer (it's only a workaroud). There must be some way to get this working without the android:configChanges trick.
In case it's not clear, what I want to know how whether to prevent the recreation of the fragment or to avoid the double initialization of it. It would be nice to know why is this happening also. :P
Here is the relevant code:
public class MyActivity extends Activity implements ActionBar.TabListener {
private static final String TAG_FRAGMENT_1 = "frag1";
private static final String TAG_FRAGMENT_2 = "frag2";
private static final String TAG_FRAGMENT_3 = "frag3";
Fragment frag1;
Fragment frag2;
Fragment frag3;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// my_layout contains a FragmentLayout inside
setContentView(R.layout.my_layout);
// Get a reference to the fragments created automatically by Android
// when reloading the activity
FragmentManager fm = getFragmentManager();
this.frag1 = fm.findFragmentByTag(MyActivity.TAG_FRAGMENT_1);
this.frag2 = fm.findFragmentByTag(MyActivity.TAG_FRAGMENT_2);
this.frag3 = fm.findFragmentByTag(MyActivity.TAG_FRAGMENT_3)
ActionBar actionBar = getActionBar();
// snip...
// This triggers onTabSelected for the first tab
actionBar.addTab(actionBar.newTab()
.setText("Tab1").setTabListener(this)
.setTag(MyActivity.TAG_FRAGMENT_1));
actionBar.addTab(actionBar.newTab()
.setText("Tab2").setTabListener(this)
.setTag(MyActivity.TAG_FRAGMENT_2));
actionBar.addTab(actionBar.newTab()
.setText("Tab3").setTabListener(this)
.setTag(MyActivity.TAG_FRAGMENT_3));
Tab t = null;
// here I get a reference to the tab that must be selected
// snip...
// This triggers onTabUnselected/onTabSelected
ab.selectTab(t);
}
#Override
protected void onDestroy() {
// Not sure if this is necessary
this.frag1 = null;
this.frag2 = null;
this.frag3 = null;
super.onDestroy();
}
#Override
public void onTabSelected(Tab tab, FragmentTransaction ft) {
Fragment curFrag = getFragmentInstanceForTag(tab.getTag().toString());
if (curFrag == null) {
curFrag = createFragmentInstanceForTag(tab.getTag().toString());
if(curFrag == null) {
// snip...
return;
}
}
ft.replace(R.id.fragment_container, curFrag, tab.getTag().toString());
}
#Override
public void onTabUnselected(Tab tab, FragmentTransaction ft)
{
Fragment curFrag = getFragmentInstanceForTag(tab.getTag().toString());
if (curFrag == null) {
// snip...
return;
}
ft.remove(curFrag);
}
private Fragment getFragmentInstanceForTag(String tag)
{
// Returns this.frag1, this.frag2 or this.frag3
// depending on which tag was passed as parameter
}
private Fragment createFragmentInstanceForTag(String tag)
{
// Returns a new instance of the fragment requested by tag
// and assigns it to this.frag1, this.frag2 or this.frag3
}
}
The code for the Fragment is irrelevant, it just returns an inflated view on onCreateView() method override.
I got a simple answer for that:
Just add setRetainInstance(true); to the Fragment's onAttach(Activity activity) or onActivityCreated(Bundle savedInstanceState).
These two are call-backs in the Fragment Class.
So basically, what setRetainInstance(true) does is:
It maintains the state of your fragment as it is, when it goes through:
onPause();
onStop();
It maintains the instance of the Fragment no matter what the Activity goes through.
The problem with it could be, if there are too many Fragments, it may put a strain on the System.
Hope it helps.
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
setRetainInstance(true);
}
Open for Correction as always. Regards, Edward Quixote.
It seems that, when the screen is rotated and the app restarted, it is recreating each Fragment by calling the default constructor for the Fragment's class.
I have encountered the same issue and used the following workaround:
in the fragment's onCreateView begining of:
if (mView != null) {
// Log.w(TAG, "Fragment initialized again");
((ViewGroup) mView.getParent()).removeView(mView);
return mView;
}
// normal onCreateView
mView = inflater.inflate(R.layout...)
I think this is a fool proof way to avoid re-inflating of the root view of the fragment:
private WeakReference<View> mRootView;
private LayoutInflater mInflater;
/**
* inflate the fragment layout , or use a previous one if already stored <br/>
* WARNING: do not use in any function other than onCreateView
* */
private View inflateRootView() {
View rootView = mRootView == null ? null : mRootView.get();
if (rootView != null) {
final ViewParent parent = rootView.getParent();
if (parent != null && parent instanceof ViewGroup)
((ViewGroup) parent).removeView(rootView);
return rootView;
}
rootView = mFadingHelper.createView(mInflater);
mRootView = new WeakReference<View>(rootView);
return rootView;
}
#Override
public View onCreateView(final LayoutInflater inflater, final ViewGroup container, final Bundle savedInstanceState) {
mInflater=inflater!=null?inflater:LayoutInflater.from(getActivity());
final View view = inflateRootView();
... //update your data on the views if needed
}
add
android:configChanges="orientation|screenSize"
in the manifest file
To protect activity recreate try to add configChanges in your Activity tag (in manifest), like:
android:configChanges="keyboardHidden|orientation|screenSize"
My code was a little different, but I believe our problem is the same.
In the onTabSelected I didn't use replace, I use add when is the first time creating the fragment and attach if isn't. In the onTabUnselected I use detach.
The problem is that when the view is destroyed, my Fragment was attached to the FragmentManager and never destroyed. To solve that I implemented on the onSaveInstanceBundle to detach the fragment from the FragmentManager.
The code was something like that:
FragmentTransition ft = getSupportFragmentManager().begin();
ft.detach(myFragment);
ft.commit();
In the first try I put that code in the onDestroy, but I get a exception telling me that I couldn't do it after the onSaveInstanceBundle, so I moved the code to the onSaveInstanceBundle and everything worked.
Sorry but the place where I work don't allow me to put the code here on StackOverflow. This is what I remember from the code. Feel free to edit the answer to add the code.
I think you are facing what I faced. I had a thread downloader for json which starts in onCreate() , each time I changed the orientation the thread is called and download is fired. I fixed this using onSaveInstance() and onRestoreInstance() to pass the json response in a list, in combination of checking if the list is not empty, so the extra download is not needed.
I hope this gives you a hint.
I solved this problem by using below code.
private void loadFragment(){
LogUtil.l(TAG,"loadFragment",true);
fm = getSupportFragmentManager();
Fragment hf = fm.findFragmentByTag("HOME");
Fragment sf = fm.findFragmentByTag("SETTING");
if(hf==null) {
homeFragment = getHomeFragment();// new HomeFragment();
settingsFragment = getSettingsFragment();// new Fragment();
fm.beginTransaction().add(R.id.fm_place, settingsFragment, "SETTING").hide(settingsFragment).commit();
fm.beginTransaction().add(R.id.fm_place, homeFragment, "HOME").commit();
activeFragment = homeFragment;
}else{
homeFragment = hf;
settingsFragment = sf;
activeFragment = sf;
}
}
Initiate this method in OnCreate();

Categories

Resources