All fragments visible after rotation - android

i have a problem with fragments when my device is rotate:
i have 5 fragments:
Menu is the first fragment, when activity start, it is launched.
AddUser (simple fragment that i can see when i press a button in menu fragment)
DetailApp (simple fragment that i can see when i press a button in menu fragment)
DetailUser (simple fragment that i can see when i press a button in menu fragment)
ListUser (ListFragment that i can see when i press a button in menu fragment)
When i start my activity in vertical mode, i can see correctly my fragments, when i rotate my smartphone, i can see.. all fragments overlapping!
if i launch ListUser i have:
IllegalArgumentException: No view found for id 0x... for fragment ...
when start my Menu fragments:
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_manager);
this is oncreate
// Check whether the activity is using the layout version with
// the fragment_container FrameLayout. If so, we must add the first fragment
if (findViewById(R.id.fragment_container) != null) {
// However, if we're being restored from a previous state,
// then we don't need to do anything and should return or else
// we could end up with overlapping fragments.
if (savedInstanceState != null) {
return;
}
//first frame show a menu
Menu firstFragment = new Menu();
// In case this activity was started with special instructions from an Intent,
// pass the Intent's extras to the fragment as arguments
firstFragment.setArguments(getIntent().getExtras());
// Add the fragment to the 'fragment_container' FrameLayout
getSupportFragmentManager().beginTransaction()
.add(R.id.fragment_container, firstFragment).commit();
}
fragment container at start is void..
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/fragment_container"
android:layout_width="match_parent"
android:layout_height="match_parent" />
when i press a button and one of fragments start:
#Override
public void onDetailApp(int position) {
// The user selected the headline of an article from the HeadlinesFragment
// Capture the article fragment from the activity layout
DetailApp appFrag = (DetailApp)
getSupportFragmentManager().findFragmentById(R.id.detailapp_fragment);
if (appFrag != null) {
// If article frag is available, we're in two-pane layout...
// Call a method in the ArticleFragment to update its content
appFrag.updateAppointmentView(position);
} else {
// If the frag is not available, we're in the one-pane layout and must swap frags...
// Create fragment and give it an argument for the selected article
DetailApp newFragment = new DetailApp();
Bundle args = new Bundle();
args.putInt(DetailApp.ARG_APPOINTMENT, 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();
}
}
this is onCreateView from DetailUser, AddUser, DetailApp:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// If activity recreated (such as from screen rotate), restore
// the previous article selection set by onSaveInstanceState().
// This is primarily necessary when in the two-pane layout.
if (savedInstanceState != null) {
mCurrentPosition = savedInstanceState.getInt(ARG_POSITION);
}
// Inflate the layout for this fragment
return inflater.inflate(R.layout.detail_adduser, container, false);
}
Who can help me?

replace
getSupportFragmentManager().beginTransaction()
.add(R.id.fragment_container, firstFragment).commit();
by
getSupportFragmentManager().beginTransaction()
.replace(R.id.fragment_container, firstFragment).commit();
99% of times it solves duplication issues.

i add this on my Manifest activity and override onConfigurationChanged:
android:configChanges="keyboardHidden|orientation|screenSize"
<activity
android:name="com.map.manager.ManagerActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:label="#string/title_activity_manager" >
</activity>
and i have no more problems! i can see correctly layout vertical and horizontal (when i rotate the smartphone).
but i found this: why-not-use-always-androidconfigchanges
must i put in "blacklist" all possible configuration change? locale touchscreen screenSize etc?

Related

Come back to fragment, Android

