Crash on Rotation with this error: Fragment has not been attached yet

Crash on Rotation with this error: Fragment has not been attached yet

我有一个 Activity 和 02 tabLayout

我在我的第一个选项卡中添加了 First Fragment,自从我在第二个选项卡中添加了我的 Second Fragment 之后,一切都很好

我的 Second Fragment 工作但是当我旋转设备时它会崩溃,这是我的代码和 logCat..

我试图以不同的方式附加我的FragmentTwo到我的MainActivity..谁能告诉我哪里出了问题&&我怎样才能正确地做到这一点?

提前致谢。

主要Activity:

public class MainActivity extends AppCompatActivity {
    private DrawerLayout mDrawerLayout;
    private TabLayout tabLayout;
    private ViewPager viewPager;
    private int[] tabIcons = {
            R.drawable.ic_tab_note,
            R.drawable.ic_tab_calendar
    };

    private static final int TIME_DELAY = 2000;
    private static long back_pressed;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        //////// TOOLBAR
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);
        ActionBar actionBar = getSupportActionBar();
        actionBar.setHomeAsUpIndicator(R.drawable.ic_menu);
        actionBar.setDisplayHomeAsUpEnabled(true);

        ///////// DRAWER
        mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
        NavigationView navigationView =
                (NavigationView) findViewById(R.id.navigation_view);
        navigationView.setNavigationItemSelectedListener
                (new NavigationView.OnNavigationItemSelectedListener() {
                    @Override
                    public boolean onNavigationItemSelected(MenuItem menuItem) {
                        menuItem.setChecked(true);
                        mDrawerLayout.closeDrawers();
                        Toast.makeText(MainActivity.this,
                                menuItem.getTitle(),
                                Toast.LENGTH_LONG).show();
                        return true;
                    }
                });

        viewPager = (ViewPager) findViewById(R.id.viewpager);
        setupViewPager(viewPager);

        tabLayout = (TabLayout) findViewById(R.id.tablayout);
        tabLayout.setupWithViewPager(viewPager);
   }


    private void setupViewPager(ViewPager viewPager) {
        ViewPagerAdapter adapter = new ViewPagerAdapter(getSupportFragmentManager());
        adapter.addFragment(new FragmentOne(), "ONE");
        adapter.addFragment(new FragmentTwo(), "TWO");
        viewPager.setAdapter(adapter);
    }

    class ViewPagerAdapter extends FragmentPagerAdapter {
        private final List<Fragment> mFragmentList = new ArrayList<>();
        private final List<String> mFragmentTitleList = new ArrayList<>();

        public ViewPagerAdapter(FragmentManager manager) {
            super(manager);
        }

        @Override
        public Fragment getItem(int position) {
            return mFragmentList.get(position);
        }

        @Override
        public int getCount() {
            return mFragmentList.size();
        }

        public void addFragment(Fragment fragment, String title) {
            mFragmentList.add(fragment);
            mFragmentTitleList.add(title);
        }

        @Override
        public CharSequence getPageTitle(int position) {
//            return mFragmentTitleList.get(position);
            return null;
        }
    }

}

片段二:

import ir.mirrajabi.persiancalendar.PersianCalendarView;
import ir.mirrajabi.persiancalendar.core.PersianCalendarHandler;
import ir.mirrajabi.persiancalendar.core.interfaces.OnDayClickedListener;
import ir.mirrajabi.persiancalendar.core.interfaces.OnMonthChangedListener;
import ir.mirrajabi.persiancalendar.core.models.CalendarEvent;
import ir.mirrajabi.persiancalendar.core.models.PersianDate;

