Gặp lỗi “Java.lang.IllegalStateException Activity đã bị phá hủy” khi sử dụng các tab với ViewPager


110

Tôi có một ứng dụng bao gồm sử dụng ActionBarSherlock ở chế độ tab. Tôi có 5 tab và nội dung của mỗi tab được xử lý bằng cách sử dụng các đoạn. Tuy nhiên, đối với tab2, tôi có một phân đoạn tệp xml chứa một phần tử ViewPager, đến lượt nó có một số trang phân mảnh. Khi tôi khởi động ứng dụng lần đầu, tôi có thể chuyển đổi giữa các tab không có vấn đề gì nhưng khi tôi nhấn vào tab2 lần thứ hai, tôi gặp lỗi được đề cập ở trên. Hoạt động chính như sau:

public class MainActivity extends SherlockFragmentActivity
{
    @Override
    protected void onCreate(Bundle savedInstanceState) 
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        ActionBar actionBar = getSupportActionBar();

        ActionBar.Tab tab1 = actionBar.newTab().setText("Tab1");
        ActionBar.Tab tab3 = actionBar.newTab().setText("Tab3");
        ActionBar.Tab tab2 = actionBar.newTab().setText("Tab2");
        ActionBar.Tab tab4 = actionBar.newTab().setText("Tab4");
        ActionBar.Tab tab5 = actionBar.newTab().setText("Tab5");

        Fragment fragment1 = new Tab1();
        Fragment fragment3 = new Tab3();
        Fragment fragment2 = new Tab2();
        Fragment fragment5 = new Tab5();
        Fragment fragment4 = new Tab4();

        tab1.setTabListener(new MyTabListener(fragment1));
        tab3.setTabListener(new MyTabListener(fragment3));
        tab2.setTabListener(new MyTabListener(fragment2));
        tab5.setTabListener(new MyTabListener(fragment5));
        tab4.setTabListener(new MyTabListener(fragment4));

        actionBar.addTab(tab1);
        actionBar.addTab(tab2);
        actionBar.addTab(tab3);
        actionBar.addTab(tab4);
        actionBar.addTab(tab5); 

        actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
    }

    class MyTabListener implements ActionBar.TabListener
    {
        Fragment fragment;

        public MyTabListener(Fragment fragment)
        {
            this.fragment = fragment;
        }

        @Override
        public void onTabSelected(com.actionbarsherlock.app.ActionBar.Tab tab,FragmentTransaction ft) 
        {
            ft.replace(R.id.fragment_container,fragment);
        }

        @Override
        public void onTabUnselected(com.actionbarsherlock.app.ActionBar.Tab tab,FragmentTransaction ft) 
        {

        }

        @Override
        public void onTabReselected(com.actionbarsherlock.app.ActionBar.Tab tab,FragmentTransaction ft) 
        {

        }
    }
}

Lớp phân mảnh không có ViewPager như sau:

public class Tab1 extends Fragment 
{
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState)
    {
        return inflater.inflate(R.layout.activity_tab1, container, false);
    }
}

Lớp phân mảnh với ViewPager như sau:

public class Tab2 extends Fragment 
{
    ViewPager mViewPager;
    private MyFragmentPagerAdapter mMyFragmentPagerAdapter;  
    private static int NUMBER_OF_PAGES = 5;

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

    @Override
    public void onViewCreated(View view,Bundle savedInstanceState)
    {
        super.onViewCreated(view, savedInstanceState);
        mViewPager = (ViewPager) view.findViewById(R.id.viewpager);
        mMyFragmentPagerAdapter = new MyFragmentPagerAdapter(getChildFragmentManager());  
        mViewPager.setAdapter(mMyFragmentPagerAdapter);  
    }

    private static class MyFragmentPagerAdapter extends FragmentPagerAdapter 
    {    
        public MyFragmentPagerAdapter(FragmentManager fm) 
        {  
             super(fm);  
        }  

        @Override  
        public Fragment getItem(int index) 
        {  
             return PageFragment.newInstance("My Message " + index);
        }  