I have an activity called MainActivity with 2 fragment (let's call them A and B). This activity shows A on the left and B on the right in case of large display, but, for small display, there is only one frameLayout and I change the fragment in it after I clicked something in the fragment B.
So, for small device, I show initially fragment A and from it I can go to B, (I select a day from my CalendarView in fragment A and then I can go to B).
In B then I can go to another Activity by clicking a button. From that activity I want to came back to my previously activity but I don't know how to have the fragment B already inflated. Right now if I go back to my MainActivity I find fragment A also if I left this activity with B inflated.
I can come back either with the back button on my actionbar or after I close my last activity (the one I go after B).
Can anyone help me?
This is the Main activity class in which I have the two fragments.
public class MainActivity extends AppCompatActivity implements CalendarFragment.OnCalendarSelectedListener{
private ActionBar actionBar;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
actionBar=getSupportActionBar();
if(findViewById(R.id.left_fragment) != null){
if (savedInstanceState != null) {
return;
}
// Create a new Fragment to be placed in the activity layout
AFragment leftFragment = new AFragment();
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.add(R.id.left_fragment, leftFragment).commit();
}
// Check that the activity is using the layout version with
// the fragment_container FrameLayout
if (findViewById(R.id.right_fragment) != null) {
// However, if we're being restored from a previous state,
// then we don't need to do anything and should return or else
// we could end up with overlapping fragments.
if (savedInstanceState != null) {
return;
}
// Create a new Fragment to be placed in the activity layout
BFragment bFragment = new BFragment();
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.add(R.id.right_fragment, bFragment).commit();
}
}
...
//this is how I inflate the fragment B from a click on fragment A
public void onCalendarSelected(int day, int month, int year) {
BFragment bFragment = (BFragment)
getSupportFragmentManager().findFragmentById(R.id.right_fragment);
if (bFragment != null) {
bFragment.updateList(day);
} else {
actionBar.setDisplayHomeAsUpEnabled(true);
BFragment newFragment = new BFragment();
Bundle args = new Bundle();
args.putInt("day",day);
newFragment.setArguments(args);
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.left_fragment, newFragment);
transaction.addToBackStack(null);
// Commit the transaction
transaction.commit();
}
}
This code works fine but I don't know how to solve my problem.

Android - fragment onActivityCreated() not getting called after .replace

My main application has a blanck FrameLayout the reason for this is so that I can on the go, add and replace fragments to it...
I have had no issue with this until now. I have successfully added the first fragment and the onCreate gets called etc, then in my code using a button I replace the FrameLayout with my second fragment which seems to execute, however not showing? as onActivityCreated() does not get called.
My main application calls FrameLayout xml file known as send_activity
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
sendControlFragment sendControlFragment = new sendControlFragment();
peerItemFragment fragmentList = new peerItemFragment();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.send_activity);
if (findViewById(R.id.fragment_container) != null) {
// However, if we're being restored from a previous state,
// then we don't need to do anything and should return or else
// we could end up with overlapping fragments.
if (savedInstanceState != null) {
return;
}
// Create a new Fragment to be placed in the activity layout
sendControlFragment controlFragment = new sendControlFragment();
// Add the fragment to the 'fragment_container' FrameLayout
fragmentTransaction.add(R.id.fragment_container, controlFragment).commit();
}
}
The above works perfectly...
The button which I call the second fragment, I got told to initiate a new FragmentTransaction which I have done, however this does not call the onActivityCreated() and skips to fragmentList.addPeers(mService.peerList);
This is great that it is calling the addPeers() method however without the onActivityCreated() then it crashes!
public void authenticateClick(View v) {
mService.peerSearch();
peerItemFragment peerFragment = new peerItemFragment();
FragmentTransaction fragmentTransactionauthen = fragmentManager.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
fragmentTransactionauthen.replace(R.id.fragment_container, peerFragment);
fragmentTransactionauthen.addToBackStack(null);
// Commit the transaction
fragmentTransactionauthen.commit();
//pass peer list to fragment to display
fragmentList.addPeers(mService.peerList);
}
Can you please suggest a solution as .replace currently to my knowledge doesnt call the onActivityCreated() method...
Because i was using a listfragment I had to replace my listView id to the following, as this was causing fatal error!
android:id="#android:id/list"
it now works and replaces fragments.

Fragment Transaction load empty view but fragment is shown after rotating device

