Activity应用场景解析

一、onCreate

onCreate和onDestroy可以说是使用最频繁的了,因为在一个项目中经常会开关页面。而onCreate是生命周期的第一站,它的作用就是给开发者用来对Activity的实例对象中的成员做初始化的。Android为了方便对Activity的管理和使用,对Activity进行了进一步封装,直接new出来的Activity对象是不会委托给Android管理的,就和普通java文件无异。当然,也就失去了Activity本身的界面展示、交互的意义。

在onCreate中的操作一般和view的初始化相关,诸如addView、setContentView和对view中数据的填充(setText等)。当然这些操作也可以在onStart、onResume中进行,但是在onCreate中能保证只被调用一次,别的地方保不齐会被调用N多次。

在onCreate中有一个相当重要的参数——savedInstanceState,该参数的作用就在于可以帮助开发者在页面非正常销毁(如内存不足、横竖屏切换、系统语言改变等)之前保存一些数据(自动保存的、开发者主动保存的),并且会在Activity重新创建时恢复。因此,对应savedInstanceState参数来讲,onCreate的作用至关重要。

相对应的,在Activity主动finish或者设置启动模式下的销毁,属于Activity的正常销毁。

二、savedInstanceState

savedInstanceState会默认保存Edittext中的内容、CheckBox的Check状态、Fragment实例等数据。以fragment为例,如果我们在onCreate中对fragment手动newInstance,这样在Activity异常重启时,就会出现Double分量的fragment实例,显然是不对的。哪怕是对savedInstanceState判空处理,也行!

 if (savedInstanceState != null) {
            // 这里根据自己需要去从savedInstanceState中去数据
            Fragment fragment = getSupportFragmentManager().findFragmentByTag(FragmentBase.class.getName());
            if (fragment instanceof FragmentBase) {
                FragmentBase base = (FragmentBase) fragment;
                
            }
        } else {
            getSupportFragmentManager().beginTransaction()
                    .add(R.id.container, FragmentBase.newInstance(this, "One", FragmentBase.class.getName()))
                    .add(R.id.container, FragmentFour.newInstance(this, "Two", FragmentFour.class.getName()))
                    .add(R.id.container, FragmentFive.newInstance(this, "Three", FragmentFive.class.getName()))
                    .commit();
        } 

三、onDestroy

走到这一步,代表Activity即将要被销毁,不管它是否是正常关闭。在这个方法内,我们做的最多的就是释放一些资源,为了防止造成Activity引用异常、资源泄漏等问题。

1、异步任务造成资源泄漏

我们都知道handler、Thread这些,会使得异步任务的生命周期与Activity的生命周期不同步,而造成资源泄漏。

Handler handler =  new Handler();
handler.postDelayed(new Runnable() {
    @Override
    public void run() {
        tv.setText("hello world!");
    }
}, 2000);
handler.obtainMessage(1).sendToTarget();

不管怎么发送message,都会或直接、或间接的引用到当前所在的Activity实例对象。如果该Activity已经被finish掉了,可是message还在主线程的消息队列中,结果就是Activity实例对象无非被GC,从而引起内存泄漏。所以在onDestory中需要把message从主线程的消息队列中移除。

@Override
protected void onDestroy() {
    super.onDestroy();
    if (handler != null) {
        handler.removeCallbacksAndMessages(null);
    }
}

2.异步任务引发异常

关于这个问题,笔者在项目开发过程中也碰到过。当时的业务场景是mapView上显示一个dialog,就出现了这一异常!

Handler handler =  new Handler();
handler.postDelayed(new Runnable() {
    @Override
    public void run() {
        new AlertDialog.Builder(MainActivity.this).setMessage("Show Dialog").show();
    }
}, 5000);

如果在5s内该Activity就被正常finish掉了,5s后dialog想依靠父窗体MainActivity来显示,如此一来就会引发异常。

final void performDestroy() {
    mDestroyed = true;
    mWindow.destroy();
    mFragments.dispatchDestroy();
    onDestroy();
    mFragments.doLoaderDestroy();
    if (mVoiceInteractor != null) {
        mVoiceInteractor.detachActivity();
    }
}

