5

我使用ACL中的ViewPager顯示Fragment的幾個。起初,這些碎片全部是ListFragment,因爲它們包含一個列表。我試圖模仿2列表,因此列表中的每個元素都包含另外兩個對象的列表。我希望每個單元格都是可長期點擊的(不是整個列表項目),因此我實現了自己的ColumnLayout(也許它應該稱爲CellLayout)。每個列表項都包含兩個可長期點擊的ColumnLayout,並實現getContextMenuInfo()以返回有關長按哪個實體的信息。此方法查找ViewPager,請求當前片段,然後調用片段以從長按的視圖中返回實體ID。爲了得到正確的行片段需要做的:onCreateView未在ViewPager中使用片段調用

getListView().getPositionForView(v) 

而這裏是問題的出發點。有時getListView()會拋出IllegalStateException說「內容視圖尚未創建」。即onCreateView(...)尚未被調用。這隻有在應用程序恢復時纔會發生。今天,我通過啓用Galaxy Nexus上的「設置」>「開發人員選項」中的「不要保留活動」選項來重新產生問題。我啓動應用程序,按主頁,然後從最近的應用程序菜單重新打開應用程序,現在,如果我長時間點擊列表視圖中的任何單元格,都會引發此異常。通過一些調試輸出,我設法驗證了onCreateView從未被調用過。這有點奇怪,因爲整個ViewPager及其片段和它的ListView及其單元格項都是繪製的!

我在#android-dev上被告知ACL中的ListFragment不支持自定義佈局,所以我重新實現了我的android.support.v4.app.Fragment而未使用ListFragment但這沒有幫助。

簡短摘要:我有它處理的情況下的自定義佈局長按用於創建關於在按下所述細胞entitiy一個MenuInfo對象包含信息的目的的佈局。爲了找到佈局中包含的實體,最終調用listview.getPositionForView(View v),有時會導致IllegalStateException

這裏我的自定義佈局(也許有一個更簡單的方式來獲得ViewPager的保持比視圖層次挖掘):

package org.remotestick; 

import android.content.Context; 
import android.support.v4.view.ViewPager; 
import android.util.AttributeSet; 
import android.view.ContextMenu.ContextMenuInfo; 
import android.view.View; 
import android.widget.LinearLayout; 

public class ColumnLayout extends LinearLayout { 

    public ColumnLayout(Context context, AttributeSet attrs) { 
     super(context, attrs); 
    } 

    public ColumnLayout(Context context) { 
     super(context); 
    } 

    @Override 
    protected ContextMenuInfo getContextMenuInfo() { 
     int itemTypeId = getChildAt(0).getId(); 
     int positionTypeId = getId(); 
     View currentView = this; 
     ViewPager viewPager = null; 
     while(currentView.getParent() != null) { 
      currentView = (View) currentView.getParent(); 
      if(currentView.getId() == R.id.pager) { 
       viewPager = (ViewPager) currentView; 
       break; 
      } else if (currentView.getId() == R.id.rootLayout) 
       break; 
     } 
     if(viewPager == null) 
      return null; 

     WorkspaceAdapter adapter = (WorkspaceAdapter) viewPager.getAdapter(); 
     Pair<Integer, Integer> itemIdAndListPosition = adapter.getItemIdFromWorkspace(viewPager.getCurrentItem(), this, itemTypeId, (positionTypeId == R.id.leftColumn)); 
     if(itemIdAndListPosition == null) 
      return null; 
     else 
      return new MatrixAdaptableContextMenuInfo(itemTypeId, itemIdAndListPosition.first, itemIdAndListPosition.second); 
    } 

    public static class MatrixAdaptableContextMenuInfo implements ContextMenuInfo { 

     public final int itemTypeId; 
     public final Integer itemId; 
     public final Integer positionInList; 

     public MatrixAdaptableContextMenuInfo(int itemTypeId, Integer itemId, Integer positionInList) { 
      this.itemTypeId = itemTypeId; 
      this.itemId = itemId; 
      this.positionInList = positionInList; 
     } 

    } 
} 

而這裏的(的片段)的Fragment

public class EntityTableFragment extends Fragment implements TelldusEntityChangeListener { 

    protected static final String ARG_TITLE = "title"; 

    protected MatrixAdapter mAdapter; 
    protected ProgressViewer mProgressViewer; 
    protected MatrixFilter mFilter; 
    protected Handler mHandler = new Handler(); 
    protected RemoteStickData db; 

    public boolean onAttach = false; 
    public boolean onCreateView = false; 

    private ListView listView; 

    public static EntityTableFragment newInstance(String title) { 
     EntityTableFragment f = new EntityTableFragment(); 

     Bundle args = new Bundle(); 
     args.putString(ARG_TITLE, title); 
     f.setArguments(args); 
     return f; 
    } 

    @Override 
    public void onAttach(SupportActivity activity) { 
     super.onAttach(activity); 
     onAttach = true; 
      try { 
      mProgressViewer = (ProgressViewer) activity; 
      mAdapter = new MatrixAdapter(getActivity(), mProgressViewer, new ArrayList<List<MatrixEntity>>(), null); 
      TelldusLiveService.addListener(this); 
     } catch (ClassCastException e) { 
      throw new ClassCastException(activity.toString() + " must implement ProgressViewer"); 
     } 
     db = new RemoteStickData(getActivity()); 
    } 

    @Override 
    public void onDetach() { 
     super.onDetach(); 
     TelldusLiveService.removeListener(this); 
    } 

    @Override 
    public void onActivityCreated(Bundle savedInstanceState) { 
     super.onActivityCreated(savedInstanceState); 
     listView.setAdapter(mAdapter); 
    } 

    @Override 
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 
     View view = inflater.inflate(R.layout.list, null); 
     listView = (ListView) view.findViewById(R.id.list); 
     return view; 
    } 

    @Override 
    public String toString() { 
     return getArguments().getString(ARG_TITLE); 
    } 

    public Pair<Integer, Integer> getIdAndPositionForView(View v, boolean isLeft) { 
     if(listView == null) 
      throw new IllegalStateException("Listview not yet created"); 
     int positionForView = listView.getPositionForView(v); 
     if(isLeft) 
      return new Pair<Integer, Integer>(mAdapter.getItem(positionForView).get(0).getId(), positionForView); 
     else 
      return new Pair<Integer, Integer>(mAdapter.getItem(positionForView).get(1).getId(), positionForView); 
    } 

是不是很奇怪,當恢復應用程序(如果活動被銷燬),ViewPager及其碎片及其ListView及其自定義佈局全部繪製。但我得到IllegalStateException說如果我長按列表視圖中的任何單元格,視圖還沒有創建?

編輯/ 其實,在onCreateView一個Log.d(Constants.TAG, "onCreateView!!!!");輸出顯示方法被調用我第一次啓動應用程序(一個在ViewPager每個片段),但是它從來沒有再次調用時,應用程序恢復的兩倍! ?這是一個錯誤,或者我可能做錯了什麼?

回答

4

關鍵部分似乎是FragmentPagerAdapter(我沒有包括)。調試顯示在重新創建活動時不會調用getItem()。碎片是通過其他方式重新創建的。這意味着我對FragmentPagerAdapter的執行錯誤地引用了FragmentManager中的片段。

因此,當我需要查找片段時,我使用findFragmentByTag()(在FragmentManager上)使用makeFragmentName()來獲取適當的標籤名稱。這是在添加片段時由FragmentPagerAdapter使用的方法。雖然不確定這是否安全。

相關問題