I have created display using Fragments, both of which is being populated with data pulled from the internet. While the code itself works as expected without any issues, one of a Fragments (implemented as ListFragment) displays an indeterminant progress indicator within the fragment, which is skewed off to the side. I wish to remove the indicator and use a different ProgressDialog I implemented as the indicator instead.
Doing some research, I have discovered the function setListShownNoAnimation() (documented here) in the ListFragment class, but the following attempts didn't work:
Calling setListShownNoAnimation() in the fragment's onActivityCreated()
Calling it in the parent activity's onCreate
Calling it in the fragment's onCreateView() (this caused an IllegalStateException)
How can I remove the fragment's progress indicator?
The right way to do this is to call:
setListShown(true);
when you need the ProgressBar to be hidden and show the ListView. Call this when you are finished getting the data in the background and are ready to show the list.
This workaround may not be the best method to solve this, but it works nicely:
What I did was first make the Fragment not display at all when I declared it in the layout.xml file:
<fragment class="com.example.MyListFragment"
android:id="#+id/frag_list"
android:layout_width="0dp"
android:layout_height="match_parent"
android:visibility="gone" />
Then after the data has been downloaded and processed, I would then display the Fragment using a FragmentTransaction:
FragmentManager fm = getFragmentManager();
Fragment frag = fm.findFragmentById(R.id.frag_list);
FragmentTransaction ft = fm.beginTransaction();
ft.show(frag);
ft.commit();
If there is a better way to resolve this issue, I'm open to suggestions.
#Override
public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
adapter.swapCursor(cursor);
if(isResumed()) {
setListShown(true);
} else {
setListShownNoAnimation(true);
}
}
But you have to setListShown(false) where you set the ListAdapter. This works fine.
Related
Hello you!
I am not a native english speaker, so hope you understand me anyway.
In my application i have a activity with a RelativeLayout wich i use as Fragment-container.
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<RelativeLayout
android:id="#+id/fragmentContainer"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#android:color/white" />
</FrameLayout>
At the time i have two different Fragments, one will be shown at Startup and die other one will be called by click on a TextView in the first one. Both Fragments have its own class and the first one has a interface to the main activity to perform the replacement of the Fragment after onClick.
And now there is my Problem....
public void onCallForAGB() {
getFragmentManager().beginTransaction()
.replace(R.id.fragmentContainer, new LoginReaderFragment(), "agbreader")
.addToBackStack(null)
.commit();
LoginReaderFragment fragment = (LoginReaderFragment) getFragmentManager()
.findFragmentById(R.id.fragmentContainer);
if (fragment != null && fragment.isInLayout()) {
fragment.setText("Gruß an die Welt!");
} else {
Toast.makeText(mContext, "Fail", Toast.LENGTH_LONG).show();
}
}
just for explaining:
the container holds a Fragment named LoginLoginFrament. The user of my app can Login or click on a link (TextView) to show the AGB (dont know how to translate, maybe "Therms for use and Law dependencies" ??). Via the interfaceonCallForAGBwill be executed and replace the Fragment with a Fragment calledLoginReaderFragment` wich is a Fragment with a headline (TextView) and a textfield (TextView) to show filecontents. The function setText(string) should set the text after the Fragment was created.
But after Fragmenttransaction.commit() it seems the change will not be executed immediately. It seems it will be executed when leaving the whole procedure. So i can't access the new fragments Views (to change text) without the complete perfomed replace by commit.
So here is my question: How can i force the FragmentTransaction to be executed after commit() ? Or is there a workaround, so that i can change the headline and text of the new Fragment right after changing from the first to the second Fragment?
Here is the Errorreport (LogCat) which is why I have this assumption
05-29 20:59:18.748: E/AndroidRuntime(14334):
java.lang.ClassCastException:
de.example.myapp.fragments.LoginLoginFragment cannot be cast to
de.example.myapp.fragments.LoginReaderFragment
I think LoginReaderFragment fragment = .... create this error because the old Fragment (LoginLoginFragmet) is still active.
Hope you can help me.
Greets !
Do not try to set the Fragments UI data from the Activity itself after creating it.
Instead, give the fragment the information, which should be shown after the fragment is visible.
The best way to do this is to use the getInstance() pattern. see here.
You need to call the setText function from onViewCreated() in the fragment itself. this grants you that the data will be set, after the view is availible.
i have a piece of code where i wish to just hide the current fragment so it doesnt destroy its view and then show a new one using this :
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.hide(oldFragment);
ft.show(newFragment);
ft.commit();
The issue is that when i execute the above code, it doesnt show any UI components.
if i do ft.replace(id,fragment); it works but i do not want to remove the previous displayed fragment as i want to maintain the fragments and its views so i dont need to re-initialise it
Did you previously add newFragment to some part of your Activity's view hierarchy? If you just instantiate a Fragment and tell it to show, it won't know where to show (unless it's a DialogFragment, I guess). You need to use add(somelayoutid,fragment,"sometag") for each Fragment and then you can hide/show them as you'd like. You can also just continually use replace, rather than hide/show, if you don't need to keep your Fragment's around while they're hidden.
"sometag" will be useful if you're handling rotation so you can retrieve a reference to each Fragment after your Activity is recreated, and then you can hide/show them as before.
Was your fragment initialized before calling this?
if (newFragment == null) {
// If not, instantiate and add it to the activity
ft.add(yourFragmentContainerId, newFragment,"tag");
} else {
// If it exists, simply attach it in order to show it
ft.show(newFragment);
}
When I start my app it runs an AsyncTask to load up and then in onPostExecute, I then setContentView to the new layout then add a fragment with two buttons offering two modes by an add FragmentTransaction. After one of the two modes is clicked, it then replaces the fragment with yet another FragmentTransaction using the replace method.
If the app crashes it returns to the first screen, loading up the two buttons offering the two modes. In this case if either mode is selected, the second fragment is loaded but is now the background is suddenly transparent showing the two buttons below and they remain clickable. If they are clicked again they properly replace the fragment so that it isn't visible below. This is just weird, I can't understand what could cause this.
I've researched and seen these two similar questions, one and two, which suggested that it might be because the ID is wrong or I have defined the fragment in XML. Neither of these two factors are the case.
My code is shown below:
Below I replace the loading screen.
#Override
protected void onPostExecute(Void result) {
setContentView(R.layout.activity_main_screen);
FragmentTransaction transaction = getSupportFragmentManager()
.beginTransaction();
transaction.add(R.id.fragment_container, new ModeFragment())
.commit();
}
After which, when a button is clicked I pass the fragment I wish to replace the current with into this method below:
private void replaceCurrentFragment(Fragment fragment) {
FragmentTransaction transaction = getSupportFragmentManager()
.beginTransaction();
transaction.replace(R.id.fragment_container, fragment)
.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN)
.addToBackStack(null).commit();
}
This works the first time, however if a crash occurs then the app returns to the first fragment and the second time this method is passed, the new replacing fragment is semi-invisible. Clicking the button on the first fragment again calls this method again and it is now fine.
Obviously I don't want the app to crash so this shouldn't occur, but I get this feeling that there's something wrong with how I'm writing my code.
I've had the same problem happen to me, and it was because I loaded a fragment in the OnCreate of my Activity, without checking if there was a savedInstanceState, so android first reopen all old fragments, then do the OnCreate, which added the fragment over the old ones without replacing them so when you navigate to another fragment, it only replaces the top one, but not the bottom one, so you will see the fragments under it.
Might not be exactly the same thing for you, but it might help you figure it out.
If it helps, what I want is similar to what is done in this google tutorial
But there a fragment is created prior to the transition. If I do that the transition works fine; but I can't use this approach
=====
Aiming to API 7+ I am just trying to have one Fragment visible in the whole screen and using a button (a drawn button, with an onTouch event) then alternate to a second fragment and viceversa.
But I either get a blank screen when I replace the first fragment with the second, or if I use fragmentTransaction.show and fragmentTransaction.hide; I can switch two times before I get blank screen. I dont want to have on backstack.
I am creating the fragments in MainActivity's onCreate:
DiceTable diceTable = new DiceTable();
Logger logger = new Logger();
fragmentTransaction.add(diceTable, DICETABLE_TAG);
fragmentTransaction.add(logger, LOGGER_TAG);
fragmentTransaction.add(R.id.fragment_container, logger);
fragmentTransaction.add(R.id.fragment_container, diceTable);
Then on one method (called from the fragments) I do the switch:
Logger logger = (Logger)fragmentManager.findFragmentByTag(LOGGER_TAG);
DiceTable diceTable = (DiceTable)fragmentManager.findFragmentByTag(DICETABLE_TAG);
if (diceTable.isVisible()) {
fragmentTransaction.replace(R.id.fragment_container, logger);
fragmentTransaction.commit();
fragmentTransaction.hide(diceTable);
fragmentTransaction.show(logger);
}
else if (logger.isVisible()) {
fragmentTransaction.replace(R.id.fragment_container, diceTable);
fragmentTransaction.commit();
fragmentTransaction.hide(logger);
fragmentTransaction.show(diceTable);
}
This is not how I should do this?
Blank screen when replacing fragments
Try to initialize fragments in that way:
private void initFragments() {
mDiceTable = new DiceTable();
mLogger = new Logger();
isDiceTableVisible = true;
FragmentManager fm = getSupportFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
ft.add(R.id.fragment_container, mDiceTable);
ft.add(R.id.fragment_container, mLogger);
ft.hide(mLogger);
ft.commit();
}
And then flip between them in that way:
private void flipFragments() {
FragmentManager fm = getSupportFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
if (isDiceTableVisible) {
ft.hide(mDiceTable);
ft.show(mLogger);
} else {
ft.hide(mLogger);
ft.show(mDiceTable);
}
ft.commit();
isDiceTableVisible = !isDiceTableVisible;
}
You are combining two different methods of changing which Fragment is shown:
Calling replace() to replace the contents of the container with a different Fragment
Calling hide() to remove a Fragment, then calling show() to show another Fragment.
Pick one method and stick with it. The Building a Flexible UI guide uses just the replace() method, so I would start by trying to remove all of your calls to show() and hide().
Also see Android Fragments: When to use hide/show or add/remove/replace? for a quick summary of when it might be beneficial to use hide/show instead of replace.
In case anyone has tried all of the already suggested answers and is still facing the issue, like I was a few moments ago, the problem may come from a different source than your fragments.
In my case, I was switching between fragments correctly, but the reason for the blank screen was that in each new fragment I was trying to asynchronously load images by starting a new Thread every time (something a bit like this) instead of the recommended AsyncTask, or better yet the newSingleThreadExecutor, since AsyncTask is deprecated.
I disturbed the background enough that the fragment was just not showing up unless I navigated to a different app then back.
So unless your mistake is similar to mine my suggestion might be kind of vague but try to see if anything is happening in your fragment that may be intensive on the resources (commenting out different pieces of code may help in investigating this).
I have a problem with a fragmented layout and I sincerely apologize if it has been answered before and I was too dumb to find it. I searched for hours and got nothing (well, I got lots but nothing solved my problem).
So here's my setup: I have a two pane layout using two FrameLayouts as containers for my fragments. activity_listing.xml:
<FrameLayout android:id="#+id/listing" />
<FrameLayout android:id="#+id/details" />
On opening the app (onCreate in the fragment's activity) a fragment called Listing is added to FrameLayout "listing" programmatically using a FragmentTransaction.
public class ListingActivity extends FragmentActivity
implements ListingFragment.Callbacks {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_listing);
// Displaying the first listing here ...
Fragment fragment = new ListingFragment();
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.add(R.id.listing, fragment);
ft.addToBackStack(null);
ft.commit();
...
}
This ListingFragment is replaced a few times during runtime, so I have to create it instead of defining it in XML. I tried the latter with
<fragment android:name="com.example.app.ListingFragment" />
but then it won't be replaced or removed programmatically later on. I can only add() and then the old one is visible through the new one. But that's not the problem here - just an explanation for my way.
So far all of this works as it should, Listing is created and displayed etc., so no problems there. But:
When ListingFragment is displayed at startup and I press the back key, at the last position FrameLayout "listing" is emptied instead of dropping back to the Homescreen! I figured it has to be because onCreate of my ListingActivity I display an empty frame and add() a ListingFragment to it. So the back stack has the empty frame in it, too. Right?
I tried solving the situation by this to ListingActivity:
#Override
public void onBackPressed() {
super.onBackPressed();
if(getSupportFragmentManager().getBackStackEntryCount() == 0) {
this.finish();
}
}
But somehow that does not look or feel right ... it looks like a bad work around.
So is there any way to insert the fragment before the view with the empty FrameLayout is inflated so there is no empty state to "back" to? Or is it possible to remove the "empty" state from the back stack even though it is not in it? Any other ideas on how to avoid the empty frame after hitting "back"?
Thank you very much for your efforts in advance!
Don't call ft.addToBackStack(null) when you add the Fragment in onCreate. That tells the FragmentManger that you have another state BEFORE that fragment that you want to be able to jump back to.