横坚屏切换时对数据的恢复

一. 强制开启屏幕旋转效果


        如果用户的手机没有开启重力感应器或者在AndroidManifest.xml中设置了android:screenOrientation,默认情况下,该Activity不会响应屏幕旋转事件。如果在这种情况下,依然希望Activity能响应屏幕旋转,则添加如下代码:

// 在activity的 onCreate 函数中添加

this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR);

二. 监听屏幕旋转


        当屏幕发生旋转(当手机的方向锁没有开启,并且没有强行设定屏幕显示方向),那么程序将会做以下几个步骤:

①在onPause()和onStop()之间调用当前的Activity的onSaveInstanceState(Bundle outState)方法去保存应用中的一些数据,你可以重写这个方法,当然onSaveInstanceState(Bundle outState)方法的调用是有一些条件的,条件在下面;

然后调用onDestroy()销毁当前的Activity;

③重新调用onCreate()方法去重新创建一个Activity,并且在onStart()和onResume方法之间调用onRestoreInstanceState()方法,有一点要记住onRestoreInstanceState()方法只会在屏幕旋转的时候调用;

         Activity的 onSaveInstanceState() 和 onRestoreInstanceState()并不是生命周期方法,它们不同于 onCreate()、onPause()等生命周期方法,它们并不一定会被触发。当应用遇到意外情况(如:内存不足、用户直接按Home键)由系统销毁一个Activity时,onSaveInstanceState(Bundle outState) 会被调用。但是当用户主动去销毁一个Activity时,例如在应用中按返回键,onSaveInstanceState()就不会被调用。因为在这种情况下,用户的行为决定了不需要保存Activity的状态。通常onSaveInstanceState()只适合用于保存一些临时性的状态,而onPause()适合用于数据的持久化保存。

        总而言之,onSaveInstanceState(Bundle outState)的调用遵循一个重要原则,即当系统“未经你许可”时销毁了你的activity,则onSaveInstanceState会被系统调用,这是系统的责任,因为它必须要提供一个机会让你保存你的数据(当然你不保存那就随便你了)。另外,onRestoreInstanceState(Bundle outState)的bundle参数也会传递到onCreate方法中,你也可以选择在onCreate方法中做数据还原。


三.onSaveInstanceState(Bundle outState)方法的默认实现


        如果我们没有覆写onSaveInstanceState(Bundle outState)方法, 此方法的默认实现会自动保存activity中的某些状态数据, 比如activity中各种UI控件的状态.。android应用框架中定义的几乎所有UI控件都恰当的实现了onSaveInstanceState(Bundle outState)方法,因此当activity被摧毁和重建时, 这些UI控件会自动保存和恢复以前的状态数据. 比如EditText控件会自动保存和恢复输入的数据,而CheckBox控件会自动保存和恢复选中状态.开发者只需要为这些控件指定一个唯一的ID(通过设置android:id属性即可), 剩余的事情就可以自动完成了.如果没有为控件指定ID, 则这个控件就不会进行自动的数据保存和恢复操作。

        由上所述, 如果我们需要覆写onSaveInstanceState()方法, 一般会在第一行代码中调用该方法的默认实现:super.onSaveInstanceState(Bundle outState)

案例:

 @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        //你的后续操作,下文有举例
    }

四.是否需要重写onSaveInstanceState(Bundle outState)方法


        如果需要保存额外的数据时(指的是UI控件的状态以外数据,比如TextView的text改变), 就需要覆写onSaveInstanceState(Bundle outState)方法。大家需要注意的是:onSaveInstanceState(Bundle outState)方法只适合保存瞬态数据, 比如UI控件的状态, 成员变量的值等,而不应该用来保存持久化数据,持久化数据应该当用户离开当前的activity时,在onPause()中保存(比如将数据保存到数据库或文件中)。说到这里,还要说一点的就是在onPause()中不适合用来保存比较费时的数据,所以这点要理解。(可以考虑另开线程,别阻塞UI线程。比如需要访问网络或需要耗费大量资源)

书写案例:

@Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        outState.putString("message", text.getText().toString());
       outState.putCharSequence("text", text.getText());
    }

@Override
    public void onRestoreInstanceState(Bundle savedInstanceState){
        super.onRestoreInstanceState(savedInstanceState);
        message = savedInstanceState.getString("message");
        text = savedInstanceState.getCharSequence("text");
 }

或者:

@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        if (savedInstanceState != null) {
            CharSequence text = savedInstanceState.getCharSequence("text");
            text.setText(charSequence);
        }
    }