public class FragmentTwo extends Fragment {
    private View view;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    }

    @Override
    public View onCreateView(LayoutInflater inflater,
                             ViewGroup container,
                             Bundle savedInstanceState) {
        view = inflater.inflate(R.layout.fragment_two_layout,
                container, false);

        final PersianCalendarView persianCalendarView = (PersianCalendarView) view.findViewById(R.id.persian_calendar);
        final PersianCalendarHandler calendar = persianCalendarView.getCalendar();
        final PersianDate today = calendar.getToday();
        calendar.addLocalEvent(new CalendarEvent(
                today, "Custom event", false
        ));
        calendar.addLocalEvent(new CalendarEvent(
                today.clone().rollDay(2, true), "Custom event 2", true
        ));
        calendar.setOnMonthChangedListener(new OnMonthChangedListener() {
            @Override
            public void onChanged(PersianDate date) {
                Toast.makeText(getActivity(), calendar.getMonthName(date), Toast.LENGTH_SHORT).show();
            }
        });
        persianCalendarView.setOnDayClickedListener(new OnDayClickedListener() {
            @Override
            public void onClick(PersianDate date) {
                for (CalendarEvent e : calendar.getAllEventsForDay(date))
                    Toast.makeText(getActivity(), e.getTitle(), Toast.LENGTH_LONG).show();


                calendar.addLocalEvent(new CalendarEvent(
                        today.clone().rollDay(2, false), "Some event that will be added in runtime", false
                ));
                persianCalendarView.update();
            }
        });

        calendar.setHighlightOfficialEvents(false);
        TextView txtDayMonth = (TextView) view.findViewById(R.id.txt_day_month);
        TextView txtYear = (TextView) view.findViewById(R.id.txt_year);

        String dayAndMonth = calendar.getWeekDayName(today) + calendar.formatNumber(today.getDayOfMonth())
                + calendar.getMonthName(today);
        txtDayMonth.setText(dayAndMonth);
        txtYear.setText(calendar.formatNumber(today.getYear()));

        calendar.setColorBackground(getResources().getColor(android.R.color.holo_blue_dark));
        persianCalendarView.update();


        return view;
    }

}

这是我的 activity_main.xml :

<android.support.v4.widget.DrawerLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/drawer_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true">

    <RelativeLayout
        android:id="@+id/base2"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="vertical">

    <android.support.v7.widget.Toolbar
        android:id="@+id/toolbar"
        android:layout_width="match_parent"
        android:layout_height="?attr/actionBarSize"
        android:background="?attr/colorPrimary"
        android:theme="@style/ThemeOverlay.AppCompat.Dark"/>

        <android.support.design.widget.TabLayout
            android:id="@+id/tablayout"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="?attr/colorPrimary"
            app:tabGravity="fill"
            android:theme="@style/ThemeOverlay.AppCompat.Dark"/>

            <RelativeLayout
                android:id="@+id/relativee"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content">

        <android.support.v4.view.ViewPager
            android:id="@+id/viewpager"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            layout_weight="1"/>
            </RelativeLayout>
        </LinearLayout>
    </RelativeLayout>

    <android.support.design.widget.NavigationView
        android:id="@+id/navigation_view"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:layout_gravity="start"
        app:headerLayout="@layout/drawer_header"
        app:menu="@menu/drawer"/>
</android.support.v4.widget.DrawerLayout>

这里是 fragment_two_layout.xml :

<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/colorPrimaryDark"
    android:orientation="vertical">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <android.support.v7.widget.CardView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_margin="24dp">

    <ir.mirrajabi.persiancalendar.PersianCalendarView
        android:id="@+id/persian_calendar"
        android:layout_width="match_parent"
        android:layout_height="290sp"
        app:pcv_colorBackground="#292929"
        app:pcv_colorDayName="#bab6b6"
        app:pcv_colorHoliday="#ffd506"
        app:pcv_colorHolidaySelected="#f1f2f3"
        app:pcv_colorNormalDaySelected="#d9d9d9"
        app:pcv_colorNormalDay="#f3f4f5"
        app:pcv_eventUnderlineColor="#02f0f0"
        app:pcv_fontSize="20sp"
        app:pcv_headersFontSize="14sp"/>
        </android.support.v7.widget.CardView>
        </LinearLayout>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        android:layout_marginBottom="8dp">

        <TextView
            android:id="@+id/txt_day_month"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textColor="@color/colorAccent"
            android:layout_gravity="center_horizontal"
            android:textSize="30sp"/>

        <TextView
            android:id="@+id/txt_year"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_horizontal"
            android:textColor="@color/colorAccent"
            android:textSize="20sp"/>
    </LinearLayout>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center_horizontal">

        <Button
            android:id="@+id/change_to_ad"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Change to Gregorian Calendar"
            android:textSize="14dp"/>
    </LinearLayout>
