2011-09-28 8 views
8

Tôi đang phát triển ứng dụng Android cho máy tính bảng và không phải bằng thư viện tương thích.IllegalArgumentException: Không tìm thấy chế độ xem cho id cho đoạn khi chuyển đổi nhanh tab ActionBar

Chỉ có một Hoạt động và nó sử dụng ActionBar với 3 tab. Trong TabListener, tôi sử dụng setContentView để tải bố cục cụ thể cho tab đó và sau đó thêm các đoạn có liên quan vào khung của chúng. Điều này gần như hoạt động chính xác như tôi muốn, ngoại trừ khi bạn chuyển đổi giữa các tab đủ nhanh ứng dụng sẽ gặp sự cố.

Tôi đang sử dụng Tab Samsung Galaxy làm thiết bị gỡ lỗi và các tab chuyển đổi thực sự nhanh. Với tốc độ bình thường, tôi có thể chạm vào lại giữa chúng và các trang được tải ngay lập tức. Vấn đề là khi tôi chuyển đổi giữa các tab.

Lúc đầu, tôi có một

IllegalStateException: Fragment not added 

như đã thấy ở đây: http://code.google.com/p/android/issues/detail?id=17029 Tiếp theo gợi ý để sử dụng try/catch khối trong onTabUnselected, tôi đã ứng dụng một chút mạnh mẽ hơn, nhưng chì để vấn đề này tại bàn tay:

IllegalArgumentException: No view found for id 0x... for fragment ... 

Tôi không tìm thấy bất kỳ trường hợp nào khác trên web của bất kỳ ai khác có cùng vấn đề, vì vậy tôi lo ngại rằng tôi có thể đang làm một việc không được hỗ trợ. Một lần nữa, những gì tôi đang cố gắng làm là sử dụng 3 bố cục khác nhau trong một Hoạt động - khi bạn nhấp vào một tab, người nghe sẽ gọi setContentView để thay đổi bố cục và sau đó thêm các đoạn. Nó hoạt động rất đẹp trừ khi bạn bắt đầu chuyển đổi mạnh mẽ giữa các tab.

Tôi có ý tưởng về điều này từ: http://developer.android.com/resources/samples/ApiDemos/src/com/example/android/apis/app/FragmentTabs.html và thay vì TabListener giữ tham chiếu đến một đoạn, tôi có một mảng. Ngoài ra, tôi không sử dụng đính kèm/tách ra vì chúng chỉ được thêm vào API 13.

Lý thuyết của tôi là setContentView chưa hoàn thành việc tạo khung nhìn, và đó là lý do tại sao FragmentTransaction không thể thêm chúng, HOẶC các đoạn được thêm vào cho một tab khi một tab khác được chọn và setContentView được gọi, phá hủy tập hợp các chế độ xem khác.

Tôi đã cố gắng hack thứ gì đó để làm chậm chuyển đổi tab nhưng không nhận được bất kỳ đâu.

Đây là mã cho TabListener tôi:

private class BTabListener<T extends Fragment> implements ActionBar.TabListener{ 

    private int mLayout; 
    private Fragment[] mFrags; 
    private TabData mTabData; 
    private Activity mAct; 
    private boolean mNoNewFrags; 


    public BTabListener(Activity act, int layout, TabData td, boolean frags){ 
     mLayout = layout; 
     mTabData = td; 
     mAct = act; 
     mNoNewFrags = frags; 

     mFrags = new Fragment[mTabData.fragTags.length]; 
     for(int i=0; i<mFrags.length; i++){ 
      //on an orientation change, this will find the fragments that were recreated by the system 
      mFrags[i] = mAct.getFragmentManager().findFragmentByTag(mTabData.fragTags[i]); 
     } 

    } 

    @Override 
    public void onTabReselected(Tab tab, FragmentTransaction ft) { 

    } 

