Using FragmentActivity throws InflateException - android

Common Fragment to be used in 2 Activity's
public class Ads extends Fragment {
private View rootView ;
private MoPubView adView ;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
rootView = inflater.inflate(R.layout.ads, container, true) ;
adView = (MoPubView) rootView.findViewById(R.id.adView) ;
adView.setAdUnitId(LogoQuizUtil.MOPUB_AD_UNIT);
adView.loadAd();
return rootView;
}
}
Fragment layout
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/ad_layout"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:gravity="bottom" >
<com.mopub.mobileads.MoPubView
android:id="#+id/adView"
android:layout_width="fill_parent"
android:layout_height="50dp"
android:layout_marginTop="10dp"
android:gravity="bottom" />
</LinearLayout>
Other Layout where I include this fragment
<fragment
android:id="#+id/ads"
android:name="myPackage.Ads"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:gravity="bottom" />
I get a dont get a exception when I call setContentView (R.layout.ads) the first time, when the second activity calls the fragementactivity (Ads) I get a exception at setContentView (R.id.ads).
Exception I get is
08-07 09:38:30.359: W/System.err(975): java.lang.RuntimeException: Unable to start activity ComponentInfo{mypackage/mypackage.SecondActivity}: android.view.InflateException: Binary XML file line #263: Error inflating class fragment

Lets start at the beginning. An activity is not a fragment and a fragment is not an activity.
You need an activity to contain/control fragments. To do that you extend Activity (for Honeycomb+ development) or use the support library and extend FragmentActivity. In this class you would use setContentView to set the layout that will contain the fragment(s).
You then, from that class, call the fragment manager (getFragmentManager or getSupportFragmentManager depending on which class you have extended). The fragment manager is then used to create, attach and detach the fragments.
The fragment, not being an activity, is coded differently. It should have an onCreateView method that inflates the layout for the fragment and returns it to the fragment manager from the activity.
Then it is typical to use onActivityCreated for the rest of your code (or whatever else is needed).
Making the changes to use fragments properly may or may not solve all of your problems, as I see you are using some kind of custom widget in your layout and the issue could be there too.

Related

findViewById Attribute in Fragment from the activity xml Not work [duplicate]

This question already has answers here:
findViewById in Fragment
(37 answers)
Closed 2 years ago.
How to access an attribute in the activity xml?
I want to use it in fragment.
for example : this is my activity xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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"
xmlns:fab="http://schemas.android.com/apk/res-auto">
<androidx.constraintlayout.widget.ConstraintLayout
fab:layout_constraintTop_toTopOf="parent"
fab:layout_constraintLeft_toLeftOf="parent"
fab:layout_constraintRight_toRightOf="parent"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/layTitle"
android:layoutDirection="rtl"
android:background="#color/colorPrimary"
android:padding="#dimen/paddingTitle"
android:elevation="#dimen/elevationActivityTitle"
android:layout_alignParentTop="true">
<ImageView
fab:layout_constraintLeft_toLeftOf="parent"
fab:layout_constraintTop_toTopOf="parent"
fab:layout_constraintBottom_toBottomOf="parent"
android:layout_width="#dimen/imgActivityTitle"
android:layout_height="#dimen/imgActivityTitle"
android:id="#+id/btn_back"
android:src="#drawable/ic_back"
android:elevation="5dp"
android:layout_alignParentEnd="true"
android:layout_centerVertical="true"/>
</androidx.constraintlayout.widget.ConstraintLayout>
<FrameLayout
android:id="#+id/frag"
android:layout_width="0dp"
android:layout_height="0dp"
fab:layout_constraintBottom_toBottomOf="parent"
fab:layout_constraintTop_toBottomOf="#+id/layTitle"
fab:layout_constraintLeft_toLeftOf="parent"
fab:layout_constraintRight_toRightOf="parent"
/>
</androidx.constraintlayout.widget.ConstraintLayout>
I want findViewByid ImageView in fragment
When I was searching for solution I got the following one:
TextView btn_back= (TextView) getView().findViewById(R.id.btn_back)
But, unfortunately it was not working for me.
You can use the interface to do it :
Create an interface names IBtnClick with one void method: "void onBtnClicked();"
use interface in activity like this:
IBtnClick iBtnClick= (IBtnClick)getActivity();
here getAtivity is our context, if it doesn't work use another scope context.
and use your method in button click listener like this
iBtnClick.onBtnClicked();
Now in your fragment you have to implements interface and
you can add any action you want in Overrided method.
Use either viewModel or interfaces to talk between activity and fragment. don't try to send the button to fragment but trigger it from there. That will prevent any leaks or null pointers.
Ok. You have some options.
Firstly, you can access these variables to directly in fragment like that.
MainActivity.java
TextView backButton;
backButton = findViewById(R.id.btn_back);
Fragment.java
((MainActivity) getActivity()).backButton
You can get current activity with getActivity() but Java compiler cannot understand which activity so have to cast to MainActivity.
Secondly, you can pass your activity instance to fragment. You can use constructors and newInstance() function. You can read that post Best practice for instantiating a new Android Fragment
In my opinion, I prefer second option because you guarantee these variables that include activity class. Some devices occur errors at first option. But second option uses more ram because you are passing your variables to another class.
The choice is yours
Try This code
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
view = inflater.inflate(R.layout.recharge_plane_fragment, container, false);
alertdialog_Listview=view.findViewById(R.id.alertdialog_Listview);
return view;
}
You can declare your TextView btn_back as static in activity
public static TextView btn_back;
btn_back = (TextView) findViewById(R.id.btn_back);
and get it in fragment
TextView btn_back = ((MainActivity)getActivity()).btn_back;

