zoukankan      html  css  js  c++  java
  • 【转】 Pro Android学习笔记(五六):配置变化

    目录(?)[-]

    1. Activity的destorycreate过程
    2. Fragment的destorycreate过程
      1. onSaveInstanceState
      2. saveFragmentInstanceState
      3. onRetainInstance

    横屏竖屏的切换就是最为常见的配置变化,我们在Pro Android学习笔记(四一):Fragment(6):数据保留中讨论过。 配置变化还有设备连接了dock,改变语言等,在资源res/中,不同的配置有不同的后缀来进行最佳匹配,具体见Pro Android学习笔记(四):了解Android资源(下)的资源和配置的变更 ,我们从中可以看到Android检测哪些配置变化。

    当配置变化时,当前的activity被destroy,并新re-created一个activity对象,我们要确保用户体验的无缝切换。我们应该尽量避免re-create的时间,减少activity处理的非UI部分。在配置变化是activity被destroy,但是application仍然存在,后台线程,数据库、content provider也存在,因此尽可能将数据和业务逻辑放在activity之外。

    Activity的destory/create过程

    配置变化过程中,Activity经历destroy,重新create的过程,有三个回调函数需要关注。

    onSaveInstanceState(Bundle outState):当检测到配置变化时会触发此回调函数,在activity的onStop()之前被调用,在此通过Bundle保存数据,并传递到新创建activity的onCreate(Bundle savedInstanceState)onRestoreInstanceState(Bundle savedInstanceState)的参数中。对于带有android:id的view,系统在onSaveInstanceState()中或自动存储用户输入的内容,并在重建时恢复。因此,如果我们需要重写,要记住调用super.onSaveInstanceState(); 通过bundle保存数据,例如整数使用putInt()方法,对于组合对象,可以采用putParcelable()

    onCreate()和onRestoreInstanceState()都可以通过bundle获取信息。一般会在onCreate()中处理,因为那里进行UI初始化的处理。但是有时我们会extends activity,这是在onRestoreInstanceState()中处理有时会更为简单。相关的执行顺序为onCreate() –>onStart() –>onRestoreInstanceState() –> onResume()。

    如果我们通过bundle进行数据保留,要注意,这种情况下,旧的activity是不能进行垃圾回收的,存在内存泄漏的风险,因此我们应当避免将activity上下文相关的Drawables、Views、Adapters等对象放入bundle中。如果实现需要,我们可以将之放在activity之外,或者使用某些id索引(int这类不是保持对象,而是赋值)。

    Fragment的destory/create过程

    onSaveInstanceState():

    Fragment和activity一样,可以通过onSaveInstanceState()进行数据保存,可以通过onInflate()、onCreate()、onCreateView()和onActivityCreate()进行获取。Android只保证在onDestroy()之前调用onSaveInstanceState(),不保证具体的执行顺序,因此有可能在调用onSaveInstanceState()时,相关的view容器已经无效,也就是,不应该在onSaveInstanceState()中处理view的数据。有例如,如果fragment在back stack,由于不可视,没有view(即为null),这并非异常,在代码中需要注意。同样,不应将fragment重创建后已不存在的对象进行保留,bundle携带的数据应尽可能地少,减少内存泄漏的风险。

    saveFragmentInstanceState():

    如果确实需要进行view的处理,可以通过fragment管理器主导要求触发onSaveInstanceState(),如下:

    getFragmentManager().saveFragmentInstanceState(this);

    saveFragmentInstanceState()将返回Fragment.SavedState对象,这state对象中包含fragment的状态(含有在onSaveInstanceState中保存的bundle),通过setInitialSavedState()可以在新的fragment恢复。我们利用Dialog中的提示框的例子,对例子进行少许修改,实现在下次弹出提示框时,能保留上次的输入值。

    public class PromptDialogFragment extends DialogFragment implements OnClickListener{ 
        … … 
        private static Fragment.SavedState fgState = null;  //可以保存在Application的某个对象,为了示范方便,本例子采用静态函数 
         
        public static PromptDialogFragment newInstance(String prompt){ 
            PromptDialogFragment pdf = new PromptDialogFragment();
            pdf.setInitialSavedState(fgState);  //获取保存的状态  
            ... ...  
            return pdf; 
        }  
         
        @Override //如果fgState非null,那么就可以从得到Bundle数据。在原例子中,新弹框是新建的dialog fragment,和原对话框无关,也不属于配置改变,因此bundle为null。在新例子中,由于我们保存了上一次对话框的state,并在实例创建时恢复,因此可以获取原对话框的state,包括当中的bundle
        public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 
            ... ... 
            if(savedInstanceState != null){ 
                CharSequence text = savedInstanceState.getCharSequence("input"); 
                et.setText(text == null ? "" : text); 
            } 
            //将原来dismiss的button改为触发信息保存 
            Button dismissBtn = (Button)v.findViewById(R.id.button_dismiss); 
            dismissBtn.setOnClickListener(this); 
            dismissBtn.setText("保存信息");   
            ...... 
        }  
         
        @Override  
        public void onSaveInstanceState(Bundle outState) { 
            showInfo("onSaveInstanceState() is called"); 
            outState.putCharSequence("input", et.getText()); 
            super.onSaveInstanceState(outState); 
        } 

        @Override 
        public void onClick(View v) {  
            //saveFragmentInstanceState()将触发onSaveInstanceState()回调函数,进行信息保存,并将保存内容存放在fgState对象中
            switch(v.getId()){ 
            case R.id.button_dismiss:  //新例子为“信息保存”触发按钮
                fgState = getFragmentManager().saveFragmentInstanceState(this);
                break;  
            ... ... 
            } 
        }  

    }

    onRetainInstance():

    通过onRetainInstatnce(true),当activity被destroy和re-created时,fragment的onDestroy()并不会被调用,说明fragment对象仍然存在于app中,在新activity创建时,fragment对象将attach到新的activity中,这个过程无需调用onCreate(),因为并重新创新fragment。我们在原对话框的例子进行测试,在onCreate()中加入onRetainInstatnce(true),进行横竖屏切换,状态跟踪如下。

    相关链接: 我的Android开发相关文章

  • 相关阅读:
    array_flip
    qy Undefied index报错
    strip_tag
    query使用
    tp5 sql 大于小于
    OfficeTools.OnlineEditWord
    OCX控件打包成CAB并实现数字签名过程
    使用css技术代替传统的frame技术
    delphi常用函数和方法
    js正则表达使用实例
  • 原文地址:https://www.cnblogs.com/blongfree/p/5048017.html
Copyright © 2011-2022 走看看