要想解决,可以在dialog显示时加一个判断,用来分辨父窗体是否还存在。

Handler handler =  new Handler();
handler.postDelayed(new Runnable() {
    @Override
    public void run() {
        if (!MainActivity.this.isDestroyed()) {
            new AlertDialog.Builder(MainActivity.this).setMessage("Show Dialog").show();
        }
    }
}, 5000);

关于isDestroyed的源码:

/**
 * Returns true if the final {@link #onDestroy()} call has been made
 * on the Activity, so this instance is now dead.
 */
public boolean isDestroyed() {
    return mDestroyed;
}

isDestroyed要求最低的api是17,可以立一个flag判断当前Activity的状态。

四、onStart、onRestart和onStop

  • 对数据的实时性要求:点击列表进入详情,finish返回列表时为保证列表数据的实时性,需要拉取最新的数据并填充。可以放在onStart中,也可以放onRestart中,但是onRestart在Activity首次加载启动时并不会被调用。
  • 动画效果:Activity1进入到Activity2中,由于Activity1已经不可见了动画没必要继续进行了,可以在onStop中停止动画以节省资源

五、onResume和onPause

这两个回调接口的使用频率要稍高一些,比方说是否获得焦点。

  • 结束占用CPU的动画、其他正在运行的任务
@Override  
protected void onPause(){  
        mMapView.onPause();
        super.onPause();  
}  
@Override  
protected void onResume(){  
        mMapView.onResume();
       super.onResume();  
}  
  • 视频播放,当视图组件获得焦点时,即onResume中播放视频,当视图组件失去焦点时,即onPause中暂停播放视频。
  • 保存重要数据,为了防止App被意外强杀,一般会在onPause中将一些重要数据保存到本地。

六、Activity的4种启动模式

1.Standard

默认启动模式,每当我们需要开启一个新的Activity页面时系统都会新建一个Activity实例对象,然后开启上面说的Activity的生命周期流程之旅,onCreate->onStart->onResume。

2.SingleTop

当MainActivity的实例已经存在于栈顶,系统不会重新创建实例,而是进入一个特殊的方法onNewIntent,具体流程为:onNewIntent->onResume。这种场景还是比较多的,比方说商品详情页面一般都会有相关的商品推荐,点击推荐的某个商品后进入的还是一个商品详情页面,这个时候就不需要重新再创建一个新的商品详情Activity页面,直接复用已有的页面,刷新下View中的数据就好了。

3.SingleTask

保证栈中每个Activity都只有一个实例,当通过startActivity启动Activity A时,如果当前Task栈中已经存在一个Activity A的实例,那么不再重新创建一个新的Activity实例,而是直接复用该实例,进入该Activity的onNewIntent方法,同时将位于Activity A实例之上的所有Activity弹出Task栈并销毁。这种场景在IM应用中使用的比较多,比如QQ或者微信的聊天页面,当从聊天页面进入其他页面,然后在重新进入聊天页面时就会直接进入原来的聊天页面,同时销毁中间新创建的Activity页面,并刷新聊天页面的数据。

4.SingleInstance

设置该模式可以保证该Activity所在的Task中有且仅有一个activity实例,当通过startActivity启动Activity A时,如果该Activity的实例已经存在,那么不再重新创建一个新的Activity实例,而是直接复用该实例,进入该Activity的onNewIntent方法。这种场景出现的比较少,该Activity在整个系统只有一个实例,一般用于系统应用,并且可以被其他应用共享使用(有点类似于操作系统概念中的临界资源),比方说来电呼叫页面,在整个系统中就只能有一个,因为同一时刻只能存在一个电话呼叫。

关于启动模式的设置,一般会在清单文件进行配置,也可在代码中动态设置:

intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);

一般将Intent.FLAG_ACTIVITY_NEW_TASK和Intent.FLAG_ACTIVITY_CLEAR_TOP搭配使用实现类似SingleTask的效果,将Intent.FLAG_ACTIVITY_NEW_TASK和Intent.FLAG_ACTIVITY_SINGLE_TOP搭配使用实现类似SingleTop的效果。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值