Where is the ViewGroup container initialized?

I am trying to understand the following fragment code:
public class FragmentA extends Fragment {
public FragmentA(){
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
if(container!=null)
// WHY IS THIS CODE EXECUTED? I did not set container variable
// why if I pass null insted of Container, I get the same result?
return inflater.inflate(R.layout.fragment_a,container,false);
}
}
This ViewGroup container I never initialized or something. How does android know what is my container?, if I never initialized it.
The other thing that is not clear to me is when I call inflate and if instead the container I write null, the result is same.
return inflater.inflate(R.layout.fragment_a,null,false);
I am working with ViewPager in my main activity.
I create the fragment is this way in the FragmentPagerAdapter:
Fragment fragment = new FragmentA();
These are my xml files:
<android.support.v4.view.ViewPager xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/pager"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity"/>
and for the fragment :
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#FFCC00" >
<!-- TODO: Update blank fragment layout -->
<TextView
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_gravity="center"
android:gravity="center"
android:textColor="#ffffff"
android:textStyle="bold"
android:text="THIS IS FRAGMENT A" />
</FrameLayout>
EDIT:
I found this on the developer site:
The container parameter passed to onCreateView() is the parent
ViewGroup (from the activity's layout) in which your fragment layout
will be inserted. The savedInstanceState parameter is a Bundle that
provides data about the previous instance of the fragment, if the
fragment is being resumed (restoring state is discussed more in the
section about Handling the Fragment Lifecycle).
But, is still not clear for me. I did not pass any ViewGroup to the Fragment in the Fragment call....
The container is supplied externally to the fragment. It's either generated automatically when you use the <fragment> tag in xml, or it's passed as part of the FragmentTransaction when you initialize the fragment in code.

Using Google Maps v2 in subclass activity with navigation drawer

I need to work back to API level 8. I have multiple activities and am using a navigation drawer to move between them as well as an action bar (with AppCompat v7). I have created a base abstract class that has all the navigation drawer setup and handling and that descends from ActionBarActivity.
File BaseNavActivity.java
abstract class BaseNavActivity extends ActionBarActivity {
}
All my activities subclass BaseNavActivity, and they all work fine.
public class MainActivity extends BaseNavActivity {
}
Before I added the navigation drawer feature I had a map working fine when descending from FragmentActivity. However, I cannot do that anymore because I need to descend from my BaseNavActivity. Even though the docs say ActionBarActivity descends from FragmentActivity I get an error when trying to use this XML.
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/drawerLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/background" >
<!-- The main content view -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/background"
android:orientation="vertical"
>
<include layout="#layout/common_toolbar" />
<fragment
android:id="#+id/map"
class="com.google.android.gms.maps.SupportMapFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingTop="3dip"
/>
<include layout="#layout/common_footer" />
</LinearLayout>
<!-- The navigation drawer -->
<include layout="#layout/nav_menu" />
</android.support.v4.widget.DrawerLayout>
I get an InflateException: Binary XML file line #19: Error inflating class fragment.
I have tried other solutions such as having a separate XML file with just the and opening it as a fragment and adding it to the above in place of the . That approach always returned a null when I tried to point to the map (smf was always null):
SupportMapFragment smf = (SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map);
I also tried to have a
public class MapFragment extends FragmentActivity {
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// TODO Auto-generated method stub
View myFragmentView = inflater.inflate(R.layout.location_map, container, false);
return myFragmentView;
}
}
but I couldn't add the fragment using
MapFragment mapFragment = new MapFragment();
fragmentTransaction.add(R.id.map_container, mapFragment);
fragmentTransaction.commit();
The add() function needed to have parameters of (int, Fragment).
Any help will be appreciated. If you need more code I can add it but didn't want to make this post too long. I have spent a couple of days searching and trying various approaches and nothing seems to get everything working together.
Basically I would like to know how to have a <fragment> inside the XML when descending from a custom subclass that descends from ActionBarActivity. My 2nd choice would be to know how to add a fragment that holds the map and works with the support libraries.
Thanks!
I finally found my issue. I took a different approach for searching and found this gem: Android Google Maps V2 Caused by: java.lang.ClassCastException: com.google.android.gms.maps.SupportMapFragment cannot be cast to android.app.Fragment
Basically my issue was that I had the custom base class call setContentView before calling the super.onCreate. That meant that fragments weren't understood because it was a couple of supers up that knew about them. This caught me because 1) I needed to specify a theme that appcompat could use and had my setContentView next to it when I copied things to the base class, and 2) everything else worked up to this point so I didn't realize it was incorrect.
So the fix is in my base class that all my activities inherit from (abbreviated):
abstract class BaseNavActivity extends ActionBarActivity {
protected void onCreate(Bundle savedInstanceState, int resLayout) {
// need to set the theme first
setTheme(R.style.AppTheme2);
// then call super before setting the content view
super.onCreate(savedInstanceState);
setContentView(resLayout);
}
}