</LinearLayout>

logCat:

java.lang.RuntimeException: Unable to start activity ComponentInfo{com.drgnme.listhamrah/com.drgnme.listhamrah.MainActivity}: java.lang.IllegalStateException: Fragment has not been attached yet.
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2434)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2494)
at android.app.ActivityThread.handleRelaunchActivity(ActivityThread.java:4095)
at android.app.ActivityThread.access00(ActivityThread.java:153)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1353)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:148)
at android.app.ActivityThread.main(ActivityThread.java:5451)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
Caused by: java.lang.IllegalStateException: Fragment has not been attached yet.
at android.support.v4.app.Fragment.instantiateChildFragmentManager(Fragment.java:2195)
at android.support.v4.app.Fragment.getChildFragmentManager(Fragment.java:745)
at ir.mirrajabi.persiancalendar.core.fragments.CalendarFragment.createViewPagers(CalendarFragment.java:55)
at ir.mirrajabi.persiancalendar.core.fragments.CalendarFragment.access[=14=]0(CalendarFragment.java:27)
at ir.mirrajabi.persiancalendar.core.fragments.CalendarFragment.update(CalendarFragment.java:46)
at ir.mirrajabi.persiancalendar.PersianCalendarView.update(PersianCalendarView.java:116)
at com.drgnme.listhamrah.FragmentTwo.onCreateView(FragmentTwo.java:87)
at android.support.v4.app.Fragment.performCreateView(Fragment.java:2239)
at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1332)
at android.support.v4.app.FragmentManagerImpl.moveFragmentToExpectedState(FragmentManager.java:1574)
at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1641)
at android.support.v4.app.FragmentManagerImpl.dispatchActivityCreated(FragmentManager.java:2959)
at android.support.v4.app.FragmentController.dispatchActivityCreated(FragmentController.java:201)
at android.support.v4.app.FragmentActivity.onStart(FragmentActivity.java:550)
at android.support.v7.app.AppCompatActivity.onStart(AppCompatActivity.java:177)
at android.app.Instrumentation.callActivityOnStart(Instrumentation.java:1238)
at android.app.Activity.performStart(Activity.java:6340)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2397)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2494) 
at android.app.ActivityThread.handleRelaunchActivity(ActivityThread.java:4095) 
at android.app.ActivityThread.access00(ActivityThread.java:153) 
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1353) 
at android.os.Handler.dispatchMessage(Handler.java:102) 
at android.os.Looper.loop(Looper.java:148) 
at android.app.ActivityThread.main(ActivityThread.java:5451) 
at java.lang.reflect.Method.invoke(Native Method) 
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726) 
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)

将以下所有代码移至onActivityCreated():

final PersianCalendarView persianCalendarView = (PersianCalendarView) view.findViewById(R.id.persian_calendar);
        final PersianCalendarHandler calendar = persianCalendarView.getCalendar();
        final PersianDate today = calendar.getToday();
        calendar.addLocalEvent(new CalendarEvent(
                today, "Custom event", false
        ));
        calendar.addLocalEvent(new CalendarEvent(
                today.clone().rollDay(2, true), "Custom event 2", true
        ));
        calendar.setOnMonthChangedListener(new OnMonthChangedListener() {
            @Override
            public void onChanged(PersianDate date) {
                Toast.makeText(getActivity(), calendar.getMonthName(date), Toast.LENGTH_SHORT).show();
            }
        });
        persianCalendarView.setOnDayClickedListener(new OnDayClickedListener() {
            @Override
            public void onClick(PersianDate date) {
                for (CalendarEvent e : calendar.getAllEventsForDay(date))
                    Toast.makeText(getActivity(), e.getTitle(), Toast.LENGTH_LONG).show();


                calendar.addLocalEvent(new CalendarEvent(
                        today.clone().rollDay(2, false), "Some event that will be added in runtime", false
                ));
                persianCalendarView.update();
            }
        });

        calendar.setHighlightOfficialEvents(false);
        TextView txtDayMonth = (TextView) view.findViewById(R.id.txt_day_month);
        TextView txtYear = (TextView) view.findViewById(R.id.txt_year);

        String dayAndMonth = calendar.getWeekDayName(today) + calendar.formatNumber(today.getDayOfMonth())
                + calendar.getMonthName(today);
        txtDayMonth.setText(dayAndMonth);
        txtYear.setText(calendar.formatNumber(today.getYear()));

        calendar.setColorBackground(getResources().getColor(android.R.color.holo_blue_dark));
        persianCalendarView.update();