    @Override 
    public void onTabSelected(Tab tab, FragmentTransaction ft) { 
     //this gets called _after_ unselected 
     //note: unselected wont have been called after an orientation change! 
     //we also need to watch out because tab 0 always gets selected when adding the tabs 

     //set the view for this tab 
     mAct.setContentView(mLayout); 

     for(int i=0; i<mFrags.length; i++){ 
      //this will be null when the tab is first selected 
      if(mFrags[i]==null){ 
       mFrags[i] = Fragment.instantiate(GUITablet.this, mTabData.classes[i].getName());      
      } 

      //if there was an orientation change when we were on this page, the fragment is already added 
      if(!mNoNewFrags || mDefaultTab!=tab.getPosition()){ 
       ft.add(mTabData.containterIDs[i], mFrags[i], mTabData.fragTags[i]); 
      } 
     } 
     mNoNewFrags = false; 


    } 

    @Override 
    public void onTabUnselected(Tab tab, FragmentTransaction ft) { 
     // this gets called when another tab is selected, before it's onSelected method 

     for(Fragment f : mFrags){ 
      try{ //extra safety measure 
       ft.remove(f); 
      }catch(Exception e){ 
       e.printStackTrace(); 
       System.out.println("unselect couldnt remove"); 
      } 
     } 
    } 

} 

Và cuối cùng, stack trace:

09-29 01:53:08.200: ERROR/AndroidRuntime(4611): java.lang.IllegalArgumentException: No view found for id 0x7f0b0078 for fragment Fraggle{40ab2230 #2 id=0x7f0b0078 dummy2} 
09-29 01:53:08.200: ERROR/AndroidRuntime(4611):  at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:729) 
09-29 01:53:08.200: ERROR/AndroidRuntime(4611):  at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:926) 
09-29 01:53:08.200: ERROR/AndroidRuntime(4611):  at android.app.BackStackRecord.run(BackStackRecord.java:578) 
09-29 01:53:08.200: ERROR/AndroidRuntime(4611):  at android.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1226) 
09-29 01:53:08.200: ERROR/AndroidRuntime(4611):  at android.app.FragmentManagerImpl$1.run(FragmentManager.java:374) 
09-29 01:53:08.200: ERROR/AndroidRuntime(4611):  at android.os.Handler.handleCallback(Handler.java:587) 
09-29 01:53:08.200: ERROR/AndroidRuntime(4611):  at android.os.Handler.dispatchMessage(Handler.java:92) 
09-29 01:53:08.200: ERROR/AndroidRuntime(4611):  at android.os.Looper.loop(Looper.java:132) 
09-29 01:53:08.200: ERROR/AndroidRuntime(4611):  at android.app.ActivityThread.main(ActivityThread.java:4028) 
09-29 01:53:08.200: ERROR/AndroidRuntime(4611):  at java.lang.reflect.Method.invokeNative(Native Method) 
09-29 01:53:08.200: ERROR/AndroidRuntime(4611):  at java.lang.reflect.Method.invoke(Method.java:491) 
09-29 01:53:08.200: ERROR/AndroidRuntime(4611):  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:844) 
09-29 01:53:08.200: ERROR/AndroidRuntime(4611):  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:602) 
09-29 01:53:08.200: ERROR/AndroidRuntime(4611):  at dalvik.system.NativeStart.main(Native Method) 

THANK YOU !!

+0

Bất kỳ ai có thể giúp tôi thoát khỏi lỗi này .... [link] [1] [1]: http://stackoverflow.com/questions/2540 0641/fragmentmanager-illegargumentexception-no-view-found-for-id-for-fragment? Noredirect = 1 –

+0

@SamKazmi, bạn có thử các câu trả lời được đề xuất không ...? – hooby3dfx

Trả lời

5

Được rồi, tìm thấy một khoảng cách này:

Đặt các tham chiếu đến các mảnh vỡ trong các tập tin bố trí, và bao quanh các cuộc gọi setContentView trong onTabSelected trong một khối try/catch.

Xử lý ngoại lệ đã giải quyết vấn đề!

+0

Bạn không chỉ kết thúc với một màn hình trống? – CACuzcatlan

+0

