美文网首页
savedInstanceState

savedInstanceState

作者: 最美下雨天 | 来源:发表于2018-07-11 11:42 被阅读19次

    1、protected void onCreate(@Nullable Bundle savedInstanceState)
    这个savedInstanceState值什么时候会保存呢?系统异常退出时还是自己退出?需不需要手动保存

    官方介绍:https://developer.android.com/training/basics/activity-lifecycle/recreating?hl=zh-cn
    如果用户按了返回键或者说手动调用finish()销毁了Activity,这种情况我们不用管。
    这些情况需要考虑(有些设备配置可能会在运行时发生变化):
    https://developer.android.com/guide/topics/resources/runtime-changes?hl=zh-cn

    • 如果我们按了home键退到了后台或者说跳转到了其他Activity,这时候如果 Activity 长期未使用,或者前台 Activity 需要更多资源以致系统必须关闭后台进程恢复内存。
    • 旋转屏幕导致Activity重建

    针对上述情况,默认情况下,系统会使用 Bundle实例状态保存您的 Activity 布局(比如,输入到 EditText对象中的文本值)中有关每个 View 对象的信息。 这样,如果您的 Activity 实例被销毁并重新创建,布局状态便恢复为其先前的状态,且您无需代码。 但是,您的 Activity 可能具有您要恢复的更多状态信息,比如跟踪用户在 Activity 中进度的成员变量。

    要保存有关 Activity 状态的其他数据,您必须替代 onSaveInstanceState() 回调方法。当用户要离开 Activity 并在 Activity 意外销毁时向其传递将保存的 Bundle 对象时,系统会调用此方法。 如果系统必须稍后重新创建 Activity 实例,它会将相同的 Bundle 对象同时传递给 onRestoreInstanceState() 和 onCreate()方法。

    image.png
    保存 Activity 状态

    当您的 Activity 开始停止时,系统会调用 onSaveInstanceState() 以便您的 Activity 可以保存带有键值对集合的状态信息。 此方法的默认实现保存有关 Activity 视图层次的状态信息,例如 EditText小部件中的文本或ListView 的滚动位置。

    要保存 Activity 的更多状态信息,您必须实现 onSaveInstanceState()并将键值对添加至 Bundle对象。 例如:

    static final String STATE_SCORE = "playerScore";
    static final String STATE_LEVEL = "playerLevel";
    ...
    
    @Override
    public void onSaveInstanceState(Bundle savedInstanceState) {
        // Save the user's current game state
        savedInstanceState.putInt(STATE_SCORE, mCurrentScore);
        savedInstanceState.putInt(STATE_LEVEL, mCurrentLevel);
    
        // Always call the superclass so it can save the view hierarchy state
        super.onSaveInstanceState(savedInstanceState);
    }
    
    恢复 Activity 状态

    在恢复数据时,有两个地方可以恢复,第一个是onCreate()方法,第二个是onRestoreInstanceState()方法,但是需要判断null

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState); // Always call the superclass first
    
        // Check whether we're recreating a previously destroyed instance
        if (savedInstanceState != null) {
            // Restore value of members from saved state
            mCurrentScore = savedInstanceState.getInt(STATE_SCORE);
            mCurrentLevel = savedInstanceState.getInt(STATE_LEVEL);
        } else {
            // Probably initialize members with default values for a new instance
        }
        ...
    }
    

    第二个就无需判断null

    public void onRestoreInstanceState(Bundle savedInstanceState) {
        // Always call the superclass so it can restore the view hierarchy
        super.onRestoreInstanceState(savedInstanceState);
    
        // Restore state members from saved instance
        mCurrentScore = savedInstanceState.getInt(STATE_SCORE);
        mCurrentLevel = savedInstanceState.getInt(STATE_LEVEL);
    }
    

    如果重启 Activity 需要恢复大量数据,比如:重新建立网络连接或执行其他密集操作,那么因配置变更而引起的完全重启可能会给用户留下应用运行缓慢的体验

    有些设备配置可能会在运行时发生变化(例如屏幕方向、键盘可用性及语言)。 发生这种变化时,Android 会重启正在运行的 Activity(先后调用 onDestroy() 和 onCreate(),重启行为旨在通过利用与新设备配置匹配的备用资源自动重新加载您的应用,来帮助它适应新配置。

    此外,依靠系统通过onSaveInstanceState() 回调为您保存的 Bundle,可能无法完全恢复 Activity 状态,因为它并非设计用于携带大型对象(例如位图),而且其中的数据必须先序列化,再进行反序列化,这可能会消耗大量内存并使得配置变更速度缓慢。 在这种情况下,如果 Activity 因配置变更而重启,则可通过保留 Fragment 来减轻重新初始化 Activity 的负担。此片段可能包含对您要保留的有状态对象的引用。

    package com.example.huozhenpeng.myapplication;
    
    import android.os.Bundle;
    import android.support.v4.app.FragmentManager;
    import android.support.v7.app.AppCompatActivity;
    import android.util.Log;
    
    /**
     * 作者 huozhenpeng
     * 日期 2018/7/11
     * 邮箱 huohacker@sina.com
     */
    
    public class SecondActivity extends AppCompatActivity {
    
        private RetainedFragment dataFragment;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_second);
    
            // find the retained fragment on activity restarts
            FragmentManager fm = getSupportFragmentManager();
    
            dataFragment = (RetainedFragment) fm.findFragmentByTag("data");
    
            // create the fragment and data the first time
            if (dataFragment == null) {
                // add the fragment
                dataFragment = new RetainedFragment();
                fm.beginTransaction().add(dataFragment,"data").commit();
            }
    
            // the data is available in dataFragment.getData()
            //恢复复杂数据
            MyDataObject myDataObject=dataFragment.getData();
            if(myDataObject!=null)
            {
                Log.e("abc",myDataObject.getName());
            }
    
        }
    
        @Override
        protected void onStop() {
            super.onStop();
            Log.e("abc","stop");
        }
    
        @Override
        protected void onDestroy() {
            super.onDestroy();
            Log.e("abc","destroy");
            // store the data in the fragment
            //保存复杂数据
            dataFragment.setData(new MyDataObject("复杂数据"));
        }
    
        @Override
        protected void onSaveInstanceState(Bundle outState) {
            super.onSaveInstanceState(outState);
            Log.e("abc","onSaveInstanceState");
        }
    
    
    
        @Override
        protected void onRestoreInstanceState(Bundle savedInstanceState) {
            super.onRestoreInstanceState(savedInstanceState);
            Log.e("abc","onRestoreInstanceState");
        }
    }
    
    
    package com.example.huozhenpeng.myapplication;
    
    import android.os.Bundle;
    import android.support.v4.app.Fragment;
    
    public class RetainedFragment extends Fragment {
    
        // data object we want to retain
        private MyDataObject data;
    
        // this method is only called once for this fragment
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            // retain this fragment
            setRetainInstance(true);
        }
    
        public void setData(MyDataObject data) {
            this.data = data;
        }
    
        public MyDataObject getData() {
            return data;
        }
    }
    
    package com.example.huozhenpeng.myapplication;
    
    /**
     * 作者 huozhenpeng
     * 日期 2018/7/11
     * 邮箱 huohacker@sina.com
     */
    
    public class MyDataObject {
    
        public MyDataObject(String name)
        {
            this.name=name;
        }
    
        private String name;
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    }
    
    

    注意:尽管您可以存储任何对象,但是切勿传递与 Activity 绑定的对象,例如,Drawable、Adapter、View或其他任何与 Context 关联的对象。否则,它将泄漏原始 Activity 实例的所有视图和资源。 (泄漏资源意味着应用将继续持有这些资源,但是无法对其进行垃圾回收,因此可能会丢失大量内存。)

    当然,你也可以阻止Activity重启,请在清单文件中编辑相应的 <activity>元素,以包含 android:configChanges属性以及代表要处理的配置的值。android:configChanges属性的文档中列出了该属性的可能值(最常用的值包括 "orientation""keyboardHidden",分别用于避免因屏幕方向和可用键盘改变而导致重启)。您可以在该属性中声明多个配置值,方法是用管道 | 字符分隔这些配置值。

    例如,以下清单文件代码声明的 Activity 可同时处理屏幕方向变更和键盘可用性变更:

    <activity android:name=".MyActivity"
              android:configChanges="orientation|keyboardHidden| screenSize"
              android:label="@string/app_name">
    

    现在,当其中一个配置发生变化时,MyActivity 不会重启。相反,MyActivity 会收到对 onConfigurationChanged()的调用。

    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
    
        // Checks the orientation of the screen
        if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
            Toast.makeText(this, "landscape", Toast.LENGTH_SHORT).show();
        } else if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT){
            Toast.makeText(this, "portrait", Toast.LENGTH_SHORT).show();
        }
    }
    

    相关文章

      网友评论

          本文标题:savedInstanceState

          本文链接:https://www.haomeiwen.com/subject/mfvzuftx.html