设计模式 -- 备忘录模式
2015-12-26 23:40
399 查看
定义:
记忆一个对象的内部状态,为了允许用户取消不确定或者错误的操作,能够恢复到以前的状态。
优缺点:
优点:
1,提供可恢复机制,能够让用户恢复到历史某个状态。
2,封装细节的操作。
缺点:
貌似犯了设计模式的通病,就是类的数量增加,消耗系统资源和性能。
在android源码中的使用:
activity源码查看:
http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/5.1.1_r1/android/app/Activity.java#Activity.onSaveInstanceState%28android.os.Bundle%29
activity状态保存:onsaveInstanceState()和onRestoreInstanceState().
onSaveInstanceState()里面:
1,存储窗口的视图树状态。
2,存储fragment的状态。
3,调用activity的activityLifecycleCallbacks的onSaveInstance函数进行状态存储。
如下是2.3的activity里面onSaveInstanceState里面的方法,保存存储窗口的视图状态。
mContentParent.saveHierarchyState(states):
会去调用 dispatchSaveInstanceState(container)方法:看这个方法里面实现:
如无id,不保存状态,否则将状态存储在container里面。
存储信息的bundle存储在哪里?
onsaveInstanceState是在activity销毁之前,onstop之前进行的。
ActivityThread的performStopActivity里面通过调用callCallActivityonSaveInstanceState()来执行onsaveInstance
performStopActivityInner(r, null, false, saveState):
callCallActivityOnSaveInstanceState:
上面是保存状态,那么恢复状态呢?
当activity重新启动的时候,会去查询activityClientRecord,如果存在状态信息,就会调用onRestoreInstanceState()
代码可点击查看:http://grepcode.com/file_/repo1.maven.org/maven2/org.robolectric/android-all/5.0.0_r2-robolectric-1/android/app/ActivityThread.java/?v=source
Activity负责存储,恢复UI状态,也就是说负责存储备忘录,不对备忘录信息进行任何操作,只是传递给其他对象;
activity,View,ViewGroup存储对象的状态,创建备忘录,可以记录,恢复备忘录状态;
Bundle存储activity,View,ViewGroup的UI状态,存储备忘录状态。
2015年12月27日23:08:44更新
写个java的例子出来,主要涉及到状态的保存和恢复,使用备忘录模式实现:
首先原始类,要备份的对象类:
备忘录类,比起上面的类,少了创建备份和设置备份数据的方法:
Caretaker类:负责存储备忘录,不对内容进行操作和访问,将备忘录传递给其他对象。
测试类Test.java:
运算结果:
其他博客看到的一篇文章,讲的有意思,可以去看看:http://www.blogjava.net/amigoxie/archive/2007/04/12/110031.html
记忆一个对象的内部状态,为了允许用户取消不确定或者错误的操作,能够恢复到以前的状态。
优缺点:
优点:
1,提供可恢复机制,能够让用户恢复到历史某个状态。
2,封装细节的操作。
缺点:
貌似犯了设计模式的通病,就是类的数量增加,消耗系统资源和性能。
在android源码中的使用:
activity源码查看:
http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/5.1.1_r1/android/app/Activity.java#Activity.onSaveInstanceState%28android.os.Bundle%29
activity状态保存:onsaveInstanceState()和onRestoreInstanceState().
onSaveInstanceState()里面:
1,存储窗口的视图树状态。
2,存储fragment的状态。
3,调用activity的activityLifecycleCallbacks的onSaveInstance函数进行状态存储。
如下是2.3的activity里面onSaveInstanceState里面的方法,保存存储窗口的视图状态。
protected void More ...onSaveInstanceState(Bundle outState) { 1087 outState.putBundle(WINDOW_HIERARCHY_TAG, mWindow.saveHierarchyState()); 1088 }
saveHierarchyState在window类里面是个抽象的方法,因此去实现类PhoneWindow去查看 强调下这里这个方法的作用:存储UI,actionBar等相关view状态。 : 代码可查看:http://grepcode.com/file/repo1.maven.org/maven2/org.robolectric/android-all/5.0.0_r2-robolectric-1/com/android/internal/policy/impl/PhoneWindow.java#PhoneWindow.saveHierarchyState%28%29
@Override public Bundle More ...saveHierarchyState() { Bundle outState = new Bundle(); if (mContentParent == null) { return outState; } SparseArray<Parcelable> states = new SparseArray<Parcelable>(); //存储整根树的结构 mContentParent.saveHierarchyState(states); //视图树结构放到outState中 outState.putSparseParcelableArray(VIEWS_TAG, states); // save the focused view id 保存获取焦点deview View focusedView = mContentParent.findFocus(); if (focusedView != null) { if (focusedView.getId() != View.NO_ID) { outState.putInt(FOCUSED_ID_TAG, focusedView.getId()); } else { if (false) { Log.d(TAG, "couldn't save which view has focus because the focused view " + focusedView + " has no id."); } } } // save the panels 存储整个面板状态 SparseArray<Parcelable> panelStates = new SparseArray<Parcelable>(); savePanelState(panelStates); if (panelStates.size() > 0) { outState.putSparseParcelableArray(PANELS_TAG, panelStates); } //存储actionBar状态 if (mDecorContentParent != null) { SparseArray<Parcelable> actionBarStates = new SparseArray<Parcelable>(); mDecorContentParent.saveToolbarHierarchyState(actionBarStates); outState.putSparseParcelableArray(ACTION_BAR_TAG, actionBarStates); } return outState; }
mContentParent.saveHierarchyState(states):
public void More ...saveHierarchyState(SparseArray<Parcelable> container) { dispatchSaveInstanceState(container); }
会去调用 dispatchSaveInstanceState(container)方法:看这个方法里面实现:
如无id,不保存状态,否则将状态存储在container里面。
protected void More ...dispatchSaveInstanceState(SparseArray<Parcelable> container) { if (mID != NO_ID && (mViewFlags & SAVE_DISABLED_MASK) == 0) { mPrivateFlags &= ~PFLAG_SAVE_STATE_CALLED; Parcelable state = onSaveInstanceState(); if ((mPrivateFlags & PFLAG_SAVE_STATE_CALLED) == 0) { throw new IllegalStateException( "Derived class did not call super.onSaveInstanceState()"); } if (state != null) { // Log.i("View", "Freezing #" + Integer.toHexString(mID) // + ": " + state); container.put(mID, state); } } }
存储信息的bundle存储在哪里?
onsaveInstanceState是在activity销毁之前,onstop之前进行的。
ActivityThread的performStopActivity里面通过调用callCallActivityonSaveInstanceState()来执行onsaveInstance
final void More ...performStopActivity(IBinder token, boolean saveState) { ActivityClientRecord r = mActivities.get(token); performStopActivityInner(r, null, false, saveState); }
performStopActivityInner(r, null, false, saveState):
private void More ...performStopActivityInner(ActivityClientRecord r, StopInfo info, boolean keepShown, boolean saveState) { if (localLOGV) Slog.v(TAG, "Performing stop of " + r); if (r != null) { if (!keepShown && r.stopped) { if (r.activity.mFinished) { // If we are finishing, we won't call onResume() in certain // cases. So here we likewise don't want to call onStop() // if the activity isn't resumed. return; } RuntimeException e = new RuntimeException( "Performing stop of activity that is not resumed: " + r.intent.getComponent().toShortString()); Slog.e(TAG, e.getMessage(), e); } if (info != null) { try { // First create a thumbnail for the activity... // For now, don't create the thumbnail here; we are // doing that by doing a screen snapshot. info.description = r.activity.onCreateDescription(); } catch (Exception e) { if (!mInstrumentation.onException(r.activity, e)) { throw new RuntimeException( "Unable to save state of activity " + r.intent.getComponent().toShortString() + ": " + e.toString(), e); } } } // Next have the activity save its current state and managed dialogs... if (!r.activity.mFinished && saveState) { if (r.state == null) { //activity finish 且保存状态,调用activity的onsaveInstanceState方法。 callCallActivityOnSaveInstanceState(r); } } if (!keepShown) { try { //activity不可见,调用stop方法 // Now we are idle. r.activity.performStop(); } catch (Exception e) { if (!mInstrumentation.onException(r.activity, e)) { throw new RuntimeException( "Unable to stop activity " + r.intent.getComponent().toShortString() + ": " + e.toString(), e); } } r.stopped = true; } r.paused = true; } }
callCallActivityOnSaveInstanceState:
private void More ...callCallActivityOnSaveInstanceState(ActivityClientRecord r) { r.state = new Bundle(); r.state.setAllowFds(false); if (r.isPersistable()) { r.persistentState = new PersistableBundle(); mInstrumentation.callActivityOnSaveInstanceState(r.activity, r.state, r.persistentState); } else { mInstrumentation.callActivityOnSaveInstanceState(r.activity, r.state); } }
上面是保存状态,那么恢复状态呢?
当activity重新启动的时候,会去查询activityClientRecord,如果存在状态信息,就会调用onRestoreInstanceState()
代码可点击查看:http://grepcode.com/file_/repo1.maven.org/maven2/org.robolectric/android-all/5.0.0_r2-robolectric-1/android/app/ActivityThread.java/?v=source
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) { // System.out.println("##### [" + System.currentTimeMillis() + "] ActivityThread.performLaunchActivity(" + r + ")"); ActivityInfo aInfo = r.activityInfo; if (r.packageInfo == null) { r.packageInfo = getPackageInfo(aInfo.applicationInfo, r.compatInfo, Context.CONTEXT_INCLUDE_CODE); } ComponentName component = r.intent.getComponent(); if (component == null) { component = r.intent.resolveActivity( mInitialApplication.getPackageManager()); r.intent.setComponent(component); } if (r.activityInfo.targetActivity != null) { component = new ComponentName(r.activityInfo.packageName, r.activityInfo.targetActivity); } Activity activity = null; try { java.lang.ClassLoader cl = r.packageInfo.getClassLoader(); activity = mInstrumentation.newActivity( cl, component.getClassName(), r.intent); StrictMode.incrementExpectedActivityCount(activity.getClass()); r.intent.setExtrasClassLoader(cl); r.intent.prepareToEnterProcess(); if (r.state != null) { r.state.setClassLoader(cl); } } catch (Exception e) { if (!mInstrumentation.onException(activity, e)) { throw new RuntimeException( "Unable to instantiate activity " + component + ": " + e.toString(), e); } } try { Application app = r.packageInfo.makeApplication(false, mInstrumentation); if (localLOGV) Slog.v(TAG, "Performing launch of " + r); if (localLOGV) Slog.v( TAG, r + ": app=" + app + ", appName=" + app.getPackageName() + ", pkg=" + r.packageInfo.getPackageName() + ", comp=" + r.intent.getComponent().toShortString() + ", dir=" + r.packageInfo.getAppDir()); if (activity != null) { Context appContext = createBaseContextForActivity(r, activity); CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager()); Configuration config = new Configuration(mCompatConfiguration); if (DEBUG_CONFIGURATION) Slog.v(TAG, "Launching activity " + r.activityInfo.name + " with config " + config); activity.attach(appContext, this, getInstrumentation(), r.token, r.ident, app, r.intent, r.activityInfo, title, r.parent, r.embeddedID, r.lastNonConfigurationInstances, config, r.voiceInteractor); if (customIntent != null) { activity.mIntent = customIntent; } r.lastNonConfigurationInstances = null; activity.mStartedActivity = false; int theme = r.activityInfo.getThemeResource(); if (theme != 0) { activity.setTheme(theme); } activity.mCalled = false; if (r.isPersistable()) { mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState); } else { mInstrumentation.callActivityOnCreate(activity, r.state); } if (!activity.mCalled) { throw new SuperNotCalledException( "Activity " + r.intent.getComponent().toShortString() + " did not call through to super.onCreate()"); } r.activity = activity; r.stopped = true; if (!r.activity.mFinished) { activity.performStart(); r.stopped = false; } //主要是这块的代码,判断state是否为null,不为null,保存了状态,调用onRestoreInstanceState函数恢复状态。 if (!r.activity.mFinished) { if (r.isPersistable()) { if (r.state != null || r.persistentState != null) { mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state, r.persistentState); } } else if (r.state != null) { mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state); } } if (!r.activity.mFinished) { activity.mCalled = false; if (r.isPersistable()) { mInstrumentation.callActivityOnPostCreate(activity, r.state, r.persistentState); } else { mInstrumentation.callActivityOnPostCreate(activity, r.state); } if (!activity.mCalled) { throw new SuperNotCalledException( "Activity " + r.intent.getComponent().toShortString() + " did not call through to super.onPostCreate()"); } } } r.paused = true; mActivities.put(r.token, r); } catch (SuperNotCalledException e) { throw e; } catch (Exception e) { if (!mInstrumentation.onException(activity, e)) { throw new RuntimeException( "Unable to start activity " + component + ": " + e.toString(), e); } } return activity; }
Activity负责存储,恢复UI状态,也就是说负责存储备忘录,不对备忘录信息进行任何操作,只是传递给其他对象;
activity,View,ViewGroup存储对象的状态,创建备忘录,可以记录,恢复备忘录状态;
Bundle存储activity,View,ViewGroup的UI状态,存储备忘录状态。
2015年12月27日23:08:44更新
写个java的例子出来,主要涉及到状态的保存和恢复,使用备忘录模式实现:
首先原始类,要备份的对象类:
package mementopattern; public class People { //姓名 private String name; //性别 private String sex; public People() { } public People(String name, String sex) { this.name = name; this.sex = sex; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getSex() { return sex; } public void setSex(String sex) { this.sex = sex; } public Memento createMemento() { return new Memento(name,sex); } public void setMemento(Memento memento) { this.name = memento.getName(); this.sex = memento.getSex(); } public void showPeople(){ System.out.println(toString()); } @Override public String toString() { return "People [name=" + name + ", sex=" + sex + "]"; } }
备忘录类,比起上面的类,少了创建备份和设置备份数据的方法:
public class Memento { // 姓名 private String name; // 性别 private String sex; public Memento(String name, String sex) { super(); this.name = name; this.sex = sex; } /** * @return 返回 name **/ public String getName() { return name; } /** * @param name 要设置的 name */ public void setName(String name) { this.name = name; } /** * @return 返回 sex **/ public String getSex() { return sex; } /** * @param sex 要设置的 sex */ public void setSex(String sex) { this.sex = sex; } @Override public String toString() { return "Memento [name=" + name + ", sex=" + sex + "]"; } }
Caretaker类:负责存储备忘录,不对内容进行操作和访问,将备忘录传递给其他对象。
public class Caretaker { private Memento memento; public Memento getMemento() { return memento; } public void setMemento(Memento memento) { this.memento = memento; } }
测试类Test.java:
package mementopattern; public class Test { public static void main(String[] args) { People per = new People("soyoungboy","男"); Caretaker caretaker = new Caretaker(); caretaker.setMemento(per.createMemento()); per.showPeople(); per.setName("caijj"); per.setSex("女"); per.showPeople(); per.setMemento(caretaker.getMemento()); per.showPeople(); } }
运算结果:
People [name=soyoungboy, sex=男] People [name=caijj, sex=女] People [name=soyoungboy, sex=男]
其他博客看到的一篇文章,讲的有意思,可以去看看:http://www.blogjava.net/amigoxie/archive/2007/04/12/110031.html
相关文章推荐
- 求最大回文子串的长度
- 山东省第四届蓝桥杯 ///标题: 马虎的算式//c/c++组
- 算法之美:动态规划
- Android面试题总结加强再加强版(四)
- Linux netstat命令详解
- 在eclipse中进行Struts2项目的配置
- 【懒程序员的日常】接口文档绝对是个混账!
- BeanUtils.populate的作用
- MySQL常用字符集
- 一身正气姥爷之幽默谈开博!
- linux service命令
- 本地通知
- MyBatis Generator 详解
- 【跟我学spring 4.0 】之第三节-bean的配置
- Fragment不同操作的生命周期
- lua中的closure(闭合函数)
- 简单c语言习题:矩阵求乘积
- fast-rcnn的例子执行和selective search中遇到的问题及解决(二)
- GreenDao 教程
- JavaScript中的对象及层级关系、常用函数