2013-07-13 41 views
9

我使用的是操作欄選項卡,因爲我需要導航元素放在每個頁面上。我使用ActionBarSherlock來實現向後兼容性(最低API 8,目標API 17)。我的MainActivity擴展了SherlockFragmentActivity。在我爲onCreate(),我有當使用後退按鈕時,片段並不總是被替換

ActionBar actionBar = getSupportActionBar(); 
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS); 

actionBar.setDisplayShowTitleEnabled(true); 

Tab tab1 = actionBar.newTab().setText("My Pages") 
    .setTabListener(new MyPagesFragment()); 

Tab tab2 = actionBar.newTab().setText("Search") 
    .setTabListener(new SearchFragment()); 

Tab tab3 = actionBar.newTab().setText("About") 
    .setTabListener(new AboutFragment()); 

// Start with the second tab selected. 
actionBar.addTab(tab1, 0, false); 
actionBar.addTab(tab2, 1, true); 
actionBar.addTab(tab3, 2, false); 

所有的標籤片段是實現ActionBar.TabListener SherlockListFragments,併爲此

@Override 
public void onTabSelected(Tab tab, FragmentTransaction ft) { 
    ft.replace(android.R.id.content, this, "mypages"); 
} 

@Override 
public void onTabUnselected(Tab tab, FragmentTransaction ft) { 
    ft.remove(this); 
} 

@Override 
public void onTabReselected(Tab tab, FragmentTransaction ft) { 
    // Force a complete reload. 
    onTabSelected(tab, ft); 
} 

搜索頁面有一個EditText和一個使用它的值AsyncTask從API獲取數據並將其添加到SQLite數據庫,然後調用

((MainActivity) getActivity()).showDetailView(responseCode); 

顯示細節,這是一種方法,在我的MainActivity如下:

protected void showDetailView(long codeID) { 
    SherlockFragment detailFragment = new DetailFragment(); 
    Bundle args = new Bundle(); 
    args.putLong("codeID", codeID); 
    detailFragment.setArguments(args); 

    FragmentManager manager = getSupportFragmentManager(); 
    FragmentTransaction ft = manager.beginTransaction(); 
    ft.replace(android.R.id.content, detailFragment); 
    ft.addToBackStack(null); 
    ft.commit(); 
} 

DetailFragment是SherlockFragment使用檢索codeID--

Bundle args = getArguments(); 
if (null != args) { 
    codeRowID = args.getLong("codeID"); 
} 

- - 從數據庫中讀取匹配的數據以顯示它。所述數據通常包含更多細節的鏈接,點擊會導致使用新的codeID再次調用showDetailView。

MyPages是所有緩存的詳細信息頁面的列表,並且它也呼籲showDetailView:

@Override 
public void onItemClick(AdapterView<?> parent, View v, int position, long id) { 
    ((MainActivity) getActivity()).showDetailView(pages[position].codeId); 
} 

展望未來,這似乎很好地工作。但是,當我使用後退按鈕時,有時候這些碎片會留下來,所以它們在恢復的碎片後面仍然可見。我如何阻止這種情況發生?


我認爲問題可能是標籤沒有被添加到後臺?但是當我嘗試這樣做時,他們會拋出異常告訴我他們不能添加到後臺,所以我不明白你應該如何處理這個問題。我不明白爲什麼這個東西看起來應該是很多人想要做的令人難以置信的基本導航事物 - 後退鍵已經在我見過的每個Android手機和桌面上,物理或軟件上! - 顯然沒有已知的解決方案。我是否從根本上誤解了他們的使用?在這種情況下是不是應該使用碎片?如果沒有在每個頁面上重複相同的代碼,您還會如何執行持久性導航元素?


記錄 - 啓動應用程序 -

07-20 23:33:49.521: D/NAVIGATION_TRACE(7425): MAIN - onCreate 
07-20 23:33:50.013: D/NAVIGATION_TRACE(7425): SEARCH - onTabSelected 
07-20 23:33:50.021: D/NAVIGATION_TRACE(7425): SEARCH - onCreateView 
07-20 23:33:50.060: D/NAVIGATION_TRACE(7425): SEARCH - onActivityCreated 
07-20 23:33:50.060: D/NAVIGATION_TRACE(7425): MAIN - onResume 

搜索現在可見。搜索項目以調出詳細視圖 -

07-20 23:34:52.123: D/NAVIGATION_TRACE(7425): SEARCH - handleResponseCode 
07-20 23:34:52.123: D/NAVIGATION_TRACE(7425): MAIN - showDetailView - 31 

細節現在可見;搜索消失了。點擊mypages標籤 -

