最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

實例探究Android開發(fā)中Fragment狀態(tài)的保存與恢復(fù)方法

 更新時間:2016年04月27日 10:00:04   作者:FindWG  
這篇文章主要介紹了實例探究Android開發(fā)中Fragment狀態(tài)的保存與恢復(fù)方法,或許開發(fā)者們對Fragment的操作都比較熟悉,但onSaveInstanceState()方法并不能夠很好地保存Fragment狀態(tài),需要的朋友可以參考下

我們都知道,類似 Activity, Fragment 有 onSaveInstanceState() 回調(diào)用來保存狀態(tài)。

在Fragment里面,利用onSaveInstanceState保存數(shù)據(jù),并可在onActivityCreated里面恢復(fù)數(shù)據(jù)。

public void onActivityCreated(Bundle savedInstanceState) {
  super.onActivityCreated(savedInstanceState);
  ...
  if (savedInstanceState != null) {
    // Restore the fragment's state here
  }
}

public void onSaveInstanceState(Bundle outState) {
  super.onSaveInstanceState(outState);
  // Save the fragment's state here
}

但是,根據(jù)作者的經(jīng)驗,這個方法調(diào)用非常的不靠普。Fragment 在屏幕旋轉(zhuǎn)和返回堆棧(Backstack)中的時候,都會創(chuàng)建一個全新的 View,這個 onSaveInstanceState() 方法經(jīng)常會出現(xiàn)不會被調(diào)用的情況,導(dǎo)致 Fragment 的狀態(tài)丟失。

我們來通過接下來的實例尋找解決方法。

首先,盡管已經(jīng)有了一個類似 Activity 中的 onSaveInstanceState 方法,但是它顯然不能覆蓋所有情況。換種說法就是,你不能僅僅依賴于 onSaveInstanceState 方法來保存/恢復(fù)視圖的狀態(tài)。這里有一些案例研究。

案例1:只有一個 Fragment 在棧中時,旋轉(zhuǎn)屏幕

201642795611832.jpeg (900×450)

屏幕旋轉(zhuǎn)是用來測試實例狀態(tài)的保存/恢復(fù)的最簡單的案例。這種情況很容易處理,你僅僅需要簡單地保存一些東西,比如:成員變量,它也會在屏幕旋轉(zhuǎn)時在 onSaveInstanceState 丟失,在 onActivityCreated 或者 onViewStateRestored 中恢復(fù),如下所示:

int someVar;
@Override
  protected void onSaveInstanceState(Bundle outState) {
  outState.putInt("someVar", someVar);
  outState.putString(“text”, tv1.getText().toString());
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
  super.onActivityCreated(savedInstanceState);
  someVar = savedInstanceState.getInt("someVar", 0);
  tv1.setText(savedInstanceState.getString(“text”));
}

看上去是不是很好?不過也不是全不管用。這種情況是在 onSaveInstanceState 不被回調(diào),但是視圖重新生成。這意味著什么?UI 里的所有東西都沒了。下面就是這種案例。

案例2:后退棧(Back Stack)中的 Fragment

201642795642363.jpeg (900×450)
當(dāng)一個 fragment 從后退棧中返回時(Fragment A就是在這種情況),F(xiàn)ragment A 中視圖將會遵循下圖的 Fragment 生命周期被重新創(chuàng)造出來。

201642795709760.png (317×847)

你將會看到Fragment從后退棧中返回時,會回調(diào) onDestroyview 方法和 onCreateview 方法。不管怎樣,顯然在這種情況 onSaveInstanceState 方法沒有被調(diào)用。結(jié)果就是 UI 里的所有都沒有了,然后默認(rèn)按照 Layout XML 文件中定義的來重新創(chuàng)建。

不管怎樣,實現(xiàn)了內(nèi)在視圖狀態(tài)保存的視圖,如:帶有 android:freeezeText 的 EditText 或者 TextView,仍然能夠保存好視圖的狀態(tài),這是因為 Fragment 實現(xiàn)了對內(nèi)在視圖的狀態(tài)保存,但我們這些開發(fā)者不能抓住這些事件。我們唯一能做的就是在 onDestroyView 方法中手動保存實例狀態(tài)。