        @Override  
        public int getCount() 
        {  
             return NUMBER_OF_PAGES;  
        }  
   }
}

Từ những gì tôi đã đọc ở những nơi khác nhau (và vui lòng sửa cho tôi nếu tôi sai), điều này xảy ra bởi vì trình quản lý phân đoạn trên lượt thứ hai cố gắng sử dụng lại các phân đoạn từ hoạt động không tồn tại nữa, do đó gây ra lỗi. Nhưng tôi không chắc tại sao điều này lại xảy ra ở đây vì tôi không sử dụng hoạt động phân mảnh. Theo logcat, lỗi nằm trong lớp Tab2, phương thức onViewCreate trên dòng có nội dung mViewPager.setAdapter (mMyFragmentPagerAdapter). Bất kỳ trợ giúp được đánh giá rất nhiều, cảm ơn.

03-04 12:01:05.468: E/AndroidRuntime(2474): FATAL EXCEPTION: main
03-04 12:01:05.468: E/AndroidRuntime(2474): java.lang.IllegalStateException: Activity has been destroyed
03-04 12:01:05.468: E/AndroidRuntime(2474):     at android.support.v4.app.FragmentManagerImpl.enqueueAction(FragmentManager.java:1342)
03-04 12:01:05.468: E/AndroidRuntime(2474):     at android.support.v4.app.BackStackRecord.commitInternal(BackStackRecord.java:595)
03-04 12:01:05.468: E/AndroidRuntime(2474):     at android.support.v4.app.BackStackRecord.commitAllowingStateLoss(BackStackRecord.java:578)
03-04 12:01:05.468: E/AndroidRuntime(2474):     at android.support.v4.app.FragmentPagerAdapter.finishUpdate(FragmentPagerAdapter.java:139)
03-04 12:01:05.468: E/AndroidRuntime(2474):     at android.support.v4.view.ViewPager.populate(ViewPager.java:1011)
03-04 12:01:05.468: E/AndroidRuntime(2474):     at android.support.v4.view.ViewPager.populate(ViewPager.java:880)
03-04 12:01:05.468: E/AndroidRuntime(2474):     at android.support.v4.view.ViewPager.setAdapter(ViewPager.java:433)
03-04 12:01:05.468: E/AndroidRuntime(2474):     at com.example.tabs.Tab2.onViewCreated(Tab2.java:31)
03-04 12:01:05.468: E/AndroidRuntime(2474):     at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:925)
03-04 12:01:05.468: E/AndroidRuntime(2474):     at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1088)
03-04 12:01:05.468: E/AndroidRuntime(2474):     at android.support.v4.app.BackStackRecord.run(BackStackRecord.java:682)
03-04 12:01:05.468: E/AndroidRuntime(2474):     at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1444)
03-04 12:01:05.468: E/AndroidRuntime(2474):     at android.support.v4.app.FragmentManagerImpl$1.run(FragmentManager.java:429)
03-04 12:01:05.468: E/AndroidRuntime(2474):     at android.os.Handler.handleCallback(Handler.java:587)
03-04 12:01:05.468: E/AndroidRuntime(2474):     at android.os.Handler.dispatchMessage(Handler.java:92)
03-04 12:01:05.468: E/AndroidRuntime(2474):     at android.os.Looper.loop(Looper.java:123)
03-04 12:01:05.468: E/AndroidRuntime(2474):     at android.app.ActivityThread.main(ActivityThread.java:3687)
03-04 12:01:05.468: E/AndroidRuntime(2474):     at java.lang.reflect.Method.invokeNative(Native Method)
03-04 12:01:05.468: E/AndroidRuntime(2474):     at java.lang.reflect.Method.invoke(Method.java:507)
03-04 12:01:05.468: E/AndroidRuntime(2474):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:842)
03-04 12:01:05.468: E/AndroidRuntime(2474):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:600)
03-04 12:01:05.468: E/AndroidRuntime(2474):     at dalvik.system.NativeStart.main(Native Method)

