天天看點

Android元件:Fragment切換後儲存狀态

之前寫的第一篇Fragment執行個體,和大多數人一開始學的一樣。都是通過FragmentTransaction的replace方法來實作,replace方法相當于先移除remove()原來全部已存在的fragments,然後加入add()目前這個fragment。這就導緻了一個問題,我們切換一次,然後再切換回來,相當于又一次載入了這個fragment,原來的狀态不複存在,這顯然與我們的日常使用不符。

想要儲存切換後的狀态。思路還是非常easy的。我們先加入了若幹fragments。切換後将全部fragments都隐藏hide()。并顯示show()切換後的fragment就可以。

執行個體:山寨微信

因為代碼較長。這裡僅僅講核心的部分,有興趣的能夠下載下傳源代碼來看一下

public class MainActivity extends ActionBarActivity implements OnClickListener {

  private View weixinLayout, tongxunluLayout, faxianLayout, woLayout;
  private TextView weixinTv, tongxunluTv, faxianTv, woTv;
  private ImageView weixinIv, tongxunluIv, faxianIv, woIv;
  private Fragment1 fragment1;
  private Fragment2 fragment2;
  private Fragment3 fragment3;
  private Fragment4 fragment4;
  private FragmentManager fm;

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    // 初始化
    initViews();

    fm = getFragmentManager();

    // 初識狀态是顯示微信
    weixinIv.setBackgroundResource(R.drawable.weixin2);
    weixinTv.setTextColor(getResources().getColor(R.color.green));
    showFragment(1);
  }

  void initViews() {
    // 注冊各IamgeView
    weixinIv = (ImageView) findViewById(R.id.weixin_iv);
    tongxunluIv = (ImageView) findViewById(R.id.tongxunlu_iv);
    faxianIv = (ImageView) findViewById(R.id.faxian_iv);
    woIv = (ImageView) findViewById(R.id.wo_iv);

    // 注冊各TextView
    weixinTv = (TextView) findViewById(R.id.weixin_tv);
    tongxunluTv = (TextView) findViewById(R.id.tongxunlu_tv);
    faxianTv = (TextView) findViewById(R.id.faxian_tv);
    woTv = (TextView) findViewById(R.id.wo_tv);

    // 注冊各Layout
    weixinLayout = (View) findViewById(R.id.weixin_layout);
    tongxunluLayout = (View) findViewById(R.id.tongxunlu_layout);
    faxianLayout = (View) findViewById(R.id.faxian_layout);
    woLayout = (View) findViewById(R.id.wo_layout);

    // 各Layout注冊監聽器
    weixinLayout.setOnClickListener(this);
    tongxunluLayout.setOnClickListener(this);
    faxianLayout.setOnClickListener(this);
    woLayout.setOnClickListener(this);

  }

  @Override
  public void onClick(View arg0) {
    // TODO Auto-generated method stub
    // 當點選某個layout時。先清除狀态。這裡的狀态指的是布局裡面的圖檔和文字
    clearState();
    switch (arg0.getId()) {
    case R.id.weixin_layout:
      // 假設點的是微信。将微信布局的圖檔和文字的顔色變為綠色
      weixinIv.setBackgroundResource(R.drawable.weixin2);
      weixinTv.setTextColor(getResources().getColor(R.color.green));
      // 顯示微信的fragment
      showFragment(1);
      break;
    case R.id.tongxunlu_layout:
      tongxunluIv.setBackgroundResource(R.drawable.tongxunlu2);
      tongxunluTv.setTextColor(getResources().getColor(R.color.green));
      showFragment(2);
      break;
    case R.id.faxian_layout:
      faxianIv.setBackgroundResource(R.drawable.faxian2);
      faxianTv.setTextColor(getResources().getColor(R.color.green));
      showFragment(3);
      break;
    case R.id.wo_layout:
      woIv.setBackgroundResource(R.drawable.wo2);
      woTv.setTextColor(getResources().getColor(R.color.green));
      showFragment(4);
      break;
    }
  }

  public void clearState() {
    // 未選中時的圖檔
    weixinIv.setBackgroundResource(R.drawable.weixin1);
    tongxunluIv.setBackgroundResource(R.drawable.tongxunlu1);
    faxianIv.setBackgroundResource(R.drawable.faxian1);
    woIv.setBackgroundResource(R.drawable.wo1);
    // 未選中時字型顔色
    weixinTv.setTextColor(getResources().getColor(R.color.black));
    tongxunluTv.setTextColor(getResources().getColor(R.color.black));
    faxianTv.setTextColor(getResources().getColor(R.color.black));
    woTv.setTextColor(getResources().getColor(R.color.black));
  }

  public void showFragment(int index) {
    FragmentTransaction ft = fm.beginTransaction();

    // 想要顯示一個fragment,先隐藏全部fragment。防止重疊
    hideFragments(ft);

    switch (index) {
    case 1:
      // 假設fragment1已經存在則将其顯示出來
      if (fragment1 != null)
        ft.show(fragment1);
      // 否則是第一次切換則加入fragment1,注意加入後是會顯示出來的。replace方法也是先remove後add
      else {
        fragment1 = new Fragment1();
        ft.add(R.id.content, fragment1);
      }
      break;
    case 2:
      if (fragment2 != null)
        ft.show(fragment2);
      else {
        fragment2 = new Fragment2();
        ft.add(R.id.content, fragment2);
      }
      break;
    case 3:
      if (fragment3 != null)
        ft.show(fragment3);
      else {
        fragment3 = new Fragment3();
        ft.add(R.id.content, fragment3);
      }
      break;
    case 4:
      if (fragment4 != null)
        ft.show(fragment4);
      else {
        fragment4 = new Fragment4();
        ft.add(R.id.content, fragment4);
      }
      break;
    }
    ft.commit();
  }

  // 當fragment已被執行個體化,就隐藏起來
  public void hideFragments(FragmentTransaction ft) {
    if (fragment1 != null)
      ft.hide(fragment1);
    if (fragment2 != null)
      ft.hide(fragment2);
    if (fragment3 != null)
      ft.hide(fragment3);
    if (fragment4 != null)
      ft.hide(fragment4);
  }

}      
Android元件:Fragment切換後儲存狀态

當我們一開始把微信fragment的ListView下拉到如上圖時,切換到通訊錄fragment。然後再切換回去微信fragment。此時微信的ListView還是原來的狀态。這是由于并不是又一次載入微信fragment,而是将其先hide起來,切換回來後再show出來。

引用上篇文章的fragment生命周期圖:

Android元件:Fragment切換後儲存狀态

假設是repalce方法,我們切換至目前fragment則進行紅線以上的生命周期。切換到其它fragment後進行紅線下面的生命周期。

可是。假設我們使用hide()和show()的方法,切換至目前fragment依舊進行紅線以上的生命周期,切換到其它fragment後并沒有進行其它生命周期,僅僅是簡單地隐藏了起來。這樣應該非常明了了吧。

繼續閱讀