Activity/Fragment/Viewの状態保存/データ復旧
6399 ワード
Activity/Fragmentのライフサイクルについて
まず余談ですが、金曜日のテストでバグを出して、次のFragmentにジャンプして、前のfragmentに戻って、前のtextviewに対する操作がなくなりました.
そこで私はまたViewのlifecircleを見てみると、Activityとはやはり違います.彼はbackstackから前のfragmentを取り出してonCreateViewを歩きますが、inflateviewとbutterknifer bind viewはonCreateViewでやっています(これは正しいです.onCreateViewはviewに戻ります.公式ドキュメントではこのviewでこのfragmentのroot layoutを返します.onCreateでは、コンポーネントを初期化するために必要です).つまりviewは再構築されているので、view状態はすべて初期状態になっています.
最終的に私はこの業務問題を解決しました:onCreateViewのupdateの現在のfragmentのviewの方法に判断を加えて、uidataの中で相応のデータがあれば、textviewを更新します.
ActivityとFragmentのライフサイクルの違いを感じています.
また、onAttach(Activity activity)がapi 23以上でdeprecatedされていることに気づき、パラメータが変わりました:
/*
* onAttach(Context) is not called on pre API 23 versions of Android and onAttach(Activity) is deprecated
* Use onAttachToContext instead
*/
@TargetApi(23)
@Override
public void onAttach(Context context) {
super.onAttach(context);
onAttachToContext(context);
}
この新しい方法を上書きすると、gradleのtarget apiが23未満の場合、onAttachは呼び出されません(先週外部SDKにアクセスしたとき、彼らのsoはtargetApi 23以上をサポートしていなかったため、私たちのappはtargetApi 22に変更されました.これがリスクです).正しい方法はtargetApiをアップグレードするか、2つのonAttachを同時に書くことです.
Fragmentの状態保存について
私たちのグループのAppではUIdataの案を使っていますが、巧みだと思います.FragmentのonAttach()メソッド(また、onCreate()メソッドでもgetActivityをmActivityに付与)でmActivityのリカバリとmUIDataのリカバリを行いました:
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
this.mActivity = (CPActivity) activity;
this.mUIData = mActivity.mUIData;
}
これにより、getActivityによるonDetachによる空のポインタを回避できます.onDetachの後、getActivityはnullですから.しかしFragmentオブジェクトはGCによって回収されていないためmActivityは回収されていない.
また、ViewPager+Fragmentのようなデザインでは、viewpagerのデフォルトで3ページ目に滑ると、1ページ目のFragmentがonDestroyViewになり、このときに1ページ目に戻ってくると、多くのものが再構築されます.このような状況は状況によって異なり、リアルタイム性の高いappであれば、このようにするのは間違いない.リアルタイム性の低いappであれば、onCreateViewでネットワークデータが空であるか、rootViewが空であるか、空でなければネットワークを要求せず、リソース消費を避けることができます.
Activityの状態保存
私たちのActivityにはpublicのmUIdataがあり、onCreate()、onRestoreInstanceState()、onRestoreInstanceState()の場合、savedInstanceStateから保存/取り出します.
@Override
protected void onCreate(Bundle savedInstanceState) {
//
if (savedInstanceState == null) {
//initUIData ,
mUIData = initUIData();
} else {
// , set classLoader, , classLoader
savedInstanceState.setClassLoader(getClass().getClassLoader());
mUIData = (UIData) savedInstanceState.getSerializable(UIDATA);
}
super.onCreate(savedInstanceState);
imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
}
ActivityのFragment間のデータ通信
私はこの文章を見て、Handler、放送/EventBus、インタフェース、setArgumentなどの方法について言及しました.その中の最後のsetArgument方式はFragmentのデザイナーたちの初志で、私も前に簡単に分析したことがありますが、その利点はActivityの再構築時にデータを復元できることです.そのため、Fragmentは単例の使用をお勧めしません.それに比べて、私たちのグループのUIdata案はいいと思います.
Viewの状態保存
Activityだけでなく、
View
というクラスにもonSaveInstanceState
とonRestoreInstanceState(android.os.Parcelable)
というstateを保存する方法があります.複雑なview、例えばユーザーが埋め尽くしたフォームについて、ユーザーが画面を回転したら、データがなくなってはいけません.Viewには、Base class for derived classes that want to save and restore their own onSaveInstancesState()と解釈されるクラスがあります.私たちはカスタマイズしてViewのstateを保存します.
私たちのJDRViewでは、保存とリカバリ時にuidataに値を割り当てるために継承されています.parcelにuidataを追加してリカバリする必要があります.
public static class SavedState extends BaseSavedState {
/**
*
*/
private UIData mUIData;
public SavedState(Parcelable superState) {
super(superState);
}
private SavedState(Parcel in) {
super(in);
mUIData = (UIData) in.readSerializable();
}
@Override
public void writeToParcel(Parcel out, int flags) {
super.writeToParcel(out, flags);
out.writeSerializable(mUIData);
}
public static final Creator CREATOR = new Creator() {
public SavedState createFromParcel(Parcel in) {
return new SavedState(in);
}
public SavedState[] newArray(int size) {
return new SavedState[size];
}
};
}
JDRViewはどうやってデータを復元したのか思い出しました.JDRViewのコンストラクション関数JDRView()->init(){mUIdata=initUIIData();initUI();onRestoreSavedInstaceでupdateUI()を呼び出します.
Finance Viewを例にとると、
@Override
public UIData initUIData() {
InvestmentListData investmentListData = mStorageUtil.get(InvestmentListData.class);
if (investmentListData == null || investmentListData.fundCardInfo == null) {
investmentListData = new InvestmentListData();
investmentListData.fundCardInfo = createDefaultData();
}
return investmentListData;
}
私たちはmStorageUtilを使っています.SerializableのデータをJsonに変換して保存したSharedPreferencesに使います.コンストラクション関数の初期化とonRestoreSavedInstanceでは、mUIdataに値が割り当てられ、initUi/updateUiになります.ディスクからキャッシュデータをリカバリし、ビューを再構築したときにデータをリカバリするために使用されます.
MainSequenceFragment:
protected void updateCardListUI(CardSequenceList cardSequenceList) {
if (cardSequenceList == null) {
return;
}
List mCardList = cardSequenceList.tabStructureList;
if (needDraw(mCardList)) {
mCardView = CardViewManager.generateCardView(mActivity, mCardList);
addCardViewLayout();
}
for (int i = 0; i < mCardView.size(); i++) {
View cardView = mCardView.get(i);
if (cardView instanceof JDRView) {
//loadData cardId server ,onSuccess updateUI。
((JDRView) cardView).loadData(null);
}
}
}
cardIdはキャッシュ時に役立つ以外に、何の役に立ちますか.昔はページ名が伝わっていたようですが、今はcardIdに変更されました.
ref: http://www.jianshu.com/p/662c46cd3b5f http://blog.csdn.net/u012702547/article/details/47151001 http://www.bubuko.com/infodetail-828889.html