Vì vậy, tôi nghĩ rằng tôi có thể đã tìm ra vấn đề. Khi nhìn vào biến mMyFragmentPagerAdapter (lớp Tab2) thông qua trình gỡ lỗi nhật thực, tôi thấy rằng nó có một biến FragmentManager mà khi nhấp vào Tab2 lần đầu tiên có một trường gọi là mActivity trỏ đến MainActivity. Nhưng khi chuyển từ tab2 sang một số tab khác và xem xét lại mActivity, nó có giá trị là null, điều này có lẽ giải thích tại sao nó đưa ra lỗi Activity đã bị hủy.
Yulric Sequeira

Câu trả lời:


284

Đây dường như là một lỗi trong hỗ trợ mới được thêm vào cho các đoạn lồng nhau. Về cơ bản, đứa trẻ FragmentManagerkết thúc với một trạng thái bên trong bị phá vỡ khi nó bị tách ra khỏi hoạt động. Một giải pháp ngắn hạn đã khắc phục được vấn đề đó đối với tôi là thêm phần sau vào onDetach()mỗi Fragmentthứ bạn gọi getChildFragmentManager():

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

    try {
        Field childFragmentManager = Fragment.class.getDeclaredField("mChildFragmentManager");
        childFragmentManager.setAccessible(true);
        childFragmentManager.set(this, null);

    } catch (NoSuchFieldException e) {
        throw new RuntimeException(e);
    } catch (IllegalAccessException e) {
        throw new RuntimeException(e);
    }
}

21
Nếu bạn nhìn vào việc triển khai Fragment, bạn sẽ thấy rằng khi chuyển sang trạng thái tách rời, nó sẽ thiết lập lại trạng thái bên trong. Tuy nhiên, nó không đặt lại mChildFragmentManager (đây là một lỗi trong phiên bản hiện tại của thư viện hỗ trợ). Điều này khiến nó không gắn lại trình quản lý phân đoạn con khi Phân đoạn được gắn lại, gây ra ngoại lệ mà bạn đã thấy.
Marcus Forsell Stahre

14
Bạn phải đùa với tôi. Rất vui vì bạn đã đăng bài này, nhưng rất tiếc.
secureboot

8
Lỗi này đang được theo dõi trong trình theo dõi vấn đề Nguồn mở của Android: code.google.com/p/android/issues/detail?id=42601
Kristopher Johnson

3
Một chút muối nhưng điều này không thành công khi sử dụng phiên bản support-v4 hoặc phiên bản android.app. Vì vậy, các lỗi không chỉ xảy ra ở các thư viện hỗ trợ
gbero

6
Nó dường như đã được sửa trong thư viện hỗ trợ phiên bản 24.0.0. Phương thức 'performanceDetach ()' của 'android.support.v4.app.Fragment', do 'mChildFragmentManager = null;'.
Emerson Dallagnol

13

Tôi đang gặp chính xác cùng một vấn đề. Cách giải quyết duy nhất mà tôi đã tìm thấy, là thay thế các đoạn bằng một phiên bản mới, mỗi khi các tab được thay đổi.

ft.replace(R.id.fragment_container, Fragment.instantiate(PlayerMainActivity.this, fragment.getClass().getName()));

Không phải là một giải pháp thực sự, nhưng tôi chưa tìm ra cách để sử dụng lại phiên bản phân đoạn trước đó ...


1
Ồ, cảm ơn rất nhiều ... điều đó đã khắc phục được sự cố. Có thể giải thích tại sao nó hoạt động không?
Yulric Sequeira

1
Bạn đã phân tích dấu chân bộ nhớ của mình chưa? Bởi vì việc này có thể làm tăng nó, at-nhất tôi nghi ngờ
nmxprime

dont biết tại sao nó works..dont biết làm thế nào nó hoạt động nhưng nó hoạt động lol

7

Tôi gặp phải vấn đề tương tự khi gọi super.onCreate()ở cuối phương thức của mình. Lý do: attachActivity()được gọi trong onCreate () của FragmentActivity. Khi ghi đè onCreate()và, ví dụ, khi tạo tab, Trình quản lý tab sẽ cố gắng chuyển sang một phân đoạn trong khi không có hoạt động được gắn vào FragmentManager.