Tại sao tôi lại kết thúc bằng một màn hình trống? Tôi nghĩ rằng các lỗi chỉ xảy ra khi chuyển đổi nhanh hoặc trong chưa chọn hoặc chọn DURING một lựa chọn khác, vì vậy lựa chọn cuối cùng sẽ luôn hoạt động (không có ngoại lệ). – hooby3dfx

1

Tôi biết đó là một câu hỏi hơi cũ nhưng tôi đã có cùng và tìm một công việc khác xung quanh.

Phương pháp tự nó được mô tả ở đây Avoid recreating same view when perform tab switching

nhưng vào bối cảnh của vụ tai nạn đặc biệt này, làm Show/Hide thay vì thêm/thay thế tránh được nhiều cuộc gọi nhanh để onCreateView trên mảnh.

mã cuối cùng của tôi đã kết thúc một cái gì đó như thế này:

@Override 
public void onTabSelected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) { 
if (fragments[tab.getPosition()] == null) { 
    switch(tag.getPosition()){ 
     case 0: fragments[tab.getPosition()] = new // fragment for this position 
     break; 
     // repeat for all the tabs, for each `case` 
    } 
    fragmentTransaction.add(R.id.container, fragments[tab.getPosition()]); 
}else{ 
    fragmentTransaction.show(fragments[tab.getPosition()]); 
} 
} 

@Override 
public void onTabUnselected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) { 
if (fragments[tab.getPosition()] != null) 
    fragmentTransaction.hide(fragments[tab.getPosition()]); 
} 
0

Thấy một trường hợp tương tự trong một báo cáo tai nạn Google Play.

java.lang.IllegalStateException: 
    Fragment not added: MessageDisplayFragment{406e28f0 #2 id=0x7f0b0020} 
at android.app.BackStackRecord.hide(BackStackRecord.java:397) 
at org.kman.AquaMail.ui.AccountListActivity$UIMediator_API11_TwoPane. 
    closeMessageDisplay(AccountListActivity.java:2585) 

đang liên quan:

AbsMessageFragment fragDisplay = (AbsMessageFragment) 
    mFM.findFragmentById(R.id.fragment_id_message_display); 

if (fragDisplay != null) { 
    FragmentTransaction ft = mFM.beginTransaction(); 
    ft.setTransition(FragmentTransaction.TRANSIT_NONE); 
    ft.show(some other fragment); 
    ft.hide(fragDisplay); 

^^ Đây là nơi nó bị treo

Đoạn chắc chắn là có (nó đã được trả về bởi findFragmentById), nhưng gọi hide() thổi lên với "IllegalStateException: Phân đoạn không được thêm"

Không được thêm? Làm thế nào nó không được thêm nếu findFragmentById đã có thể tìm thấy nó?

Tất cả các cuộc gọi FragmentManager đang được thực hiện từ chuỗi giao diện người dùng.

Đoạn được xóa (fragDisplay) đã được thêm vào trước đó và tôi chắc chắn rằng FragmentTransaction của nó đã được cam kết.

0

Cố định nó bằng cách lặp qua các đoạn của tôi, xóa bất kỳ phần nào đã được thêm vào và sau đó thêm mới. Ngoài ra kiểm tra đầu tiên mà bạn không cố gắng để thay thế nó bằng null hoặc một đoạn hiện có.

Edit: trông giống như nó chỉ là

getChildFragmentManager().executePendingTransactions(); 

mà dừng lại nó từ đâm

private void replaceCurrentTabFragment(TabFragment tabFragment){ 

    if (tabFragment == null){ return; } 

    if (tabFragment == getActiveTabFragment()){ return; } 

    FragmentTransaction ft = getChildFragmentManager().beginTransaction(); 

    for (TabFragment fragment : mTabButtons.values()){ 
     if (((Fragment)fragment).isAdded()){ 
      ft.remove((Fragment)fragment); 
     } 
    } 

    ft.add(R.id.fragment_frameLayout, (Fragment) tabFragment); 
    ft.commit(); 
    getChildFragmentManager().executePendingTransactions(); 

} 

private TabFragment getActiveTabFragment(){ 
    return (TabFragment) getChildFragmentManager().findFragmentById(R.id.fragment_frameLayout); 
}