I am building a navigation drawer as designed by the google documentation however I have an issue where the fragment is not being replaced. http://developer.android.com/training/implementing-navigation/nav-drawer.html
When the app first loads, the default fragment is loaded.
Clicking on another item on the drawer list leaves an empty view
However on rotating the device, loads the fragment chosen.
public void selectNavActivty(int position){
// TODO Changing between the different screens selection
fragment = null;
switch (position) {
case 0:
fragment = OverLay.newInstance();
break;
case 1:
fragment = Dummy.newInstance();
break;
}
if(fragment != null) {
// attach added to handle viewpager fragments
FragmentTransaction trans = getSupportFragmentManager().beginTransaction();
trans.replace(R.id.content_frame, fragment).attach(fragment)
.addToBackStack(null);
trans.commit();
getFragmentManager().executePendingTransactions();
} else {
Log.d("Drawer Activity","Error in creating Fragment");
}
}
For navigation menu fragment transactions I use the following approach, this way the fragment will be added and placed on top.
String name = "myFragment";
getSupportFragmentManager()
.beginTransaction()
.replace(R.id.content_frame, fragment, name)
.commit();
Look up the attach() function. It follows a different fragment lifecycle.
Also make sure that your layout files framelayout is visible.
Modify your code as below:
if(fragment != null) {
// attach added to handle viewpager fragments
FragmentTransaction trans = getSupportFragmentManager().beginTransaction();
trans.replace(R.id.content_frame, fragment);
trans.addToBackStack(null);
trans.commit();
} else {
Log.d("Drawer Activity","Error in creating Fragment");
}
If the solution doesn't work for you, share the xml code along with your fragment code.
After adding Fragment it will be added to activity state and its view
will be added to defined Container view. But by attaching nothing will
be displayed if fragment was not already added to UI. It just attaches
to fragment manager. However if view was already added to a container
in UI and detached after that, by attaching it will be displayed again
in its container. Finally you can use attach and detach if you want to
destroy fragment View temporarily and want to display and build its
view on future without losing its state inside activity.
https://stackoverflow.com/a/18979024/3329488
My solution is to tag all the fragment with unique tag on fragment replacement. Make sure you also assign a unique tag to the default fragment during it creation. A more efficient way is to identify the fragment before you recreate the same one.
public void selectNavActivty(int position){
// TODO Changing between the different screens selection
FragmentManager fragmentManager = getSupportFragmentManager();
fragment = fragmentManager.findFragmentById(R.id.content_frame);
String fragmentTag = null;
switch (position) {
case 0:
fragmentTag = "case0Tag"; // please change to better tag name
break;
case 1:
fragmentTag = "case1Tag"; // please change to better tag name
break;
default:
Log.d("Drawer Activity","Error in creating Fragment");
return;
}
if (fragmentTag != null && !fragment.getTag().equals(fragmentTag))
fragmentManager.beginTransaction().replace(R.id.content_fragment, fragment, tag).commit();
}
In my case after rotating a device a blank fragment was shown. I understood that in an Activity.onCreate() I always called creating a blank Fragment and after that a needed one. So I changed it's behaviour to this:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
if (savedInstanceState == null) {
openEmptyFragment()
openAnotherFragment()
}
}
I recommend to check savedInstanceState != null before adding new fragments, as written in Why won't Fragment retain state when screen is rotated?.

Android Fragment Basics Tutorial