Two fragments hold by another fragment - findViewById returns null

I need help for my first Android application. I have a single activity with an Action Bar at the top and Navigation Tabs. Because of these navigation tabs I had to convert my Activities into Fragments.
So one of those Activities (which is now a Fragment) held two fragments, one ListFragment on the Left and a DetailFragment on the right, so that the user is able to select an item from the list and directly sees details on the right.
But now as the Activity has been transformed into the Fragment, it's the Fragment that holds the List- and the DetailFragment. This works fine until I want to change the DetailsFragment.
First of all, here is the code of the Fragment holding the other two:
public class BlackboardFragment extends Fragment {
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
return inflater.inflate(R.layout.fragment_layout, container, false);
}
}
Here is the fragment_layout.xml file (saved in layout-land):
<?xml version="1.0" encoding="UTF-8"?>
<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:id="#+id/interfaces"
android:layout_width="0px"
android:layout_height="match_parent"
android:layout_marginRight="20dp"
android:layout_weight="0.60"
class="org.fawkesrobotics.app.InterfaceFragment" />
<FrameLayout
android:id="#+id/viewer"
android:layout_width="0px"
android:layout_height="match_parent"
android:layout_weight="1" />
</LinearLayout>
So, the ListFragment is named InterfaceFragment, here is the code:
public class InterfaceFragment extends ListFragment {
boolean mDualPane;
// some other code
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
create_list();
View viewerFrame = getActivity().findViewById(R.id.viewer);
mDualPane = viewerFrame != null
&& viewerFrame.getVisibility() == View.VISIBLE;
if (savedInstanceState != null) {
mCurCheckPosition = savedInstanceState.getInt("curChoice", 0);
}
}
// some other code
}
This is, where it doesn't work. The Fragment actually shows the list (that is created in create_list() where the ListAdapter and everything else is set), but my problem is, that viewerFrame is null. I declared the id viewer in the xml file above, so I don't understand why he cannot find the id. Does it "belong" to the BlackBoardFragment or to my overall activity? Because in BlackboardFragment I also tried it with getActivity().findViewById and it worked. Why is InterfaceFragment not able to find it?
I also tested, if he really uses the fragment_layout.xml in layout-land and he does. So he should know the id viewer, but obviously doesn't.
If you need more code or the code from the DetailsFragment, I can post it.
Thank you in advance for your help! :)
use FragmentManager to get Fragment......
ExampleFragment fragment = (ExampleFragment) getActivity().getFragmentManager().findFragmentById(R.id.example_fragment);
Nested Fragments are not supported by the Android SDK. That is, you can't have a "fragment within a fragment" in your Android application. Sorry.
EDIT:
Nested Fragments are now part of the official Android 4.2 SDK! Yay!