最佳做法是除了膨胀内部布局外不做任何工作 onCreateView()

问题不在你的应用程序中,问题在 PersianCalendar Lib 中,

如果您在 PersianCalendarView.java 中检查它们的实现,则您正在 Fragment class 的布局中膨胀 PersianCalendarView,1. 他们正在膨胀一种布局,并且他们正试图在该布局中添加一个 Fragment在那个 FragmentManager 中,它工作正常。 2. 但不仅如此,在该片段中,他们还试图使用 getChildFragmentManager() 添加 ViewPager 问题只出现在她身上。

你可以问为什么?已经有一个 FragmentManager 添加了这个 Fragment,当时它工作正常但现在它崩溃了,为此,您可以检查 this S0 Answer

中那两个 FragmnetManger 之间的区别

对于这个问题,你可以做3件事, 1. 你可以给他们建票,等结果 2. 你可以解决这个问题 3. 不用在布局中添加,只需在片段中创建一个 ViewGroup,当调用 onActivtyCreated 时,您可以添加该布局运行时。

已编辑

我尝试了那个示例,并尝试将它添加到 Fragment 中,我遇到的问题是,实际上 CalendarView 片段没有附加,即使我们的 Fragment 附加到 Activity,正如我在解决方案中提到的3 说我们可以把它加在onActivtyCreated里面是错误的。

那我们暂时怎么解决呢?

我通过在 onStart 中添加视图来解决(我知道这是错误的地方,这将在 Fragment 的生命周期中调用多次),但是我们可以添加一些逻辑,我们可以添加这个日历只查看一次以使其现在工作,直到他们的库中的开发修复。

我的样本:

我的片段布局:

<FrameLayout 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"
             tools:context="ir.mirrajabi.pc.sample.BlankFragment">

    <LinearLayout
        android:id="@+id/calendar_container"
        android:layout_width="match_parent"
        android:layout_height="290dp"
        android:orientation="vertical"/>

    <TextView
        android:id="@+id/txt_day_month"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:textColor="#f0f2f3"
        android:textSize="30sp"/>

    <TextView
        android:id="@+id/txt_year"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:textColor="#c6d9e2"
        android:textSize="20sp"/>

</FrameLayout>

片段代码

public class BlankFragment extends Fragment {

    private LinearLayout mLinearLayout;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_blank, container, false);

        mLinearLayout= (LinearLayout) view.findViewById(R.id.calendar_container);

        return view;
    }

    @Override
    public void onStart() {
        super.onStart();

        final PersianCalendarView persianCalendarView = new PersianCalendarView(getContext());

        // All your remaining PersianCalendarView implementation code here
        mLinearLayout.addView(persianCalendarView);
    }
}

注:

If you take above approach, Please add some logic and make sure it's not adding multiple time when onStart calls in the Fragment.

只需将 persianCalendarView.update() 行移动到 FragmentTwoonAttach 中并将其从 onCreate() 中删除:

@Override
public void onAttachFragment(Fragment childFragment) {
    super.onAttachFragment(childFragment);
    persianCalendarView.update();
}

同时从 persianCalendarViewOnDayClickedListener 中删除 update()。我在测试时添加了该行,但忘记将其从示例应用程序中删除。 您不必更新persianCalendarView除非您需要更改主题在运行时添加事件 .