具有片段的活动可以采取两个不同的片段和设备的旋转

时间:2015-04-26 09:55:07

标签: java android android-fragments android-activity fragment

我对android,java,...以及关于片段的新内容几乎全新。 我有一个活动(A),显示使用片段(B)的列表。选择该列表的项目,相同的片段被更改为使用片段(C)显示另一个lis。 除非我在显示第二个列表(C)时旋转设备,否则它可以工作。 此外,当显示第一个列表(B)时,如果我旋转设备,它将完美运行。

错误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

活动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>

片段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>

片段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>

也许我的问题是因为我使用1个片段来显示2个不同的片段?在这种情况下,我使用2个片段解决它,并替换必须显示的那个(具有VISIBILITY.GONE)?

由于

编辑:在XML主要活动(A)中,我更改了片段名称 - &gt; FragmentB (我在发布问题时忘记更改了)。

N.B:我需要uderline this - &gt;当活动(A)开始时,它加载FragmentB(B);然后我选择一个项目,它加载FragmentC(C);当我在XML中旋转时,存在FragmentB(obviusly),而活动(A)必须加载FragmentC(C)。我不知道Android是否可以处理这种情况。

解决:

1)在Ortsinton修改后的LogCat(创建一个空的构造函数,并使用&#34传递一些参数; BUNDLE&#34;):

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)以编程方式(而非XML)实例化片段: - 在XML中你必须使用&#34; layout&#34; (我使用的是FrameLayout)而不是&#34;片段&#34 ;; - 在java脚本中,您必须使用&#34; FragmentTransaction&#34 ;;

3) Android处理Activity(包含片段)并且Android在开始时重新创建它,因此您必须实现onSaveInstanceState(保存数据)和onRestoreInstanceState(以修改活动)就像旋转设备时那样。)

1 个答案:

答案 0 :(得分:1)

我认为你的错误在于ListPoints Fragment:

 public ListPoints (int _cod) {
    this.cod = _cod;
}

来自Fragment class reference by Android

  

Fragment的所有子类都必须包含公共无参数构造函数。框架通常会在需要时重新实例化一个片段类,特别是在状态恢复期间,并且需要能够找到此构造函数来实例化它。如果无参数构造函数不可用,则在状态恢复期间的某些情况下将发生运行时异常。

片段需要一个空的构造函数,因此可以实例化,你不能无法覆盖它。因此,如果您需要传递一些参数,请尝试以下方法:

在活动中写作:

Bundle bundle = new Bundle();
bundle.putInt(key, _cod);
fragment.setArguments(bundle);

阅读片段:

Bundle arguments = this.getArguments();
this.cod = arguments.getInt(key);

不要忘记覆盖onSaveInstanceState函数,这样如果应用程序处于后台并被杀死,它将能够正确恢复状态。否则你的变量将没有值