Do not get the rootLayoutContainer in a Fragment (Android 3.0 Preview)

I'm currently getting into the fragment API of the Android 3.0 Preview and have built the following minimal coding:
I have an Activty, which shall embed Fragment(s), which is currently implemented like this:
public class Cockpit extends Activity {
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.cockpit);
}
public static class InfoFragment extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
ViewGroup infoFragmentRoot = (ViewGroup) getActivity().findViewById(
R.id.infoFragmentRoot) ;
return inflater.inflate(R.id.infoFragment, container, false);
}
}
}
The corresponding layout of the activity:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<fragment android:name="test.android.ui.cockpit.Cockpit$InfoFragment"
android:id="#+id/infoFragment"
android:layout_weight="1"
android:layout_width="10dp"
android:layout_height="match_parent" >
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent"
android:layout_height="match_parent" android:padding="12dp" android:id="#+id/infoFragmentRoot" >
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="#string/hello"
/>
</LinearLayout>
</fragment>
Now, I do not understand why the ViewGroup container in the onCreateView() in the internal class InfoFragment is a nullpointer, nor do I understand,
why
ViewGroup infoFragmentRoot = (ViewGroup) getActivity().findViewById(
R.id.infoFragmentRoot) ;
returns also null.
Thanks for feedback.
You've got a few problems here. First of all, you don't want to be adding tags inside of the <fragment> tag. Think of the fragment tag as a placeholder. The fragment's onCreateView() method is responsible for defining the view hierarchy of your fragment, not the activity's layout XML file. What you can do though is create a separate layout XML file to be just the fragment's layout. Then inside of onCreateView(), you take the inflater passed in, and do something like this:
View v = inflater.inflate(R.layout.frag1, container, false);
TextView text1 = (TextView) v.findViewById(R.id.text1);
text1.setText( myTextData );
return v;
Notice that the attach parameter to inflate() is false? Android will take care of attaching the returned view to your container later.
Your activity's view hierarchy is not guaranteed to be in existence until the fragment gets the onActivityCreated() callback. So the attempt to get infoFragmentRoot could return null inside of onCreateView(). But I'm not even sure what is going on when that tag is buried inside of your <fragment>.
In this particular case, where you've embedded the tag in your activity's layout, the onInflate() callback of your fragment will be called with the rest of the attributes from your tag. The theory is that you could add those attributes to the arguments bundle on your fragment, then retrieve those values later in onCreateView() (using setArguments() and getArguments()). I say in theory because it appears there's a bug in the code that handles a configuration change (e.g., landscape to portrait), resulting in onInflate() being called after onCreateView() when the fragment is being reconstructed after a configuration change. See defect report http://code.google.com/p/android/issues/detail?id=14796.
For now, I recommend you extract your fragment's layout to a separate layout XML file (e.g., frag1.xml), the use my code above to inflate that layout in onCreateView(). And don't worry about any attributes being passed to onInflate().
You also do not want to use onCreate to instantiate your layout, that all will be handled within the parent activity. Saving the bundle is about all ive done there so far

Categories

Resources