So I've been stuck on the third tutorial on the Android Developer Site about Fragments for few days. I just can't understand how the app populates data when I run the app on a tablet (big screen layout). I can understand how the data is being populated on a smaller screen (phone screen).
How does the bigger screen list populate with data?
Here is a link of the whole project from Android.com tutorials.
MainActivity Class
public class MainActivity extends FragmentActivity
implements HeadlinesFragment.OnHeadlineSelectedListener {
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//Here, the system will decide which news_article layout it will use based on the screen size. Will use layout if small or layout-large if it's big.
setContentView(R.layout.news_articles);
// Check whether the activity is using the layout version with
// the fragment_container FrameLayout. If so, we must add the first fragment
//This check is to determine which layout to be used, either small screen or big screen.
//fragment_container used FrameLayout for small screens.
//fragment_container is the id of FrameLayout in news_article for small screen.
if (findViewById(R.id.fragment_container) != null) {
// However, if we're being restored from a previous state,
// then we don't need to do anything and should return or else
// we could end up with overlapping fragments.
if (savedInstanceState != null) {
return;
}
// Create an instance of ExampleFragment
HeadlinesFragment firstFragment = new HeadlinesFragment();
// In case this activity was started with special instructions from an Intent,
// pass the Intent's extras to the fragment as arguments
firstFragment.setArguments(getIntent().getExtras());
// Add the fragment to the 'fragment_container' FrameLayout
getSupportFragmentManager().beginTransaction()
.add(R.id.fragment_container, firstFragment).commit();
}
}
public void onArticleSelected(int position) {
// The user selected the headline of an article from the HeadlinesFragment
// Capture the article fragment from the activity layout
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 {
// If the frag is not available, 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();
}
}
}
HeadLineFragment
public class HeadlinesFragment extends ListFragment {
// The container Activity must implement this interface so the frag can deliver messages
public interface OnHeadlineSelectedListener {
/** Called by HeadlinesFragment when a list item is selected */
public void onArticleSelected(int position);
}
OnHeadlineSelectedListener mCallback;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// We need to use a different list item layout for devices older than Honeycomb
int layout = Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB ?
android.R.layout.simple_list_item_activated_1 : android.R.layout.simple_list_item_1;
// Create an array adapter for the list view, using the Ipsum headlines array
setListAdapter(new ArrayAdapter<String>(getActivity(), layout, Ipsum.Headlines));
}
#Override
public void onStart() {
super.onStart();
// When in two-pane layout, set the listview to highlight the selected list item
// (We do this during onStart because at the point the listview is available.)
if (getFragmentManager().findFragmentById(R.id.article_fragment) != null) {
getListView().setChoiceMode(ListView.CHOICE_MODE_SINGLE);
}
}
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
// This makes sure that the container activity has implemented
// the callback interface. If not, it throws an exception.
try {
mCallback = (OnHeadlineSelectedListener) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString()
+ " must implement OnHeadlineSelectedListener");
}
}
#Override
public void onListItemClick(ListView l, View v, int position, long id) {
// Notify the parent activity of selected item
mCallback.onArticleSelected(position);
// Set the item as checked to be highlighted when in two-pane layout
getListView().setItemChecked(position, true);
}
}
Layout for small screen
news_article.xml
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/fragment_container"
android:layout_width="match_parent"
android:layout_height="match_parent" />
Layout for bigscreen
news_article.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal" >
<fragment android:name="com.example.android.fragments.HeadlinesFragment"
android:id="#+id/headlines_fragment"
android:layout_weight="1"
android:layout_width="0dp"
android:layout_height="match_parent" />
<fragment android:name="com.example.android.fragments.ArticleFragment"
android:id="#+id/article_fragment"
android:layout_weight="2"
android:layout_width="0dp"
android:layout_height="match_parent" />
</LinearLayout>
Notice the placement of the two layouts.
Large screen is in a tablet bin (folder) res/layout-large/main.xml while small screen layout is in generic res/layout/main.xml
Since the java asks if the findViewById is null we know if the device is a large screen or normal layout.
ArticleFragment articleFrag = (ArticleFragment) getSupportFragmentManager().findFragmentById(R.id.article_fragment);
if (articleFrag != null) {
/* not null because we are in res/layout-large */
} else {
/* we are in single pain view /res/layout/... */
}
When you call setContentView(int); they system handles loading the best layout you provided for the device based on the DPI bins provided.
I think, this question is related with this post: http://developer.android.com/training/multiscreen/screensizes.html
Note: large qualifier mean that layout will be selected on devices with screens classified as large (for example, 7" tablets and above). The other layout (without qualifiers) will be selected for smaller devices;
Also if you want to use for small screens two-pane layout, create directory:
res/layout-sw600dp/main.xml;
About Data Population:
In MainActivity you have implemented interface OnHeadlineSelectedListener, when you click on item from list (HeadLinesFragment class)
interface mCallback call function from MainActivity onArticleSelected(position);
in this function you have articleFlag
ArticleFragment articleFlag = (ArticleFragment) getSupportFragmentManager(). findFragmentById(R.id.article_fragment);
if(articleFlag != null){
//we have 2 panes (big screen)
articleFlag.updateArticleView(position);
}else{
//small screen
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();
}

Android fragment - different layout into fragment

I'm trying to develop an application compatible with smartphones (one pane layout) and tablets (two panes layout). My app is displayed as shown below:
(source: android10.org)
I used the example available in Google developers website.
The example works fine. But for my app, I need to use different layout in the WebView fragment. Each element selected in ListView fragment shows a specific layout into the right fragment.
This is my code called when an element is clicked :
public void onArticleSelected(int position) {
// The user selected the headline of an article from the
// HeadlinesFragment
// Capture the article fragment from the activity layout
BodyFragment articleFrag = (BodyFragment) getSupportFragmentManager().findFragmentById(R.id.body_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 {
// If the frag is not available, we're in the one-pane layout and
// must swap frags...
// Create fragment and give it an argument for the selected
// article
BodyFragment newFragment = new BodyFragment();
Bundle args = new Bundle();
args.putInt(BodyFragment.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();
}
}
How can I should make it? I thought to replace dynamically the layout into the fragment, but it is not possible.
Is anybody has a solution?
thanks in advance

Categories

Resources