Giải pháp đơn giản: Di chuyển cuộc gọi super.onCreate()đến phần đầu của cơ quan chức năng.

Nói chung, có vẻ như có vô số lý do vấn đề này có thể xảy ra. Đây chỉ là một cái khác ...

Matthias


Cảm ơn bạn rất nhiều, bạn đã cứu ngày của tôi! Tôi đã gặp vấn đề tương tự và vẫn không thể giải quyết nó sau một tuần; (. Vì vậy, tôi rất vui vì bạn đã viết câu trả lời này !!!
JonasPTFL

4

Tôi muốn nói thêm rằng vấn đề của tôi là trong một hoạt động mà tôi đã cố gắng thực hiện FragmentTransactiononCreate TRƯỚC KHI tôi gọi super.onCreate(). Tôi vừa chuyển super.onCreate()đến đầu chức năng và đã hoạt động tốt.


2

Tôi gặp lỗi này vì tôi đang sử dụng LocalBroadcastManager và tôi đã làm:

unregisterReceiver(intentReloadFragmentReceiver);

thay vì:

LocalBroadcastManager.getInstance(this).unregisterReceiver(intentReloadFragmentReceiver);

1
điều này không giải quyết được vấn đề của tôi. Nhưng cám ơn nó đã giúp tôi để sửa chữa sai lầm của tôi về việc sử dụng BroadcastReceivers
nmxprime

Điều gì sẽ xảy ra nếu ngữ cảnh Hoạt động của bạn trống. Khi đó 'cái này' sẽ không hợp lệ.
IgorGanapolsky

khi ngữ cảnh Hoạt động có thể là rỗng? Tôi nghĩ là không bao giờ.
Malachiasz

2

Tôi gặp phải vấn đề tương tự và lateron phát hiện ra rằng, tôi đã bỏ lỡ cuộc gọi đến super.onCreate( savedInstanceState );trong onCreate()FragmentActivity.


1

Tôi đã gặp lỗi rất giống nhau khi cố gắng truy cập con FragmentManagertrước khi phân đoạn được khởi tạo hoàn toàn (tức là được đính kèm với Hoạt động hoặc ít nhất onCreateView()là được gọi). Khác FragmentManagerđược khởi tạo vớinull Hoạt động gây ra ngoại lệ nói trên.


1

Tôi buộc phân đoạn chứa phân đoạn con thành NULL trong onPause và nó đã khắc phục được sự cố của tôi

fragment = null;

1

Tôi biết đây là một bài đăng cũ, nhưng các câu trả lời được đề xuất không có tác dụng với tôi. Tôi muốn để điều này ở đây chỉ trong trường hợp ai đó sẽ thấy nó hữu ích.

Những gì tôi đã làm là:

@Override
public void onResume() {
    super.onResume();
    // add all fragments
    FragmentTransaction fragmentTransaction = getChildFragmentManager().beginTransaction();
    for(Fragment fragment : fragmentPages){
        String tag = fragment.getClass().getSimpleName();
        fragmentTransaction.add(R.id.contentPanel, fragment, tag);
        if(fragmentPages.indexOf(fragment) != currentPosition){
            fragmentTransaction.hide(fragment);
        } else {
            lastTag = tag;
        }
    }
    fragmentTransaction.commit();
}

Sau đó trong:

@Override
public void onPause() {
    super.onPause();
    // remove all attached fragments
    for(Fragment fragment: fragmentPages){
        getChildFragmentManager().beginTransaction().remove(fragment).commit();
    }
}

0

Tôi đã gặp sự cố này và tôi không thể tìm thấy giải pháp ở đây, vì vậy tôi muốn chia sẻ giải pháp của mình trong trường hợp người khác gặp sự cố này một lần nữa.

Tôi đã có mã này:

public void finishAction() {
  onDestroy();
  finish();
}

và giải quyết vấn đề bằng cách xóa dòng "onDestroy ();"

public void finishAction() {
  finish();
}

Lý do tôi viết mã ban đầu: Tôi biết rằng khi bạn thực thi "finish ()" thì hoạt động sẽ gọi "onDestroy ()", nhưng tôi đang sử dụng các luồng và tôi muốn đảm bảo rằng tất cả các luồng bị hủy trước khi bắt đầu hoạt động tiếp theo và có vẻ như "finish ()" không phải lúc nào cũng ngay lập tức. Tôi cần xử lý / giảm nhiều “Bitmap” và hiển thị các “bitmap” lớn và tôi đang nỗ lực cải thiện việc sử dụng bộ nhớ trong ứng dụng của mình

Bây giờ tôi sẽ giết các luồng bằng một phương thức khác và tôi sẽ thực thi phương thức này từ "onDestroy ();" và khi tôi nghĩ rằng tôi cần phải giết tất cả các chủ đề.

public void finishAction() {
  onDestroyThreads();
  finish();
}

0

Tôi có vấn đề này và nhận ra đó là vì tôi đã gọi setContentView(int id)hai lần trong tôi Activity'sonCreate


0

Điều này khiến tôi phát điên vì Xamarin.

Tôi gặp phải vấn đề này với một triển khai ViewPager cho TabLayout TRONG VÒNG MỘT Fragment, bản thân nó được triển khai trong DrawerLayout:

 - DrawerLayout
   - DrawerFragment
     - TabLayout
     - TabViewPager
       - TabViewPagerFragments

Vì vậy, bạn phải triển khai mã sau trong DrawerFragment của mình . Hãy lưu ý để chọn đúng FragmentManager-Path. Bởi vì bạn có thể có hai Tham chiếu FragmentManager khác nhau:

  1. Android.Support.V4.App.FragmentManager
  2. Android.App.FragmentManager

-> Chọn một trong những bạn sử dụng. Nếu bạn muốn sử dụng ChildFragmentManager, bạn phải sử dụng khai báo lớp Android.App.FragmentManager cho ViewPager của bạn!

Android.Support.V4.App.FragmentManager

Triển khai Phương pháp sau trong Phân đoạn "Chính" của bạn - trong ví dụ này: DrawerFragment

public override void OnDetach() {
    base.OnDetach();
    try {
        Fragment x = this;
        var classRefProp = typeof(Fragment).GetProperty("class_ref", BindingFlags.NonPublic | BindingFlags.Static);
        IntPtr classRef = (IntPtr)classRefProp.GetValue(x);
        var field = JNIEnv.GetFieldID(classRef, "mChildFragmentManager", "Landroid/support/v4/app/FragmentManagerImpl;");
        JNIEnv.SetField(base.Handle, field, IntPtr.Zero);
    }
    catch (Exception e) {
        Log.Debug("Error", e+"");
    }
}

Android.App.FragmentManager

public class TabViewPager: Android.Support.V13.App.FragmentPagerAdapter {}

Điều đó có nghĩa là bạn phải cài đặt ViewPager bằng Android.App.FragmentManager.

Triển khai Phương pháp sau trong Phân đoạn "Chính" của bạn - trong ví dụ này: DrawerFragment

public override void OnDetach() {
    base.OnDetach();
    try {
        Fragment x = this;
        var classRefProp = typeof(Fragment).GetProperty("class_ref", BindingFlags.NonPublic | BindingFlags.Static);
        IntPtr classRef = (IntPtr)classRefProp.GetValue(x);
        var field = JNIEnv.GetFieldID(classRef, "mChildFragmentManager", "Landroid/app/FragmentManagerImpl;");
        JNIEnv.SetField(base.Handle, field, IntPtr.Zero);
    }
    catch (Exception e) {
        Log.Debug("Error", e+"");
    }
}

0

Lỗi đã được sửa trong phiên bản androidx mới nhất. Và cách giải quyết nổi tiếng sẽ gây ra sự cố ngay bây giờ. vì vậy chúng ta không cần nó bây giờ.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.