@Override
public void onSaveInstanceState(Bundle outState) {
  super.onSaveInstanceState(outState);
  // Save State Here
}
@Override
public void onDestroyView() {
  super.onDestroyView();
  // Save State Here
}

問題也隨之而來,onDestroyView 不提供任何幫助來保存實例狀態(tài)到一個 Bundle,那我們應(yīng)該把這些實例狀態(tài)保存到什么地方呢? 答案就是 Argument, 它會隨著 Fragment 一直保存著。

現(xiàn)在代碼如下所示:

Bundle savedState;
@Override
public void onActivityCreated(Bundle savedInstanceState) {
  super.onActivityCreated(savedInstanceState);
  // Restore State Here
  if (!restoreStateFromArguments()) {
   // First Time running, Initialize something here
  }
}
@Override
public void onSaveInstanceState(Bundle outState) {
  super.onSaveInstanceState(outState);
  // Save State Here
  saveStateToArguments();
}
@Override
public void onDestroyView() {
  super.onDestroyView();
  // Save State Here
  saveStateToArguments();
}
private void saveStateToArguments() {
  savedState = saveState();
  if (savedState != null) {
   Bundle b = getArguments();
   b.putBundle(“internalSavedViewState8954201239547”, savedState);
  }
}
private boolean restoreStateFromArguments() {
  Bundle b = getArguments();
  savedState = b.getBundle(“internalSavedViewState8954201239547”);
  if (savedState != null) {
   restoreState();
   return true;
  }
  return false;
}
/////////////////////////////////
// Restore Instance State Here
/////////////////////////////////
private void restoreState() {
  if (savedState != null) {
   // For Example
   //tv1.setText(savedState.getString(“text”));
  }
}
//////////////////////////////
// Save Instance State Here
//////////////////////////////
private Bundle saveState() {
  Bundle state = new Bundle();
  // For Example
  //state.putString(“text”, tv1.getText().toString());
  return state;
}

你能夠容易地在 saveState 保存你的 fragment 的狀態(tài),在 restoreState 恢復(fù)狀態(tài)?,F(xiàn)在已經(jīng)看起來好多了不少。我們已經(jīng)快結(jié)束了,但是還有一種怪異的情況。

案例3:在后退棧中超過一個 fragment 時,旋轉(zhuǎn)屏幕兩次

201642795821161.jpeg (1118×282)

當(dāng)你旋轉(zhuǎn)屏幕一次,onSaveInstanceState 會被回調(diào),正如我們所期待的,UI 的狀態(tài)會被保存。但是當(dāng)你旋轉(zhuǎn)屏幕超過一次,上述的代碼可能導(dǎo)致應(yīng)用的崩潰。原因就是盡管當(dāng)你旋轉(zhuǎn)屏幕時, onSaveInstanceState 方法被調(diào)用,但是在后退棧中的 fragment 會完全銷毀視圖,直到你瀏覽返回到原來那個 fragment 才會重新創(chuàng)建。因此,你再次旋轉(zhuǎn)屏幕,就沒有視圖來保存狀態(tài)。當(dāng)你試圖訪問那些不存在的視圖,saveState() 將會導(dǎo)致 NullPointerException,從而使應(yīng)用崩潰。

方法就是檢查在 fragment 中視圖是否存在。如果存在那就保存,如果不存在,那就在 Argument 中 savedState 不需要保存,然后返回時保存。或者我們甚至不需要做任何事,因為在Argument 中已經(jīng)做好了。

private void saveStateToArguments() {
  if (getView() != null)
   savedState = saveState();
  if (savedState != null) {
   Bundle b = getArguments();
   b.putBundle(“savedState”, savedState);
  }
}

哈,現(xiàn)在全都解決了!

Fragment 最終模版
如下就是我現(xiàn)在用于我工作中的 fragment 模版。

import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

import com.inthecheesefactory.thecheeselibrary.R;

/**
 *Created by nuuneoi on 11/16/2014.
 */
public class StatedFragment extends Fragment {

  Bundle savedState;

  public StatedFragment() {
    super();
  }

