I'm struggling combining a tabbed ActionBar and fragments.
I'm using ActionBarSherlock to display three independent tabs, and my problem relates to the first tab exclusively. It's supposed to display items (called "coupons") in a combination of list and detail view. The other two tabs display different content and do not play a role here.
What I'm doing is the following:
The main activity creates three fragments for three tabs
Tab A (a list fragment) populates and renders its list
For clicks on the list I wrote a callback in the main activity that receives the clicked item's id and exchanges the list fragment with the detail fragment on the tab (at least its supposed to do so)
In that callback I create the to-be-displayed detail fragment and try to replace the list fragment with it.
Unfortunately I dont get beyond:
java.lang.IllegalArgumentException: No view found for id 0x7f040027
for fragment CouponDetailFragment{44f4e310 #1 id=0x7f040027}
I attached the relevant snippets at the end of the question. Any help is highly appreciated.
These are the relevant snippets:
public class MyCouponActivity extends SherlockFragmentActivity implements CouponListFragment.Callbacks
List fragment:
<fragment xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:name="foo.bar.CouponListFragment"
android:id="#+id/coupon_list"
android:layout_width="match_parent"
android:layout_height="match_parent" />
Transaction for fragment exchange:
#Override
public void onItemSelected(final String id) {
final Bundle arguments = new Bundle();
arguments.putString(CouponDetailFragment.ARG_ITEM_ID, id);
final CouponDetailFragment fragment = new CouponDetailFragment();
fragment.setArguments(arguments);
getSupportFragmentManager().beginTransaction().replace(R.id.coupon_list, fragment).commit();
}
If you define a fragment in XML, it is fixed and you can't replace it with another fragment in a FragmentTransaction.
Your best bet would be to replace the <fragment /> with some sort of ViewGroup. Don't forget then you'd have to use a FragmentTransaction to add a CouponListFragment in the onCreate(..) of your Activity.
Related
So I basically have a button in 'DemosFragment' and when I click it, I want it to open another fragment (SettingsFragment), I understand now that I need an activity to fix this issue, as the button currently has an onClick method using intent/startActivity, so how would I go about creating an activity that just holds my fragment? I know that may sound weird they way I wrote it, I just started Android development, but basically I have a fragment and because I want a fragment to have a button to open another fragment, I figure I need an activity for the fragment I am trying to open, so how do I create that activity and what do I need to put in it? Thanks.
You need an activity with the following code:
public class ShowFragmentActivity extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_show_fragment);
}
}
You also have to create a layout xml file called activity_show_fragment.xml in your res/layout folder:
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<fragment class="com.example.yourFragmentsClassName"
android:id="#+id/fragment_id"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</FrameLayout>
This should work for just displaying your fragment.
To launch the activity, paste this code in your button's onClick method:
Intent i = new Intent(this, ShowFragmentActivity.class);
startActivity(i);
It's always a good decision to look at the official docs: http://developer.android.com/reference/android/app/Fragment.html.
Hope that helps!
Wow! Your question requires a long answer, however is a good practice (and madatory too) that Fragments cannot communicates between each others, but they can be hosted by an Activity; in that case an Activity can manage the communication flow between them (fragments) and can be developed in several ways, Bundle, Intent and the Handler. Have a look to the ufficial Android documentation here:
http://developer.android.com/training/basics/fragments/index.html
The android docs section on building a flexible UI is a good example of how to start/load a Fragment from an Activity. In the example you will see that a FrameLayout in the Activity XML is used a the fragment container. This will be the View in which all of your fragments are displayed.
When you load your fragment with a FragmentTransaction the contents of your fragments layout will be displayed in the container View. In the above referenced example this takes place with SupportFragmentManager a class included with the android support library, for facilitating fragment transactions in earlier version of the operating system. SupportFramgnetManager requires that you extend FramentActivity and not just Activity. If you're not worried about backwards compatibility and are extending activity, not fragment activity, you can simply use getFragmentManager() instead.
getFragmentManager().beginTransaction()
.add(R.id.fragment_container, firstFragment).commit();
After the initial add transaction you can switch between fragments using the replace method for your fragment transaction. Replace does exactly what it sounds like, it swaps one fragment for another. To accomplish this from within your firstframgnet use
SecondFragment secondFragment = new SecondFragment();
getActivity().getFragmentManager().beginTransaction()
.replace(R.id.fragment_container, secondFragment).commit();
Notice that from within the fragment I used getActivity(). This allows you to reference the context of the host activity to access the fragment manager. When you are within the activity you do not need to use getactivity because the fragment manager is already accessible from that context.
What is the correct way to use fragments? Should i use only one FragmentActivity per interface or use a unique FragmentActivity for all interfaces?
My app is quite simple: it has 4 distinct interfaces, a fixed options menu on top and i only show contextual menu in a interface called 'actions'.
I was thinking to use only one FragmentActivity with an area where i could switch between fragments. Is it a good practice or should i keep one FragmentActivity per interface?
By now, i'm using one FragmentActivity per interface but when i change ( start ) FragmentActivity, it looks like that is creating a new object and my app blinks before open the new activity.
Thank in advance.
edit:
Here is a drawing of my app: http://postimg.org/image/mvxyk2527/
It's a lot of personal preference and requirement really. I'm not a big believer of the "correct way" concept, if you achieve your goal then it's not wrong, but there may be a nicer way to do it.
For me it would depend on how many nested fragments each FragmentActivity handles. If you have a tree of nested fragments you can get into a mess with nested fragment stacks, etc.
http://developer.android.com/training/implementing-navigation/temporal.html
Personally, if I'm writing an application with lots of fragments I tend to have a single Activity which makes navigation a bit more manageable with a single Fragment stack as using multiple FragmentActivity instances will use multiple fragment stacks.
http://developer.android.com/training/implementing-navigation/index.html
You could consider the ViewPager approach which is great if you want to use a tabular and swiping navigation. Although if you have heavy scrollable content views I would be hesitant as for some individuals multi-directional gesture interfaces can be quite frustrating.
http://developer.android.com/training/implementing-navigation/lateral.html
If your code is clean, manageable and not leaking references then I would probably stick with what you have and wouldn't waste your time re-factoring it.
I will try to explain it properly. In your case, you must use one FragmentActivity that includes fragments. You must create one fragment per interface and commit (exchange) when the user clicks on the menu. This may be an example of the structure of the project:
Java Classes:
MainActivity.class (extends FragmentActivity)
Interface1Fragment.class (extends Fragment)
Interface2Fragment.class (extends Fragment)
Interface3Fragment.class (extends Fragment)
Interface4Fragment.class (extends Fragment)
Layouts:
act_main.xml, frg_inter1, frg_inter2, frg_inter3 and frg_inter4.
In MainActivity and act_main.xml, you must create a tabhost o navigationDrawer for the menu and implement a method that allows to switch between fragments. Later, in each fragment you must implement the interface functionality.
Some code:
MainActivity:
public class ActMain extends FragmentActivity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.act_main);
}
private void createMenu() {
//you can create a menu with tabhost or navigation drawer
}
// replace a fragment
public void replaceFragment(Fragment launchFragment) {
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.replace(android.R.id.tabcontent, launchFragment).commit();
}
}
A Fragment:
public class Interface1Fragment extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
rootView = inflater.inflate(R.layout.frg_inicio, container, false);
return rootView;
}
}
MainActivity.xml
<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:facebook="http://schemas.android.com/apk/res-auto"
android:id="#+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<!-- Main content -->
<FrameLayout
android:id="#android:id/tabcontent"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="0" />
<!-- Left Navigation Drawer -->
<LinearLayout
android:id="#+id/left_drawer"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="start"
android:background="#color/black_actionbar"
android:choiceMode="singleChoice"
android:onClick="emptyOnClick"
android:orientation="vertical" >
/LinearLayout>
</android.support.v4.widget.DrawerLayout>
In fragments xml files you must design your interfaces.
Yeah, you should just change fragments, not restart the fragment activity if that part is gonna stay the same and work the same.
You should just switch between fragments like this:
getFragmentManager().beginTransaction().replace(R.id.container, new MyFragment()).addToBackStack(null).commit();
or like this if you are supporting API < 14
getSupportFragmentManager().beginTransaction().replace(R.id.container, new MyFragment()).addToBackStack(null).commit();
Note : remove addToBackStack(null) if you dont want to go back to previously loaded fragment onBackPressed
I'm working with fragments with ViewPager concept. I'm creating a diary app in which I'm using only one fragment which gets all updates from database and show in it. Until this everything is fine...According to my requirement when i click on a button in fragment i need to show another fragment which allows the user to store the images.
My problem is.....
--If i use replace method in fragments it was not replacing properly in the sense if A is fragment which consists of viewpager and B is a fragment i want to replace.
--Then if i use replace B is visible but A also appears under the fragment B
FragmentManager m=getActivity().getSupportFragmentManager();
FragmentTransaction ft = getActivity().getSupportFragmentManager()
.beginTransaction();
Demobutton demobutton = new Demobutton();
ft.replace(R.id.lay, demobutton);
ft.commit();
Hope you guys understand my problem. If you feel my question is incomplete please let me know that.
I have two suggestions depending on how you use the DemoButton Fragment:
1) Maybe your issue is with nested fragments. You get the FragmentManager from the activity but if the Demobutton is already part of an fragment use getChildFragmentManager() of the outer fragment instead.
2) From my experience when using a ViewPager with Fragments the PagerAdapter of the ViewPager should do all the fragment transactions. You could extend and overwrite the class FragmentPagerAdapter from the support library in order to get the correct fragment in your ViewPager when you need it.
I've developed a small example app that achieves this without overwriting native classes.
The point is to use a fragment as a container.
In your ViewPagerAdapter:
#Override
public Fragment getItem(int position) {
/*
* IMPORTANT: This is the point. We create a RootFragment acting as
* a container for other fragments
*/
if (position == 0)
return new RootFragment();
else
return new StaticFragment();
}
RootFragment layout should look like:
<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"
android:id="#+id/root_frame" >
</FrameLayout>
You could review my complete explanation here: https://stackoverflow.com/a/21453571/1631136
I'm building an app that the interface is based on this http://code.google.com/p/android-playground/, and I need to have a fragment inside of each tab (that are fragments). The tabs are all inflated from the same xml, and in that xml I have a fragment tag.
The problem is that when the activity is created, as the id of each fragment in the tabs are equal, the contents that should go to the second tab, go in the first.
I'm using this code to replace the fragment in the tab
FragmentTransaction ft = x.getSupportFragmentManager().beginTransaction();
ft.replace(R.id.details, fragment);
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
ft.commit();
I don't know if is possible to correct this.
do you want all the tabs to have the exactly the same content?
Usually when putting fragments in tabs each tab would be showing differnt content, so a xml file per tab would not be uncommon. You can have a seperate xml layout for each tab that just declares your fragment with a different id each time. Without declaring a seperate (read unique) id for each fragment there is no efficent / simple operation i know to get a handle to a specific fragment (as the id is the unique handle).
You also may be able to use a FragmentPagerAdapter depending on your needs. You could then fade your current tab fragment out, then call public void notifyDataSetChanged () and provide a new fragment. This is not really the standard way of doing it though and will not be preserved on the back stack.
Optionally you could create each tab programatically in the PagerAdapter and set a tag for each fragment when calling FragmentTransaction.add(..) and then use this tab-unique tag in future fragment transactions Ignore this, it does not look like you can switch fragements with a tag, id only im afraid. Go with my first suggestion I would!
I've struggled with ths as well and the way I reference a Fragment from its Activity later on is by accessing the Adapter for the tabs.
Assuming you use an Adapter, you could do something like this
private mTabsAdapter;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// etc
this.mTabsAdapter = new TabsAdapter(this, this.mViewPager);
// Tab1
Tab tab = actionBar.newTab();
this.mTabsAdapter.addTab(tab, MyFragment1.class, null);
// Tab2
tab = actionBar.newTab();
this.mTabsAdapter.addTab(tab, MyFragment2.class, null);
}
public MyFragment1 getTab1() {
return (MyFragment1)this.mTabsAdapter.getItem(0);
}
public MyFragment2 getTab2() {
return (MyFragment2)this.mTabsAdapter.getItem(1);
}
Then inside your fragment, you would have a method to access
public class MyFragment1 {
// ...
public void reloadData() {
// reload data here
}
}
Now you can access the Fragment such as
this.getTab1.reloadData();
This feels like a sad way to access a fragment, but you can't rely on a Tag in every scenario. Also, you must take care to only reference this where the reference to the Fragment exists.
There may be times that this will be null. For example if you nave a bunch of tabs, they may become garbage collected at some point. you should communicate between Fragments via a callback. This example is for only a few scenarios.
The callback method is described at Communicating with the Activity and I'd suggest this method if it fits your application. This will prevent the need for directly accessing tabs in most cases.
I have application titles fragment and contents fragment on the screen. When the user clicks on the item in titles fragment the according fragment is created and inserted to a frame and the selected title is highlighted in titles fragment.
Transaction is done with fragment.addToBackStack(), so when the user clicks the BACK key, the previous fragment is restored and inserted in the frame.
What is the best solution to restore view state when transaction manager restores fragments?
The problem is that I should highlight previous fragment name in titles fragment and I should know what fragment it is. I resolved it by storing view state in my own stack: when fragment is created and restoring on changing transaction backstack using transaction manager listener.
But this doesn't seem like the correct solution.
Before the answer, next time remember to add your code. Chances are my answer will not help you as much as it could because I don't really know your code.
This is old but anyway, IF I understand your question (and app architecture) correctly, it sounds like a case for interfacing.
Example:
add this interface as a member to the content fragment:
public class ContentFragment extends Fragment{
public interface onFragmentTitleHighlighted{
public void highLightTitle(String title);
}
}
and have the title fragment implement it. Make sure to equip your content fragments with the title fragmnet, and add a call to highLightTitle(String title); in the content fragment's onCreateView(...) call. This way whenever a new content fragmnet is being added the title will be highlighted.