【问题标题】:Activity with fragment who can take two differents fragments and rotation of device带有片段的活动,可以采用两个不同的片段和设备旋转
【发布时间】:2015-04-26 09:55:07
【问题描述】:

我对 android、java 等几乎是新人,对 Fragment 也是新人。 我有一个活动(A),它使用片段(B)显示一个列表。选择此列表中的一个项目,相同的片段将更改为使用片段 (C) 显示另一个列表。 它可以工作,除非我在显示第二个列表 (C) 时旋转设备。 此外,当它显示第一个列表 (B) 时,如果我旋转设备,它会完美运行。

错误日志:

    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)?

谢谢

EDIT:在 XML 主要活动 (A) 中,我更改了片段名称 -> FragmentB(我发布问题时忘记更改它)。

N.B:我需要对此进行下划线 -> 当活动 (A) 开始时,它会加载 FragmentB (B);然后我选择一个项目并加载 FragmentC (C);当我在 XML 中旋转时,有 FragmentB(显然),而活动(A)必须加载 FragmentC(C)。我不知道Android是否可以处理这种情况。


解决方法:

1) Ortsinton 修改后的 LogCat(创建一个空的构造函数,并使用“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) 以编程方式(不是从 XML)实例化片段: - 在 XML 中,您必须使用“布局”(我使用 FrameLayout)而不是“片段”; - 在java脚本中,你必须使用“FragmentTransaction”;

3) Android 会处理 Activity(包含 Fragment),Android 会像开始时一样重新创建它,因此您必须实现 onSaveInstanceState(保存数据)和 onRestoreInstanceState(修改 Activity)就像您旋转设备时一样)。

【问题讨论】:

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


    【解决方案1】:

    我认为您的错误出在 ListPoints Fragment 中:

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

    来自Fragment class reference by Android

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

    Fragment 需要一个空的构造函数,所以它可以被实例化,你不能覆盖它。因此,如果您需要向它传递一些参数,请尝试以下操作:

    在活动中写作:

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

    读入片段:

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

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

    【讨论】:

    • 感谢您的回复 :) ...我尝试了您的建议(在片段中我在 onAttach 循环中检索捆绑数据),现在 logcat 更改了(我发布了它)。跨度>
    • 似乎在扩展片段布局时出错。您可以发布片段 com.example.traffic.FragmentB 的 xml 文件吗?
    • 我添加了两个片段的XML文件。
    • color.xml 文件中是否定义了灰色?
    • 看看这个家伙的问题,它似乎和你的很相似stackoverflow.com/questions/7707032/…尝试通过替换片段容器而不是在xml中实例化它来以编程方式实例化第一个片段。这样可以解决横屏时的问题。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多