07-20 23:35:37.787: D/NAVIGATION_TRACE(7425): SEARCH - onTabUnselected 
07-20 23:35:37.787: D/NAVIGATION_TRACE(7425): MYPAGES - onTabSelected 
07-20 23:35:37.826: D/NAVIGATION_TRACE(7425): MYPAGES - onCreateView 
07-20 23:35:37.873: D/NAVIGATION_TRACE(7425): MYPAGES - onActivityCreated 

MyPages now now visible;細節消失了。單擊後退按鈕 -

07-20 23:36:12.130: D/NAVIGATION_TRACE(7425): SEARCH - onCreateView 
07-20 23:36:12.201: D/NAVIGATION_TRACE(7425): SEARCH - onActivityCreated 

搜索 MyPages現在均顯示。


MainActivity:

public class MainActivity extends SherlockFragmentActivity 
{ 

    @Override 
    protected void onCreate(Bundle savedInstanceState) 
    { 
     super.onCreate(savedInstanceState); 
     Log.d("NAVIGATION_TRACE", "MAIN - onCreate"); 

     ActionBar actionBar = getSupportActionBar(); 
     actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS); 

     actionBar.setDisplayShowTitleEnabled(true); 

     Tab tab1 = actionBar.newTab().setText("My Pages") 
      .setTabListener(new TabListener<MyPagesFragment>(
      this, "mypages", MyPagesFragment.class)); 

     Tab tab2 = actionBar.newTab().setText("Search") 
      .setTabListener(new TabListener<SearchFragment>(
      this, "search", SearchFragment.class)); 

     Tab tab3 = actionBar.newTab().setText("About") 
      .setTabListener(new TabListener<AboutFragment>(
      this, "about", AboutFragment.class)); 

     // Start with the second tab selected. 
     actionBar.addTab(tab1, 0, false); 
     actionBar.addTab(tab2, 1, true); 
     actionBar.addTab(tab3, 2, false); 
    } 

    @Override 
    public void onBackPressed() 
    { 
     FragmentManager fm = getSupportFragmentManager(); 
     if (0 < fm.getBackStackEntryCount()) 
     { 
      super.onBackPressed(); 
     } else { 
      // prompt to quit 
      AlertDialog.Builder alertErrorResponse = new AlertDialog.Builder(this); 
      alertErrorResponse.setMessage("Close app?"); 
      alertErrorResponse.setNegativeButton("Cancel", null); 
      alertErrorResponse.setPositiveButton("OK", new DialogInterface.OnClickListener() 
      { 
      @Override 
      public void onClick(DialogInterface dialog, int which) 
      { 
       finish(); 
      } 
      }); 
      alertErrorResponse.show(); 
     } 
    } 

    public void showDetailView(long codeID) { 
     Log.d("NAVIGATION_TRACE", "MAIN - showDetailView - "+String.valueOf(codeID)); 
     lastShownCode = codeID; 
     FragmentManager manager = getSupportFragmentManager(); 
     FragmentTransaction ft = manager.beginTransaction(); 
     SherlockFragment detailFragment = new DetailFragment(); 
     Bundle args = new Bundle(); 
     args.putLong("codeID", codeID); 
     detailFragment.setArguments(args); 
     ft.replace(android.R.id.content, detailFragment, "details"); 
     ft.addToBackStack(null); 
     ft.commit(); 
    } 

    public class TabListener<T extends SherlockListFragment> implements ActionBar.TabListener 
    { 
     private final SherlockFragmentActivity mActivity; 
     private final String mTag; 
     private final Class<T> mClass; 
     private SherlockListFragment mFragment; 

     public TabListener (SherlockFragmentActivity activity, String tag, Class<T> clz) 
     { 
      Log.d("NAVIGATION_TRACE", "TabListener - "+tag+" - "+clz.getCanonicalName()); 
      mActivity = activity; 
      mTag = tag; 
      mClass = clz; 

      FragmentTransaction ft = mActivity.getSupportFragmentManager().beginTransaction(); 
      mFragment = (SherlockListFragment) mActivity.getSupportFragmentManager().findFragmentByTag(mTag); 
      if (mFragment != null && !mFragment.isDetached()) 
      { 
       Log.d("NAVIGATION_TRACE", "DETACH - "+mTag); 
       removeDetail(ft); 
       ft.detach(mFragment); 
      } 
      ft.commit(); 
     } 

     public void clearBackStack() 
     { 
      Log.d("NAVIGATION_TRACE", "clearBackStack - "+mTag); 
      FragmentManager fm = mActivity.getSupportFragmentManager(); 
      if (null != fm && 0 < fm.getBackStackEntryCount()) 
      { 
      fm.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE); 
      } 
     } 

     @Override 
     public void onTabSelected(Tab tab, FragmentTransaction ft) 
     { 
      Log.d("NAVIGATION_TRACE", "onTabSelected - "+mTag); 

      clearBackStack(); 

      ft = mActivity.getSupportFragmentManager().beginTransaction(); 

      if (mFragment == null) 
      { 
       Log.d("NAVIGATION_TRACE", "ADD/SHOW - "+mClass.getName()); 
       removeDetail(ft); 
       mFragment = (SherlockListFragment) SherlockListFragment.instantiate(mActivity, mClass.getName()); 
       ft.add(android.R.id.content, mFragment, mTag); 
       ft.commit(); 
      } 
      else 
      { 
       Log.d("NAVIGATION_TRACE", "ATTACH/SHOW - "+mClass.getName()); 
       removeDetail(ft); 
       ft.attach(mFragment); 
       ft.show(mFragment); 
       ft.commit(); 
      } 

     } 

     @Override 
     public void onTabUnselected(Tab tab, FragmentTransaction ft) 
     {   
      Log.d("NAVIGATION_TRACE", "onTabUnselected - "+mTag); 
      ft = mActivity.getSupportFragmentManager().beginTransaction(); 

      if (null != mFragment) 
      { 
       Log.d("NAVIGATION_TRACE", "HIDE/DETACH - "+mTag); 
       removeDetail(ft); 
       ft.hide(mFragment); 
       ft.detach(mFragment); 
       ft.commitAllowingStateLoss(); 
      } 
     } 

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

     public void removeDetail(FragmentTransaction ft) { 
      SherlockFragment detailFragment = (SherlockFragment) mActivity.getSupportFragmentManager().findFragmentByTag("details"); 
      if (null != detailFragment && !detailFragment.isDetached()) { 
      Log.d("NAVIGATION_TRACE", "DETACH - details"); 
      ft.detach(detailFragment); 
      } 
     } 
    } 
} 