五.须知

            在旋转屏幕时我们除了使用onSaveInstanceState(Bundle outState)外,还可以使用onRetainNonConfigurationInstance()和getLastNonConfigurationInstance()这两个方法来保存切换屏幕的状态。与onSaveInstanceState(Bundle outState) 不同的是,onRetainNonConfigurationInstance()和getLastNonConfigurationInstance() 方法主要用于屏幕之间的旋转操作时保存数据。

        onSaveInstanceState()和onRetainNonConfigurationInstance()都可以实现保存数据的功能,如果是两个同时使用时,执行顺序是哪个在先,哪个在后呢?根据Android官方网站上介绍,如果两个方法同时出现时,onSaveInstanceState()方法执行在先,而onRetainNonConfigurationInstance()方法执行在后。

        从设计的角度看,onRetainNonConfigurationInstance()并不是多余的函数。一般情况下,如果我们要保存的数据不太大,而且适合放在Bundle中,那么使用onSaveInstanceState()是比较合适的;如果要保存的数据不适合放在Bundle中(比如:一个socket)或是数据比较大(比如:一个Bitmap),那么这个时间我们就应该使用onRetainNonConfigurationInstance(),而且我们使用onRetainNonConfigurationInstance()可以保存任何类型的对象,像AsyncTask和SQLiteDatabse,我们都可以进行保存。这些类型的数据可能会被一个新的Activity实例所重新使用。所以onSaveInstanceState()和onRetainNonConfigurationInstance()在我们的程序中扮演的是不同的角色,需要在不同的时机下调用,用来处理不同类型的数据。

        不过呢,onRetainNonConfigurationInstance()在新版本的SDK中是一个过时的方法,我们可以用setRetainInstance(boolean)来代替onRetainNonConfigurationInstance(),在旧的平台中我们仍然可以使用onRetainNonConfigurationInstance()。如果是部分朋友不知道如何使用setRetainInstance(boolean)来保存自定义的对象数据,则可以使用onRetainCustomNonConfigurationInstance()来代表onRetainNonConfigurationInstance(),同时使用getLastCustomNonConfigurationInstance()代替getLastNonConfigurationInstance() 。

09-01 20:58:43.386 1649-1649/com.jxnu.duewang.day05 E/main: onCreate
09-01 20:58:43.610 1649-1649/com.jxnu.duewang.day05 E/main: onStart
09-01 20:58:43.611 1649-1649/com.jxnu.duewang.day05 E/main: onResume
09-01 20:58:51.789 1649-1649/com.jxnu.duewang.day05 E/main: onPause//开始转屏
09-01 20:58:51.791 1649-1649/com.jxnu.duewang.day05 E/main: onSaveInstanceState
09-01 20:58:51.791 1649-1649/com.jxnu.duewang.day05 E/main: onstop
09-01 20:58:51.791 1649-1649/com.jxnu.duewang.day05 E/main: onRetainCustomNonConfigurationInstance
09-01 20:58:51.791 1649-1649/com.jxnu.duewang.day05 E/main: ondestory
09-01 20:58:51.841 1649-1649/com.jxnu.duewang.day05 E/main: onCreate
09-01 20:58:51.897 1649-1649/com.jxnu.duewang.day05 E/main: onStart
09-01 20:58:51.897 1649-1649/com.jxnu.duewang.day05 E/main: getLastCustomNonConfigurationInstance
09-01 20:58:51.897 1649-1649/com.jxnu.duewang.day05 E/main: onRestoreInstanceState
09-01 20:58:51.897 1649-1649/com.jxnu.duewang.day05 E/main: onResume
案例:
 @Override
    public Object onRetainCustomNonConfigurationInstance() {
        Log.e(TAG,"onRetainCustomNonConfigurationInstance");
        CharSequence text = this.text.getText();
        return text;
    }

@Override//可以直接在onCreate中获取,写在这里只是一个示范
    public Object getLastCustomNonConfigurationInstance() {
        String str=super.getLastCustomNonConfigurationInstance().toString();
        return str;
    }

@Override
    protected void onRestoreInstanceState(Bundle savedInstanceState) {
        super.onRestoreInstanceState(savedInstanceState);
        text.setText((CharSequence) getLastCustomNonConfigurationInstance());
        Log.e(TAG,"onRestoreInstanceState");
    }

六.横屏竖屏的判断

//判定当前的屏幕是竖屏还是横屏
    public int ScreenOrient(Activity activity)
    {
        int orient = activity.getRequestedOrientation(); 
        if(orient != ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE && orient != ActivityInfo.SCREEN_ORIENTATION_PORTRAIT) {
            WindowManager windowManager = activity.getWindowManager();  
            Display display = windowManager.getDefaultDisplay();  
            int screenWidth  = display.getWidth();  
            int screenHeight = display.getHeight();  
            orient = screenWidth < screenHeight ?  ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE:ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
        }
        return orient;
    }

 @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //强行开启屏幕旋转效果
        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR);
        if(savedInstanceState == null){
            setContentView(R.layout.activity_orientation1);
        }
        if(savedInstanceState != null){
            //横屏
            if( ScreenOrient(this)==ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE  )
                setContentView(R.layout.activity_orientation1);
            //竖屏
            if( ScreenOrient(this)==ActivityInfo.SCREEN_ORIENTATION_PORTRAIT  )
                setContentView(R.layout.activity_orientation2);  
        }
    }

本文为参考别人的文献自己通过实验总结出来的,如果有误,欢迎大家指正

你可能感兴趣的:(android,屏幕旋转,Activity的重建,恢复现场,数据保护)