  @Override
  public void onActivityCreated(Bundle savedInstanceState) {
    super.onActivityCreated(savedInstanceState);
    // Restore State Here
    if (!restoreStateFromArguments()) {
      // First Time, Initialize something here
      onFirstTimeLaunched();
    }
  }

  protected void onFirstTimeLaunched() {

  }

  @Override
  public void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);
    // Save State Here
    saveStateToArguments();
  }

  @Override
  public void onDestroyView() {
    super.onDestroyView();
    // Save State Here
    saveStateToArguments();
  }

  ////////////////////
  // Don't Touch !!
  ////////////////////

  private void saveStateToArguments() {
    if (getView() != null)
      savedState = saveState();
    if (savedState != null) {
      Bundle b = getArguments();
      b.putBundle("internalSavedViewState8954201239547", savedState);
    }
  }

  ////////////////////
  // Don't Touch !!
  ////////////////////

  private boolean restoreStateFromArguments() {
    Bundle b = getArguments();
    savedState = b.getBundle("internalSavedViewState8954201239547");
    if (savedState != null) {
      restoreState();
      return true;
    }
    return false;
  }

  /////////////////////////////////
  // Restore Instance State Here
  /////////////////////////////////

  private void restoreState() {
    if (savedState != null) {
      // For Example
      //tv1.setText(savedState.getString("text"));
      onRestoreState(savedState);
    }
  }

  protected void onRestoreState(Bundle savedInstanceState) {

  }

  //////////////////////////////
  // Save Instance State Here
  //////////////////////////////

  private Bundle saveState() {
    Bundle state = new Bundle();
    // For Example
    //state.putString("text", tv1.getText().toString());
    onSaveState(state);
    return state;
  }

  protected void onSaveState(Bundle outState) {

  }
}

如果你使用這個模版,僅僅只需簡單地繼承這個類StatedFragment,然后在 onSaveState() 中保存事物,在 onRestoreState() 中恢復(fù)它們。上述代碼就會為你做好剩下的工作,我相信這已經(jīng)覆蓋了我已知的可能情況。

setRetainInstance 能夠幫助開發(fā)者在布局改變時(如:屏幕旋轉(zhuǎn))處理成員變量 而你可能注意到我沒有設(shè)置 setRetaionInstance 為 true。請記住,這就是我的目的,因為setRetainInstance(true)并沒有覆蓋全部的情況。最主要的原因是你不能一次又一次地保存那些經(jīng)常背使用的嵌套 fragment 。所以我建議就是不要保存實例,除非你100%確定這個 fragment 不會用于嵌套。

用法:
好消息。這個博客講述的 StateFragment 現(xiàn)在加入了一個非常容易使用的庫,現(xiàn)在已經(jīng)在 jcenter 上發(fā)布了?,F(xiàn)在你可以簡單地在你工程的 build.gradle 文件中加上一個依賴。如下所示:

dependencies {
  compile 'com.inthecheesefactory.thecheeselibrary:stated-fragment-support-v4:0.9.1'
}

繼承 StateFragment ,然后在 onSaveState(Bundle outState) 中保存狀態(tài),在 onRestoreState(Bundle saveInstanceState)中恢復(fù)狀態(tài)。如果你想在 fragment 第一次啟動時做點什么的話,你也可以覆蓋 onFirstTimeLaunched() 方法(在之后不會被調(diào)用)。

public class MainFragment extends StatedFragment {

  ...

  /**
   * Save Fragment's State here
   */
  @Override
  protected void onSaveState(Bundle outState) {
    super.onSaveState(outState);
    // For example:
    //outState.putString("text", tvSample.getText().toString());
  }

  /**
   * Restore Fragment's State here
   */
  @Override
  protected void onRestoreState(Bundle savedInstanceState) {
    super.onRestoreState(savedInstanceState);
    // For example:
    //tvSample.setText(savedInstanceState.getString("text"));
  }

  ...

}

End

最后,不要忽略狀態(tài)保存的問題,在內(nèi)存不足或者系統(tǒng)限制比較苛刻的機(jī)器上面,都有可能出現(xiàn)Fragment或Activity被回收,比如經(jīng)常出現(xiàn)拍照之后返回App,但App里面的數(shù)據(jù)被清空了,更常見的就是旋轉(zhuǎn)屏幕,所以要保存好自己需要的數(shù)據(jù)。

