I'm almost new about android, java, ... and new about fragment. I have an activity (A) that shows a list using fragment (B). Selecting an item of this list, the same fragment is changed to show another lis using fragment (C). It works except when i rotate the device while it shows the second list (C). Also when it is shown the first list (B), if i rotate the device, it works perfectly.
Error LogCat:
04-26 11:30:32.769: E/AndroidRuntime(2882): FATAL EXCEPTION: main
04-26 11:30:32.769: E/AndroidRuntime(2882): java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.traffic/com.example.traffic.ListTriplines}: android.support.v4.app.Fragment$InstantiationException: Unable to instantiate fragment com.example.traffic.ListPoints: make sure class name exists, is public, and has an empty constructor that is public
(...)
04-26 11:30:32.769: E/AndroidRuntime(2882): Caused by: android.support.v4.app.Fragment$InstantiationException: Unable to instantiate fragment com.example.traffic.ListPoints: make sure class name exists, is public, and has an empty constructor that is public
(...)
04-26 11:30:32.769: E/AndroidRuntime(2882): Caused by: java.lang.InstantiationException: com.example.traffic.ListPoints
Activity A (java + XML):
public class MainA extends ActionBarActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.list_triplines);
}
@Override
public void onTripSelected(int cod) {
Fragment pointsFragment = new ListPoints(cod);
FragmentTransaction fTransaction = fManager.beginTransaction();
fTransaction.replace(R.id.trips_points_fragment, pointsFragment);
fTransaction.addToBackStack(null);
fTransaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
fTransaction.commit();
}
@Override
public void onPointSelected(int pos) {
//do some stuff (using pos)
(...)
}
}
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<TextView
android:id="@+id/main_title"
style="@style/HelpTitle"
android:text="@string/listtrips_title"
/>
<fragment
android:id="@+id/trips_points_fragment"
android:name="com.example.traffic.FragmentB"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
/>
</RelativeLayout>
Fragment B (java + XML) :
(...)
import android.support.v4.app.Fragment;
(...)
public class FragmentB extends Fragment {
private OnTripSelectedListener tSelected;
private static ListTriplines listtriplines;
private Context context;
private LayoutInflater inflater;
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
//CHECK che nell'ACTIVITY sia IMPLEMENT il listener
try {
tSelected = (OnTripSelectedListener) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString() + " must implement OnTripSelectedListener");
}
listtrips = (ListTriplines) activity;
context = activity.getApplicationContext();
inflater = LayoutInflater.from(activity);
}
@Override
public View onCreateView (LayoutInflater inflater, ViewGroup vG, Bundle savedInstanceState) {
//Inflate the layout for this fragment
final View viewResult = inflater.inflate(R.layout.list_trips, vG, false);
listview_trips = (ListView) viewResult.findViewById(R.id.trips_listview);
return viewResult;
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
listAdapter = new CursorAdapter(...);
listview_trips.setAdapter(listAdapter);
listview_trips.setOnItemClickListener(onItemClickListener);
listview_trips.setOnItemLongClickListener(onItemLongClickListener);
}
public interface OnTripSelectedListener {
public void onTripSelected(int cod);
}
private OnItemClickListener onItemClickListener = new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> av, View v, int pos, long id) {
tSelected.onTripSelected(id);
}
};
}
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
>
<ExpandableListView
android:id="@+id/trips_explistview"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:background="@color/gray"
/>
</LinearLayout>
Fragment C (java + XML) :
(...)
import android.support.v4.app.Fragment;
(...)
public FragmentC extends Fragment {
private OnPointSelectedListener pListener;
private static ListTriplines listtrips;
private Context context;
private int cod;
public ListPoints (int _cod) {
this.cod = _cod;
}
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
try {
pListener = (OnPointSelectedListener) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString() + " must implement OnPointSelectedListener");
}
listtrips = (ListTriplines) activity;
context = activity.getApplicationContext();
inflater = LayoutInflater.from(activity);
}
@Override
public View onCreateView (LayoutInflater inflater, ViewGroup vG, Bundle savedInstanceState) {
//Inflate the layout for this fragment
final View viewResult = inflater.inflate(R.layout.list_points, vG/*null*/, false);
listview_points = (ListView) viewResult.findViewById(R.id.points_listview);
return viewResult;
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
pointsAdapter = new CursorAdapter(...);
listview_points.setAdapter(pointsAdapter);
listview_points.setOnItemClickListener(onItemClickListener);
}
public interface OnPointSelectedListener {
public void onPointSelected(int pos);
}
private OnItemClickListener onItemClickListener = new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> av, View v, int pos, long id) {
pListener.onPointSelected(pos);
}
};
}
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
>
<ListView
android:id="@+id/points_listview"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:background="@color/gray"
/>
</LinearLayout>
Maybe my problem is because i use 1 fragment to show 2 different fragments ? In this case, i solve it using 2 fragments and alternate that one who must be shown (with VISIBILITY.GONE) ?
Thanks
EDIT: in the XML main activity (A), i changed the fragment name -> FragmentB (i forgot to change it when i posted the question).
N.B: i need to uderline this -> when the activity (A) starts, it loads FragmentB (B); then i select an item and it loads FragmentC (C); when i rotate in the XML there is FragmentB (obviusly) while the activity (A) must loads FragmentC (C). I dont know if Android can handle this situation.
TO SOLVE:
1) LogCat after Ortsinton modification (creating an empty constructor, and passing some arguments with "BUNDLE") :
04-26 14:24:46.809: E/AndroidRuntime(11558): FATAL EXCEPTION: main
04-26 14:24:46.809: E/AndroidRuntime(11558): java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.traffic/com.example.traffic.ListTriplines}: android.view.InflateException: Binary XML file line #23: Error inflating class fragment
04-26 14:24:46.809: E/AndroidRuntime(11558): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1659)
(...)
04-26 14:24:46.809: E/AndroidRuntime(11558): Caused by: android.view.InflateException: Binary XML file line #23: Error inflating class fragment
(...)
04-26 14:24:46.809: E/AndroidRuntime(11558): Caused by: java.lang.IllegalStateException: Fragment com.example.traffic.ListTrips did not create a view.
2) Instantiate the Fragment programmatically (not from XML): - in the XML you must use a "layout" (i used FrameLayout) not "fragment"; - in java script, you must use "FragmentTransaction";
3) Android handles the Activity (that contains the fragments) and Android recreates it as it was at the beginning, so you must implementate onSaveInstanceState (saves the data) and onRestoreInstanceState (to modify the activity as it was when you rotated the device).