喜新不厌旧之 —— Activity

  • 关于生命周期

1、三个不常用生命周期:onContentChanged、onPostCreate、onPostResume

七大常用基本生命周期已经是老生常谈的了,就不再赘述。这里说三个不常用的方法:

onContentChanged:在Activity的setContentView()或addContentView()方法执行完毕时就会调用该方法。可以看下源码:

class AppCompatDelegateImplV7 extends AppCompatDelegateImplBase
        implements MenuBuilder.Callback, LayoutInflaterFactory {

    .
    .
    .

    @Override
    public void setContentView(View v, ViewGroup.LayoutParams lp) {
        ensureSubDecor();
        ViewGroup contentParent = (ViewGroup) mSubDecor.findViewById(android.R.id.content);
        contentParent.removeAllViews();
        contentParent.addView(v, lp);
        mOriginalWindowCallback.onContentChanged();
    }

    @Override
    public void addContentView(View v, ViewGroup.LayoutParams lp) {
        ensureSubDecor();
        ViewGroup contentParent = (ViewGroup) mSubDecor.findViewById(android.R.id.content);
        contentParent.addView(v, lp);
        mOriginalWindowCallback.onContentChanged();
    }

可以看到,在setContentView()和addContentView()方法最后都调用了onContentChanged()方法。

onPostCreate、onPostResume:这两个方法在onCreate方法和onResume方法彻底执行完毕后调用,经测试onPostCreate调用时机在onStart方法之后onResume方法之前。注意:onPostCreate方法有两个重载方法,只有savedInstanceState参数的方法会被调用,另一个两个参数的方法不会调用。在onPostCreate、onPostResume两个方法中获取控件的宽高仍然是0。

2、弹出Dialog,生命周期如何执行

不要查阅资料,直接回答——第一反应是不是执行activity的onPause方法?

是的那你就错了,单纯的创建dialog并弹出,不会执行activity的任何生命周期。如果是跳转到一个设置了窗口样式的非全屏Activity,那么原Activity就会执行onPause方法。

3、横竖屏切换时的生命周期

只有设置了android:configChanges="orientation"属性,横竖屏切换时才会调用onConfigurationChanged方法,否则不会调用该方法,而是会将Activity销毁再重建。注意:当 API >12 时,需要加入 screenSize 属性,否则屏幕切换时即使你设置了 orientation 系统也会重建 Activity !

4、Activity异常退出时的生命周期

onPause() --> onSaveInstanceState() --> onStop() --> onDestory()

需要注意的是 onSaveInstanceState() 方法与 onPause 并没有严格的先后关系,有可能在 onPause 之前,也有可能在其后面调用,但总会在 onStop() 方法之前调用。

  • 关于启动模式

standard、singleTop、singleTask、singleInstance,前两者比较简单,略过。

1、singleTask。说singleTask前先来了解一下task。什么是task?task翻译为任务,可以理解为一组相互关联的activity的集合,控制界面的跳转和返回,这个task存在于一个称为back stack的数据结构中。

如果应用程序中存在A,B,C三个activity,当用户启动应用时,先启动主Activity A,接着A开启B,B开启C,这时栈中有三个Activity,并且这三个Activity默认在同一个任务(task)中。当用户按返回时,弹出C,栈中只剩A和B,再按返回键,弹出B,栈中只剩A,再继续按返回键,弹出A,任务被移除。task是可以跨应用的,这正是task存在的一个重要原因。跨应用是什么意思呢?有时为了保持用户操作的连贯性,需要把不同应用程序的Activity放在同一个任务中。例如,在我们的应用程序中的一个Activity A中点击发送邮件,会启动邮件程序的一个Activity B来发送邮件,这两个activity是存在于不同app中的,但是被系统放在一个任务中,这样当发送完邮件后,用户按back键返回,可以返回到原来的Activity A中,这样就确保了用户体验。

接下来回到singleTask根据谷歌官方文档,如果一个Activity启动模式设置为singleTask,那么系统总会在一个新任务的最底部(root)启动这个activity,并且被这个activity启动的其他activity会和该activity同时存在于这个新任务中。如果系统中已经存在这样的一个activity则会重用这个实例,并且调用它的onNewIntent()方法。不过谷歌的官方文档描述不准确,经过测试,把Activity启动模式设置为singleTask,在启动该activity时只会把它标示为在一个新task中启动,至于是否在一个新task中启动,还要受其他条件的限制。这个条件就是是否设置了android:taskAffinity属性并且是否已经存在了一个由它的taskAffinity属性指定名称的task。如果没有设置taskAffinity属性,那么该Activity就会和调用它的Activity处于同一task中,不会新建task;如果设置了taskAffinity属性并且taskAffinity所指定的task已存在,也不会新建task,而是检查在这个task中是否已经有了一个该Activity的实例,若有,则会重用这个task和task中的该Activity实例,并将这个task调到前台,清除位于该Activity上面的所有Activity,显示该Activity,并调用该Activity的onNewIntent()。若没有则会在这个task中创建该Activity的实例,并调用onCreate()方法;如果设置了taskAffinity属性但是taskAffinity所指定的task不存在,才会创建一个新的task,并且将该Activity启动到这个新的task中,这个新的task的名称就是taskAffinity属性的值,而且后续被该Activity启动的其他Activity也会在这个task中。(如果Activity没有设置android:taskAffinity属性,那么它会默认运行在名字为应用包名的task中)

另外还可以将两个不同应用中的singleTask模式的Activity的taskAffinity设成相同值,这样两个activity虽然不在同一应用中,却会在运行时被分配到同一任务中。

2、singleInstance。singleInstance的特点可以归结为以下三条:

  • 以singleInstance模式启动的Activity具有全局单例性,即整个系统中只会存在一个该Activity实例
  • 以singleInstance模式启动的Activity具有独占性,即它会独自占用一个task,被它启动的任何activity都会运行在其他task中
  • 被singleInstance模式的Activity启动的其他activity,能够但不一定新建task,也可能在一个已有的task中启动

 

  • 关于Activity数据的传递与保存

1、数据传递

使用Intent传递数据是有大小限制的,虽然官方并未详细说明,不过通过实验的方法可以测出数据大小应该被限制在1MB之内(不同手机数值也有不同,有的甚至在512KB之内),超出大小就会出现闪退、停止运行等异常。所以不要用Intent传递过大数据比如图片等。

2、数据保存

Activity 的 onSaveInstanceState() 和 onRestoreInstanceState() 并不是生命周期方法,它们不同于 onCreate() 、onPause() 等生命周期方法,它们并不一定会被触发。只有当应用遇到意外情况(如:内存不足、用户直接按 Home 键)时由系统销毁一个 Activity ,onSaveInstanceState()才会被调用。换句话说就是除非该 activity 是被用户主动销毁的,否则就会调用onSaveInstanceState()方法。通常 onSaveInstanceState() 只适合用于保存一些临时性的状态,而 onPause() 适合用于数据的持久化保存。

  • 关于Scheme 跳转协议

通过scheme 跳转协议,可以实现:服务器定制化跳转 app 页面、app 可以通过 Scheme 跳转到另一个 app 页面、可以通过 h5 页面跳转 app 原生页面。scheme跳转使用方法如下:

1、AndroidManifest中设置增加拦截器(intent-filter),设置scheme

<activity
       android:name=".SchemeActivity">
       <intent-filter>
           <action android:name="android.intent.action.VIEW" />
           <category android:name="android.intent.category.DEFAULT" />
           <category android:name="android.intent.category.BROWSABLE" />

           <data 
                android:scheme="wyx" />
       </intent-filter>
</activity>

2、调用。如上代码我们只是简单的配置了一个android:scheme属性(还可以设置其他详细属性,具体参考这里),所以调用起来就很简单了。

android原生调用:

startActivity(new Intent(Intent.ACTION_VIEW,Uri.parse("wyx://")));

 html调用:

<a href="wyx://">跳转</a>

有了这种跳转方式 ,只要知道其他app的scheme就可以随意的跳过去了,比如打开微信和QQ:

<a href="weixin://">打开微信</a>

<a href="mqqzone://">打开QQ</a>

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值