I’ve just started working on my first Android app and my focus is the main activity of the app, MathleteIDActivity, which includes a fragment TextFragment which displays some text.
The project builds fine, but crashes as soon as the app is launched. This happens on two different phones running Android 4.x.x, so fragment support shouldn’t be the issue. The stacktrace from adb logcat looks like this (package redacted):
java.lang.RuntimeException: Unable to start activity ComponentInfo{foo.bar.baz.id.MathleteIDActivity} ...
...
Caused by: android.view.InflateException: Binary XML file line #12: Error inflating class fragment
...
Caused by: android.app.Fragment$InstantiationException: Unable to instantiate fragment .fragments.TextFragment: make sure class name exists, is public, and has an empty constructor that is public
...
Caused by: java.lang.ClassNotFoundException: .fragments.TextFragment
...
My directory structure seems kosher: I’ve got the package directories foo/bar/baz/ inside src/main/java/ in the project root, and within that package:
fragments/
TextFragment.java
id/
NFCIDActivity.java
MathleteIDActivity.java
...
...
MathleteIDActivity.java reads as follows:
package foo.bar.baz.id;
import android.widget.TextView;
import android.os.Bundle;
import foo.bar.baz.R;
public final class MathleteIDActivity extends NFCIDActivity {
@Override
public void onCreate(Bundle savedState) {
super.onCreate(savedState);
TextView textView = (TextView) findViewById(R.id.fragment_text);
textView.setText("Scan mathlete tag");
}
}
NFCIDActivity is an abstract class that extends Android’s Activity. Its only method is an override of onCreate:
@Override
public void onCreate(Bundle savedState) {
super.onCreate(savedState);
setContentView(R.layout.id_activity);
}
And TextFragment.java reads as follows:
package foo.bar.baz.fragments;
import android.app.Fragment;
import android.os.Bundle;
import android.view.View;
import android.view.ViewGroup;
import android.view.LayoutInflater;
import foo.bar.baz.R;
public final class TextFragment extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.text_fragment, container, false);
}
}
In src/main/res/layout/id_activity.xml I have the activity layout defined:
<?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" >
<fragment
android:name=".fragments.TextFragment"
android:id="@+id/id_message" >
</fragment>
</LinearLayout>
In the same directory, text_fragment.xml defines TextFragment‘s layout:
<?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" >
<TextView
android:id="@+id/fragment_text"
android:layout_width="match_parent"
android:layout_height="match_parent" >
</TextView>
</LinearLayout>
I’ve already tried:
- Adding a public, no-parameter constructor to
TextFragment. Same errors. - Referencing the fragment in the layout file by its fully-qualified package name
foo.bar.baz.fragments.TextFragment. Same errors, now naming the new package. - Moving
TextFragment‘s source file to the top-level packagefoo.bar.bazand adjusting references. Same errors, now naming the new package.
Any ideas?
Advertisement
Answer
Instantiate your fragment programatically using FragmentManager as a quick solution:
FragmentManager fm = getFragmentManager(); FragmentTransaction ft = fm.beginTransaction(); TextFragment tf = new TextFragment(); ft.replace(R.id.container, tf); ft.commit();
As for your approach, use a canonical package name instead and clean-build your project. Then pay attention to the error message (it can’t be “same error” since it should at least mention different package name).