例片段 - MyPagesFragment:

public class MyPagesFragment extends SherlockListFragment implements 
     OnItemClickListener 
    { 

    @Override 
    public View onCreateView(LayoutInflater inflater, ViewGroup container, 
     Bundle savedInstanceState) 
    { 
     Log.d("NAVIGATION_TRACE", "MYPAGES - onCreateView"); 
     View view = inflater.inflate(R.layout.mypages, null); 

     // code to set up list adapter here 
    } 

    @Override 
    public void onActivityCreated(Bundle savedInstanceState) { 
     super.onActivityCreated(savedInstanceState); 
     Log.d("NAVIGATION_TRACE", "MYPAGES - onActivityCreated"); 
     getListView().setOnItemClickListener(this); 
    } 

    @Override 
    public void onItemClick(AdapterView<?> parent, View v, int position, long id) 
    { 
     Log.d("NAVIGATION_TRACE", "MYPAGES - onItemClick"); 
     ((MainActivity) getActivity()).showDetailView(pages[position].codeId); 
    } 
} 

DetailFragment

public class DetailFragment extends SherlockFragment implements 
     OnItemClickListener 
{ 

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

     // bunch of display/list set up code goes here 

     return view; 
    } 

    @Override 
    public void onActivityCreated(Bundle savedInstanceState) { 
     super.onActivityCreated(savedInstanceState);  
     lvLinks.setOnItemClickListener(this); 
    } 

    @Override 
    public void onItemClick(AdapterView<?> parent, View view, int position, long id) 
    { 
     // Details page can open other details pages: 
     ((MainActivity) getActivity()).showDetailView(pages[position].id); 
    } 

} 

注意:所做的更改是在Sheldon的回答下完成的(他似乎已經刪除了他們的答案和評論),這就是爲什麼TabListener代碼在原始部分和以後發佈的代碼之間更改的原因。

我目前已經通過清空每個選項卡上的backstack選項,並將頂部選項卡作爲退出應用程序請求對待,這是好的,我想,但我真的希望用戶如果這是可能的話,能夠通過標籤保持支持(因爲這樣,例如,如果我是五個詳細頁面,我停下來快速搜索一些事實,結果證明,它不存在,我可以回來這些詳細信息頁面,並還上一個或多個按照不同的細節鏈接。)

+0

片段可見的是'DetailFragments'或一個助教的b片段?大多數選項卡都是 – Luksprog

+0

。我之前已經在DetailFragments背後的DetailFragments結束了,但是我無法確定通過哪個路徑導致該問題,儘管如此,這可能是一個無關緊要的問題。 – vestofwarlock

+0

@vestofwarlock你可以提供所有的java文件和佈局,我可以導入到Eclipse嗎? – Sadegh

回答

1

試試這個..下面

FragmentManager manager = getSupportFragmentManager(); 
    if (manager.getBackStackEntryCount() > 0) 
     getSupportFragmentManager().popBackStack(); 
    else 
     finish(); 
+0

我最後得到了空的碎片 - 標籤欄顯示,但沒有任何顯示在它下面。奇怪的是,有時候再次回擊使得前面的片段顯示出來,這讓我認爲第一個片段也被彈出,但是我需要做一些其他的事情來使它顯示出來? – vestofwarlock