相關(guān)文章

  • Android性能優(yōu)化之圖片大小,尺寸壓縮綜合解決方案

    Android性能優(yōu)化之圖片大小,尺寸壓縮綜合解決方案

    隨著Android手機(jī)的越來越先進(jìn),給我們開發(fā)者而言傳遞的圖片也是越來越大,這個時候我們可以對一些沒有必要原圖展示的圖片進(jìn)行壓縮,這篇文章主要給大家介紹了關(guān)于Android性能優(yōu)化之圖片大小,尺寸壓縮的綜合解決方案,需要的朋友可以參考下
    2022-04-04
  • Kotlin?協(xié)程的取消機(jī)制詳細(xì)解讀

    Kotlin?協(xié)程的取消機(jī)制詳細(xì)解讀

    這篇文章主要為大家介紹了Kotlin?協(xié)程的取消機(jī)制詳細(xì)解讀,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-10-10
  • Android View的事件分發(fā)機(jī)制深入分析講解

    Android View的事件分發(fā)機(jī)制深入分析講解

    事件分發(fā)從手指觸摸屏幕開始,即產(chǎn)生了觸摸信息,被底層系統(tǒng)捕獲后會傳遞給Android的輸入系統(tǒng)服務(wù)IMS,通過Binder把消息發(fā)送到activity,activity會通過phoneWindow、DecorView最終發(fā)送給ViewGroup。這里就直接分析ViewGroup的事件分發(fā)
    2023-01-01
  • Android仿微信實現(xiàn)評論功能

    Android仿微信實現(xiàn)評論功能

    這篇文章主要為大家詳細(xì)介紹了Android仿微信實現(xiàn)評論功能,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-11-11
  • Android ListView數(shù)據(jù)綁定顯示的三種解決方法

    Android ListView數(shù)據(jù)綁定顯示的三種解決方法

    本篇文章小編為大家介紹,Android ListView數(shù)據(jù)綁定顯示的三種解決方法。需要的朋友參考下
    2013-04-04
  • Android TagCloudView云標(biāo)簽的使用方法

    Android TagCloudView云標(biāo)簽的使用方法

    這篇文章主要為大家詳細(xì)介紹了Android TagCloudView云標(biāo)簽的使用方法,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-05-05
  • Android自定義Dialog原理實例解析

    Android自定義Dialog原理實例解析

    這篇文章主要介紹了Android自定義Dialog原理實例解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-07-07
  • Android RecyclerView的焦點記憶封裝

    Android RecyclerView的焦點記憶封裝

    這篇文章主要介紹了Android RecyclerView的焦點記憶封裝,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-04-04
  • Android 開機(jī)自啟動Service實現(xiàn)詳解

    Android 開機(jī)自啟動Service實現(xiàn)詳解

    這篇文章主要為大家介紹了Android 開機(jī)自啟動Service實現(xiàn)詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-06-06
  • 從源碼編譯Android系統(tǒng)的Java類庫和JNI動態(tài)庫的方法

    從源碼編譯Android系統(tǒng)的Java類庫和JNI動態(tài)庫的方法

    這篇文章主要介紹了從源碼編譯Android系統(tǒng)的Java類庫和JNI動態(tài)庫的方法,例子基于Linux系統(tǒng)環(huán)境下來講,需要的朋友可以參考下
    2016-02-02

最新評論

江山市| 绍兴县| 新津县| 桃园市| 出国| 长白| 罗山县| 彭水| 确山县| 苍溪县| 宣恩县| 馆陶县| 襄城县| 申扎县| 密山市| 故城县| 郑州市| 咸宁市| 名山县| 莱芜市| 南召县| 新龙县| 林甸县| 丰都县| 大关县| 台北县| 子长县| 德令哈市| 平凉市| 视频| 申扎县| 浦江县| 汕尾市| 乌兰浩特市| 大英县| 高雄县| 江口县| 莱州市| 安康市| 贡山| 大冶市|