精华内容
参与话题
问答
  • Activity详解

    2017-09-19 21:21:21
    1.activity的启动过程: 启动activity的请求由instrumentation处理,通过binder向AMS发起请求,AMS内部维护着一个ActivityStack,负责同步Activity的状态,AMS通过ActivityThread去同步Activity的状态从而完成生命...
    1.activity的启动过程:
    启动activity的请求由instrumentation处理,通过binder向AMS发起请求,AMS内部维护着一个ActivityStack,负责同步Activity的状态,AMS通过ActivityThread去同步Activity的状态从而完成生命周期方法的调用。

    2.异常情况下Activity的生命周期分析:
    (1)资源相关的系统配置发生改变导致Activity被杀死并重新创建(横竖屏切换):
    Activity会被销毁,系统会调用onSaveInstanceState来保存当前Activity的状态,该方法在onStop前调用,与onPause没有固定的时序关系,且只有在Activity被异常终止的情况下才会被调用。Activity被重新创建后,系统调用onRestoreInstanceState,把onSaveInstanceState方法保存的Bundle对象作为参数传给onRestoreInstanceState和onCreate。采用onRestoreInstanceState恢复数据而不是用onCreate中的参数Bundle saveninstanceState恢复是因为onRestoreInstanceState如果被调用,则Bundle类型的参数必定不为null不需要再做判断,而在正常启动的情况下onCreate中Bundle类型参数为空。
    (2)资源内存不足导致低优先级的Activity被杀死:
    1).Activity优先级排序:
    前台activity(正在与用户交互的activity) > 可见但非前台activity(弹出对话框等原因导致该activity部分可见但并不处于前台) > 后台activity(已经被暂停的activity)
    如果系统内存不足,就会按照该优先级杀死目标activity所在进程,之后通过onSaveInstanceState和onRestoreInstanceState保存和恢复数据。

    2).当系统配置发生变化时限制activity重新创建:
    在AndroidManifest中设置activity的configChanges属性,常用属性orientationscreenSizekeyboardHidden

    总结:当屏幕翻转时系统内部发生的变化:若没有设置activity的configChanges为"orientation|screenSize",翻转屏幕activity会被销毁,在执行onStop前调用onSaveInstanceState保存当前状态,然后重新创建,调用onRestoreInstanceState恢复状态,如果设置了configChanges 则会调用onConfigurationChanged方法

    3.启动模式
    (1)standard:
    每次启动activity都会创建一个新的实例。这种模式下,谁启动了这个activity,那么新的activity就会在启动它的activity所在的栈中。如果用ApplicationContext去启动standard模式的Activity会报错,因为新activity会默认进入启动它的activity的栈中,而非activity类的Context并没有任务栈。解决方法:为待启动的activity指定FLAG_ACTIVITY_NEW_TASK标记位,这样启动时会为它创建一个新的任务栈,实际上是以singleTask模式启动。

    (2)singleTop栈顶复用模式:
    如果新activity已位于任务栈栈顶,那么不会被重新创建,会调用它的onNewIntent方法,但是该activity的onCreate,onStart不会被调用。如果新activity存在但不位于栈顶,则仍会创建新的实例。

    (3)singleTask栈内复用模式:
    只要activity在一个栈内存在,都不会创建实例,会调用onNewIntent方法。当一个singleTask模式的activity A启动后,系统首先会寻找是否有A想要的任务栈,如果不存在,则创建新的任务栈,然后把创建A的实例放入栈中。如果存在A所需的任务栈,则看栈中是否有A的
    实例,如果有实例,则把A调到栈顶(在A之上的Activtiy全部出栈)并调用他的onNewIntent方法,如果不存在实例,则创建实例并压入栈中。

    (4)singleInstance单实例模式:
    为该模式的activity单独创建一个新的任务栈,而且后续的请求都不会创建新的activity实例,除非这个单独的任务栈被系统销毁了。

    查看任务栈信息指令:dumpsys activity

    如果有两个任务栈,前台任务栈为AB,后台任务栈为CD(启动模式均为singleTask),如果请求启动D,则整个后台任务栈会被切换到前台,后退列表变成ABCD。



    如果请求启动C 则后退列表变为ABC。因为调用启动模式为singleTask 的C会让栈内Activity D出栈。


    TaskAffinity:标识Activity所需要的任务栈名字,默认情况下所有Activity的所需任务栈名字为应用的包名,一般和singleTask配合使用。

    如果Activity A(standard)启动Activity B(launchMode:singleTask,taskAffinity:task1),B再启动Activity C(launchMode:singleTask,taskAffinity:task1),C再启动A,A再启动B,此时按两次Back,将会返回桌面。
    分析:1.A启动B,系统会创建名为task1的任务栈并创建B的实例将B入栈。
    2.B启动C,由于task1存在所以系统只创建C的实例并将C入栈。
    3.C再启动A,由于A是standard所以会创建A的实例,并加入启动它的Activity所在的任务栈,即task1.
    4.此时系统内存在两个任务栈:(1)默认包名任务栈,内部为A(2)task1任务栈,内部为BCA。
    5.再由A启动B,由于存在task1并且task1内有Activity B,所以系统不会创建B的实例而是将B上放的CA全部出栈,此时task1内部只剩Activity B。
    6.第一次按back B出栈,task1任务栈销毁,位于前台的是默认任务栈的A,第二次按back,A出栈,返回桌面。

    常用的Flags:(intent.setFlags优先级比AndroidManifest中setLaunchMode更高)
    1.FLAG_ACTIVITY_NEW_TASK:效果与在XML中指定“singleTask”启动模式相同。

    2.FLAG_ACTIVITY_SINGLE_TOP:效果与在XML中制定“singleTop”启动模式相同。

    3.FLAG_ACTIVITY_CLEAR_TOP:同一任务栈位于该Activity上方的Activity都要出栈

    4.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS:效果与在XML中设定android:excludeFromRecents = “true” 相同,具有该标记的Activity不会出现在历史Activity的列表中。

    展开全文
  • Activity 生命周期 image.png 注意点 ...Activity切换时,旧...即activityA跳到activityB时执行顺序为:activityA-onPause()再 activityB-onCreate()、activityB-onStart()、activityB-onResume(),最后才...

    Activity

    生命周期

    image.png

    注意点

    1. Activity切换时,旧Activity的onPause会先执行,然后才会启动新的Activity。即activityA跳到activityB时执行顺序为:activityA-onPause()再 activityB-onCreate()、activityB-onStart()、activityB-onResume(),最后才是activityA-onStop()。
      —— 这也是为什么不建议在onPause()做重量级操作的原因。

    2. 上图为正常情况下的生命周期,异常情况下的生命周期略有不同。activity在异常情况下终止的,系统调用onSaveInstanceState()来保存当前activity状态。这个方法的时机是在onStop()之前,但和onPause()没有直接但先后关系。 当activity被重新创建后,系统会调用onRestoreInstanceState(),并把在销毁时在onSaveInstanceState()中保存的Bundle对象作为参数传递给onCreate()和onRestoreInstanceState()方法。onRestoreInstanceState()调用时机是在onStart()之后。 一般可以选择在onCreate()或onRestoreInstanceState()方法中恢复数据,两者的区别是,在onCreate()需要判断Bundle参数是否为空,在onRestoreInstanceState()中则不用,因为onRestoreInstanceState()被调用那么Bundle参数必然有值,官方建议在这里恢复。

    自己保存,在重写onSaveInstanceState()方法中保存

    @Override
        protected void onSaveInstanceState(Bundle outState) {
            super.onSaveInstanceState(outState);
            outState.putString("save_data","保存数据");
        }
    

    然后在onCreate()中恢复

    @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
          
            if(savedInstanceState!=null){
                Log.e(TAG,"onCreate恢复的数据:"+savedInstanceState.get("save_data"));
            }
        }
    
    1. 需要说明的是,系统只有在activity即将被销毁并且有机会重新显示的情况才会调用onSaveInstanceState(),也即异常终止才会调用来保存和恢复数据。
      (非正常情况销毁Activity的场景比较多,比如系统内存不够用,系统语言改变,屏幕方向改变等。用户主动意愿想要销毁Activity就是正常情况,这种场景很少,就两种:调用finish和带特殊启动模式的startActivity方法,其他都是非正常情况。savedInstanceState会保存到哪些数据呢?有两种:系统帮你自动保存的和你自己保存的。系统只会保存它认为有必要保存的(比方说EditText里面的内容,CheckBox的Check状态,Fragment实例等),特别注意Activity会自动保存其中的Fragment实例。

    2. 一般情况下屏幕方向改变等系统配置发送改变后,activity会被重新创建,那会就会调用上面保存恢复数据的方法。但我们也可以通过给activity指定configChange属性,使得在系统配置改变时不重新创建。例如屏幕旋转,如果不想旋屏时重新创建activity,可以在xml中设定android:configChange="orientation".这是再旋屏,activity不会再重新创建,那么onSaveInstanceState()和onRestoreInstanceState()也不会再被调用,取而代之的时调用来onConfigurationChanged(),我们可以在这里做我们的处理。

    3. 再说说onDestroy,执行到这一步,一般代表activity即将要被销毁掉,不管是正常情况还是非正常情况关闭activity。一般在这里面我们会做一些资源的释放操作,以防止出现资源泄露或者依赖activity所引发的一些异常情况的发生。这里我举两个例子来说下上面说的两种情况:

    异步任务引发的资源泄露,比如handler或者thread。这种情况发生的原因主要是异步任务的生命周期与activity生命周期不同步造成的,以handler中的message为例:

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

    不管是使用哪种形式来发送message,message都会直接或者间接引用到当前所在的activity实例对象,如果在activity finish后,还有其相关的message在主线程的消息队列中,就会导致该activity实例对象无法被GC回收,引起内存泄露。所以一般我们需要在onDestroy阶段将handler所持有的message对象从主线程的消息队列中清除。示例如下:

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

    异步任务引发的App运行异常,这里以一个显示Dialog的场景为例:

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

    由于我们设置的是5秒后显示一个dialog,当activity在5秒内被finish后可能会导致显示dialog时App发生崩溃。
    所以在这种场景下正确的做法应该是这样的:

    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);
    

    Activity启动模式

    • Standard标准模式

    这种启动模式最常见,也是Activity的默认启动模式,每当我们需要开启一个新的Activity页面时系统都会新建一个Activity实例对象,然后开启上面说的Activity的生命周期流程之旅,onCreate->onStart->onResume。在这种模式,谁启动了这个activity,那么这个activity就运行在启动它的那个activity所在的栈中。
    (所以如果用ApplicationContext去启动这种Standard模式的activity会报错,因为非activity类型的context并没有所谓的任务栈)

    • SingleTop栈顶复用模式

    设置该模式后,当通过startActivity启动的ActivityA已位于当前Task栈的栈顶,系统不会重新创建一个Activity实例,而是进入一个特殊的方法onNewIntent,通过此方法的参数可以取出当前请求的信息,具体流程为:onNewIntent->onResume。即onCreate()和onStart()都不会调用,因为它并没有变化。如果ActivityA存在但不在栈顶,那么ActivityA依然会重建。

    • SingleTask栈内复用模式

    设置该模式可以保证当前Task栈中每种Activity只会有一个实例存在,当通过startActivity启动ActivityA时:1、如果ActivityA所需的栈不存在,则先创建ActivityA所需的任务栈,然后将实例入栈;
    2、如果ActivityA所需的栈存在,但栈中不存在Activity A的实例,那么创建实例并入栈;
    3、如果ActivityA所需的栈存在,并且栈中存在Activity A的实例,则不再重新创建一个新的Activity实例,而是直接复用该实例,进入该Activity的onNewIntent方法,同时将位于ActivityA实例之上的所有Activity弹出Task栈并销毁

    • SingleInstance单实例模式

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


    1. 在上面多次说到activity的任务栈,那么什么是activity的任务栈呢?这要从一个参数TaskAffinity,可以翻译为任务相关性,这个参数标识来一个activity所需的任务栈的名字,默认情况为应用包名,我们也可以为每个acivity单独指定TaskAffinity。

    TaskAffinity属性主要和singleTask启动模式或allowTaskReparenting属性(运行activity在栈间转移)配对使用,其他情况没什么意义。1、当和singleTask启动模式配合使用,它是具有该模式的activity的目前任务栈的名字;
    2、当和allowTaskReparenting属性配合使用时,会产生特殊的效果。比如,当一个应用A启动来应用B的某个activityC,如果activityC的allowTaskReparenting设为true,那么应用B被启动后,此activity会直接从应用A的任务栈转移到B的任务栈中。(本来A启动activityC,activityC应该在A的任务栈中,但B启动后,activityC会转移到B的任务栈,因为activityC本来是属于B的)

    1. 如何给activity指定启动模式?
    • 通过AndroidMenifest.xml中指定
    <activity
    android:launchMode:"singletask"
    >
    
    • 通过Intent设置标志位
    Intent intent = new Intent();
    intent.setClass(MainActivity.this, SecondActivity.class);
    intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    startActivity(intent);
    

    两者的区别:
    1、优先级不同:第二种设置标志位的优先级高;
    2、限定范围不同:第一种无法直接为activity设定FLAG_ACTIVITY_CLEAR_TOP标识,而第二中无法指定singleInstance模式。

    IntentFilter 匹配规则

    启动activity分两种:显式调用和隐式调用。显示调用需要明确指定被启动对象的组件信息,包括包名类名,而隐式不用。显示优先级高。隐式调用需要Intent能偶匹配目标组件的IntentFilter中所设置的action、category、data等过滤信息,不匹配无法启动。

    • 只有一个Intent同时匹配action类别、category类别、data类别才算完全匹配,只有完全匹配才能成功启动目标activity。
    • 一个activity中可以有多个intent-filter,一个Intent只要能匹配任何一组intent-filter即可成功启动对应的activity。
    1. action匹配规则

    action是一个字符串,系统预定来一些action,我们也可以自定义action。action的匹配规则是Intent中的action存在且必须和过滤规则中的其中一个action相同(区分大小写)

    1. category匹配规则

    category是一个字符串,系统预定来一些category,我们也可以自定义category。category的匹配规则是:如果Intent包含category,那个所有的category都必须和过滤规则中的其中一个category相同。
    如果Intent不包含category也可以匹配,因为默认会有"android:intent.category.DEFAULT"这个category,所以为了能接收隐式调用,就要在intent-filter中指定"android:intent.category.DEFAULT"这个category。

    1. data匹配规则

    data由两部分组成,mimeType(媒体类型)和URI(URI结构:<scheme>://<host>:<port>/[<path>|<pathPrefix>|<pathPattern>], 如content://com.example.project:200/folder/etc, )

    data的匹配规则和action类似,如果过滤规则有data,那么要求Intent中必须包含data数据,并且能够完成匹配过滤规则中的某个data。URI有默认值content和file,所以如果过滤规则没有指定URI,Intent必须指定为content或者file才能匹配

    注意:如果要为Intent指定完整的data,必须用setDataAndType()方法,不能分别调用setData()和setType(),因为这两个方法会互相清除对方的值。

    Activity 工作过程

    1. Launcher通知AMS启动APP的MainActivity,也就是清单文件设置启动的Activity。
    2. AMS记录要启动的Activity信息,并且通知Launcher进入pause状态。
    3. Launcher进入pause状态后,通知AMS已经paused了,可以启动APP了。
    4. app未开启过,所以AMS启动新的进程,并且在新进程中创建ActivityThread对象,执行其中的main函数方法。
    5. app主线程启动完毕后通知AMS,并传入applicationThread以便通讯。
    6. AMS通知APP绑定Application并启动MainActivity。
    7. 启动MainActivitiy,并且创建和关联Context,最后调用onCreate方法。

    根Activity启动过程

    • 1、点击桌面应用图标,Launcher进程将启动Activity(MainActivity)的请求以Binder的方式发送给了AMS。
    • 2、AMS接收到启动请求后,交付ActivityStarter处理Intent和Flag等信息,然后再交给ActivityStackSupervisior/ActivityStack 处理Activity进栈相关流程。同时以Socket方式请求Zygote进程fork新进程。
    • 3、Zygote接收到新进程创建请求后fork出新进程。
    • 4、在新进程里创建ActivityThread对象,新创建的ActivityThread就是应用的主线程,在主线程里开启Looper消息循环,开始处理创建Activity。
    • 5、ActivityThread利用ClassLoader去加载Activity、创建Activity实例,并回调Activity的onCreate()方法,这样便完成了Activity的启动。
    image.png

    普通Activity启动过程

    普通Activity的启动过程只涉及两个进程,AMS所在进程和应用程序进程。

    启动Activity B -> 当前有正在显示的activity吗 -> 有就先pause() -> B的进程存在吗 -> 不存在则创建 -> B进程启动指定的Activity

    image.png

    Activity跟window,view之间的关系

    • ==Activity在创建时会调用 attach() 方法初始化一个PhoneWindow==(继承于Window),每一个Activity都包含了唯一一个PhoneWindow
    • ==Activity通过setContentView实际上是调用的 getWindow().setContentView将View设置到PhoneWindow上==,而PhoneWindow内部是通过 WindowManager 的addView、removeView、updateViewLayout这三个方法来管理View,WindowManager本质是接口,最终由WindowManagerImpl实现。
    展开全文
  • Activity是一个应用组件,用户可与其提供的屏幕进行交互,以执行拨打电话、拍摄照片、发送电子邮件或查看地图等操作。每个 Activity 都会获得一个用于绘制其用户界面的窗口。窗口通常会充满屏幕,但也可小于屏幕并...

    一.什么是Activity

           Activity是一个应用组件,用户可与其提供的屏幕进行交互,以执行拨打电话、拍摄照片、发送电子邮件或查看地图等操作。每个 Activity 都会获得一个用于绘制其用户界面的窗口。窗口通常会充满屏幕,但也可小于屏幕并浮动在其他窗口之上。一个应用通常由多个彼此松散联系的 Activity 组成。

         一般会指定应用中的某个 Activity 为“主” Activity,即首次启动应用时呈现给用户的那个 Activity。而且每个 Activity 均可启动另一个 Activity,以便执行不同的操作。每次新 Activity 启动时,前一 Activity 便会停止,但系统会在堆栈(“返回栈”)中保留该 Activity。当新Activity 启动时,系统会将其推送到返回栈上,并取得用户焦点。返回栈遵循“后进先出”堆栈机制,因此,当用户完成当前 Activity 并按“返回”按钮时,系统会从堆栈中将其弹出(并销毁),然后恢复前一 Activity。当一个 Activity 因某个新 Activity 启动而停止时,系统会通过该 Activity 的生命周期回调方法通知其这一状态变化。Activity 因状态变化—系统是创建Activity、停止 Activity、恢复Activity 还是销毁 Activity— 而收到的回调方法可能有若干种,每一种回调方法都会为您提供执行与该状态变化相应的特定操作的机会。例如,停止时,您的 Activity 应释放任何大型对象,例如网络或数据库连接。当 Activity 恢复时,您可以重新获取所需资源,并恢复执行中断的操作。这些状态转变都是 Activity 生命周期的一部分。(来自android developer API)

    二.Activity生命周期(重点)


    public class ExampleActivity extends Activity {
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            // The activity is being created.
        }
        @Override
        protected void onStart() {
            super.onStart();
            // The activity is about to become visible.
        }
        @Override
        protected void onResume() {
            super.onResume();
            // The activity has become visible (it is now "resumed").
        }
        @Override
        protected void onPause() {
            super.onPause();
            // Another activity is taking focus (this activity is about to be "paused").
        }
        @Override
        protected void onStop() {
            super.onStop();
            // The activity is no longer visible (it is now "stopped")
        }
        @Override
        protected void onDestroy() {
            super.onDestroy();
            // The activity is about to be destroyed.
        }
    }

    一表解决所有方法调用时机:

    方法

    描述

    是否能事后终止?

    后接

    onCreate()

    首次创建 Activity 时调用。 您应该在此方法中执行所有正常的静态设置— 创建视图、将数据绑定到列表等等。系统向此方法传递一个 Bundle 对象,其中包含 Activity 的上一状态,不过前提是捕获了该状态(请参阅后文的保存 Activity状态)。

    始终后接 onStart()。

    onStart()

        

    onRestart()

    在 Activity 已停止并即将再次启动前调用。

    始终后接 onStart()

    onStart()

    onStart()

    在 Activity 即将对用户可见之前调用。

    如果 Activity 转入前台,则后接 onResume(),如果 Activity 转入隐藏状态,则后接 onStop()。

    onResume()

    onStop()

        

    onResume()

    在 Activity 即将开始与用户进行交互之前调用。 此时,Activity 处于 Activity 堆栈的顶层,并具有用户输入焦点。

    始终后接 onPause()。

    onPause()

    onPause()

    当系统即将开始继续另一个 Activity 时调用。 此方法通常用于确认对持久性数据的未保存更改、停止动画以及其他可能消耗 CPU 的内容,诸如此类。 它应该非常迅速地执行所需操作,因为它返回后,下一个 Activity 才能继续执行。

    如果 Activity 返回前台,则后接 onResume(),如果 Activity 转入对用户不可见状态,则后接 onStop()。

    onResume()

    onStop()

    onStop()

    Activity 对用户不再可见时调用。如果 Activity 被销毁,或另一个 Activity(一个现有 Activity 或新 Activity)继续执行并将其覆盖,就可能发生这种情况。

    如果 Activity 恢复与用户的交互,则后接 onRestart(),如果 Activity 被销毁,则后接 onDestroy()。

    onRestart()

    onDestroy()

    onDestroy()

    在 Activity 被销毁前调用。这是 Activity 将收到的最后调用。 当 Activity 结束(有人调用 Activity 上的finish()),或系统为节省空间而暂时销毁该 Activity 实例时,可能会调用它。 您可以通过isFinishing() 方法区分这两种情形。

     

    常见情况Activity调用:

             当用户点击当前Activity进入下一个Activity时,当前Activity调用onPause(),onStop()但不会调用onDestroy();

             当用户按下返回键销毁当前Acitity返回上个Activity不会调用onCreat()而是直接调用onRestart ,onStart(),onResume().

             当用户在当前情况按下home键,依次调用onPause(),onStop(),打开app依次调用onRestart ,onStart(),onResume().

    三.Activity跳转

            Activity跳转,无返回结果

           这是最简单的Activity跳转方式。从一个Activity启动另一个Activity,直接startActivity(new Intent(当前Activity.this, 下一Activity.class))。

     

            Activity跳转,返回数据/结果

           需要返回数据或结果的,则使用startActivityForResult (Intent intent, int requestCode),requestCode 的值是自定义的,用于识 别跳转的目标Activity。跳转的目标Activity所要做的就是返回数据/结果,setResult(int resultCode)只返回结果不带数据,或者setResult(intresultCode, Intent data)两者都返回!而接收返回的数据/结果的处理函数是onActivityResult(int requestCode, int resultCode, Intent data),这里的requestCode就是startActivityForResult的requestCode,resultCode就是 setResult里面的resultCode,返回的数据在data里面。

      ** 注意,在setResult后,要调用finish()销毁当前的Activity,否则无法返回到原来的Activity,就无法执行原来Activity的onActivityResult函数,看到当前的Activity没反应。


    展开全文
  • 四大组件之Activity详解

    Activity详解

    1.activity的定义

    activity活动,窗体。四大组件中比较重要的一个,是应用不可缺少的一部分。承载界面的窗体,是用户可视化,可交互的载体。

    2.activity的生命周期

    上图描述的已经是很直观的了,我想作为一个android开发对这个图应该是深印脑海的。这里只对每一个生命周期做一个描述和特殊场景下生命周期的执行顺序做一个描述:

    生命周期的解析:

    • onCreate():activity创建,开始初始化view。首次启动时候执行该方法
    • onStart():简单理解我可见。就是绘制完成,窗体可见。但仅仅是可见!在这里可以做一些初始化的操作
    • onResume():可交互。当执行到这个生命周期后,用户和界面之间才可以交互。
    • onPause():暂停,在这个生命周期中,界面可能是可见但不可交互的(比如有弹窗的时候)此时若弹窗消失,生命周期会再次回到onResume();或者是从可见到不可见,有别的窗体过来覆盖的情况。不管是什么情况,在这个生命周期中一般会做一些释放cpu的操作,比如停止动画等。
    • onStop():不可见状态,activity完全被别的activity覆盖。
    • onRestart():和onStop对应,当activity被停止而没有被销毁的时候,若再回到前台,不会从onCreate()开始执行,而是执行onRestart()-onStart()
    • onDestroy():销毁,继不可见之后,将其销毁,也就是从栈中移除。这个activity不存在了。

    简单理解生命周期的执行顺序:

    首次启动一个activityA的时候,该activity的生命周期是:onCreate()-onStart()-onResume();

    息屏:onPause()-onStop();

    点亮屏幕:onRestart()-onStart()-onResume();

    按返回键:onPause()-onStop()-onDestroy();

    再次启动:onCreate()-onStart()-onResume();

    Home按键返回桌面:onPause()-onStop();

    再次打开应用:onRestart()-onStart()-onResume();

    点击事件弹出一个窗体:onPause();

    弹窗消失:onResume()

    竖屏切换横屏时候的生命周期顺序:onPause()-onStop()-onDestroy()-onCreate()-onStart()-onResume();

    生命周期的总结:
    理解每一个生命周期的执行特点和执行顺序,可以很好的协助我们开发。

    3.启动模式

    >

    在介绍启动模式之前,我们先来了解应用是如何管理activity的。一个应用是由很多activity组成的,这些activity中有一个入口。这些activity都存放在栈中,是由栈来管理的。具体的结合启动模式来理解。

    1. standard:默认的,在该模式下,每一次都会创建一个新的实例压入栈中。
    2. singleTop:栈中允许有多个相同的实例,但是不允许在栈顶叠加。也就是说只要栈顶存在就不会创建新的实例,而是调用onNewIntent来使用它
    3. singleTask:栈中唯一,也就是栈中只允许存在一个实例,所以只要栈中有,就不会再去创建新的,而是把它上边的activity全部销毁掉来调用它的onNewIntent来复用。
    4. singleInstance:唯一的栈,唯一的实例。该启动模式下的activity会单独创建一个栈来保存它,这个栈中也不允许有别的实例存在。

    4.保存状态值

    上边了解了生命周期和启动模式之后,我们知道activity是保存在栈中的。activity的onStop()状态是没有被销毁,还存在内存中,这时候他的成员信息和状态都是活的。所以这时候我们可以对他进行一些状态值的保存,当这个activity再回到前台时还是之前的状态。而这种方式就是通过onSaveInstanceState() 。

    或许你会说,我没做任何操作也没有实现 onSaveInstanceState() 方法,activity的状态也是之前的效果。那是因为 Activity 类里面默认实现的 onSaveInstanceState 方法恢复出来。特别是会为布局中的视图( View )默认调用 onSaveInstanceState 方法,并在这个方法中允许每一个视图提供它需要恢复的任何信息。几乎每一个 Android 框架中的 widget 都视情况实现了这个方法,这样的话,这些 UI 的可视变化将会自动保存并在 activity 重建时被恢复。例如,一个 EditText 控件保存用户输入的内容,一个复选按钮保存它是否是被选中。你要做的只是给每一个你需要保存状态的 widget 提供一个唯一的 ID (用 android:id 属性)。如果一个 widget 没有 ID 的话,它将无法保存状态。

    尽管默认实现了 onSaveInstanceState 方法来保存 activity UI 中重要的数据,但你也可以自己覆写它来保存一些额外的数据。比如,你可能需要保存一些在 activity 生命周期里更改的一些成员数据(比如一些与恢复 UI 有关、用来保存 UI 数据,但在默认情况下并没有被恢复的成员数据)。

    典型案例:
    横竖屏切换的时候是activity销毁在创建的过程。这时候我们就可以利用onSaveInstanceState方法来保存我们的替代资源,创建的时候取出展示。注意:这个保存的bundle会在onCreate(Bundle savedInstanceState)方法中返回。

    5.安全退出多个activity

    为什么要说这个问题呢,因为这是开发中最常见的一个问题,很多同学能理解启动模式,却不能很好的使用。下面举个开发中的场景
    比如类似淘宝的一个商城查看商品详情,用户评价等等进入了深层页面,然后想回到首页就要一层一层的返回,用户体验很不好,所以会有一个按钮,直接返回首页,问题是怎么安全的退出这么多个activity

    1. 通过Intent的Flags来控制堆栈去解决:

      android中,每打开一个Activity,便会在栈中加入一个Activity,当该Activity被销毁后,栈中便移除了它,并且栈中的Activity是按照启动的先后顺序依次压入栈的。
      Android的窗口类提供了历史栈,我们可以通过stack的原理来巧妙的实现,这里我们在A窗口打开B窗口时在Intent中直接加入标 志 Intent.FLAG_ACTIVITY_CLEAR_TOP,这样开启B时将会清除该进程空间的所有Activity。

      Intent intent = new Intent(this,TestActivity2.class);
      intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
      startActivity(intent);

    2. 通过堆栈管理器,对Stack中存储的Activity进行操作(推入,推出,弹出)

      实现一个StackManager 工具类来管理activity,在这个工具类中对栈中的activity进行操作,根据我们的需求来操作。

    3. 使用广播机制:通过Activity创建的时候,设置监听广播,在特定情况下,发送广播进行遍历finish()
      该方法存在的缺点是浪费资源

    总结:分析以上方法,最方便安全的就是第一种。

    展开全文
  • Android Activity详解

    万次阅读 2018-06-15 12:27:21
    Android Activity详解 1.什么是Activity Activity是一个Android的应用组件,它提供屏幕进行交互。每个Activity都会获得一个用于绘制其用户界面的窗口,窗口可以充满哦屏幕也可以小于屏幕并浮动在其他窗口之上。 ...
  • Android Activity详解

    2020-11-07 17:42:26
    Android Activity详解 1.什么是Activity Activity是一个Android的应用组件,它提供屏幕进行交互。每个Activity都会获得一个用于绘制其用户界面的窗口,窗口可以充满哦屏幕也可以小于屏幕并浮动在其他窗口之上。 ...
  • Activity详解

    万次阅读 2018-03-30 10:06:19
    一、Activity简述1、概念引入图1.1 Activity类图结构Activity作为Android的四大组件之一,Activity在Android系统中是以界面的形式进行体现。其中Activity实现了如Window.Callback, KeyEvent.Callback等接口用于与...
  • activity详解

    2018-04-10 19:33:44
    Activity 要想了解Activity,那么就必须要清楚Activity的生命周期,图片是最生动的,如下图:生命周期Activity的响应时间 当前Activity所在的线程为主线程,它的响应时间为5秒,如果在当前运行的Activity中进行...
  • Activity详解

    千次阅读 2016-08-08 13:13:51
    启动一个Activity你可以启动一个其他的activity通过调用startActivity(), 并传递一个 Intent , 它用于描述acitity。 intent指定了你想要启动的activity,或者指定了你想展现的动作(系统帮你选择合适的activity,它...
  • activity详解

    2016-12-20 21:51:58
    核心基础小专题【Activity】 Android四大组件 ActivityBroadcastReceiver 广播接收者Service 服务ContentProvider 内容提供者 Activity的继承关系 public class Activity extends ContextThemeWrapper ...
  • Activity详解—— Activity基本用法

    千次阅读 2018-05-17 14:45:22
    Activity详解—— Activity基本用法 Activity的xml配置 Activity在使用时候必须在xml中设置,否则在启动Activity时候会找不到当前的类。下面配置是常用的作为程序入口的Activity配置。如下设置后,点击应用启动...
  • [Android]【安卓】Activity详解

    千次阅读 2018-06-09 15:44:38
    [Android]【安卓】Activity详解 本篇博客已收录到我的安卓开发小结中——点击【安卓开发小结】 参考资料:《第一行代码》、《Android开发艺术探索》 一、返回栈(任务栈) Android使用任务(Task)来管理活动...
  • Android之Activity详解

    千次阅读 热门讨论 2016-11-18 14:39:07
    本篇不针对于新手,而是对于Activity中一些常识或者问题进行总结。本篇介绍了Activity的生命周期、启动关闭、状态保存、启动模式、返回栈协同调度等等知识点。
  • Activity详解 Intent的使用 Fragment详解Part 1:Activity详解1.什么是活动
  • Android Activity 详解

    千次阅读 2013-03-23 09:59:16
    Activity为Android应用程序的一个关键组成部分,它通常提供一个用户界面用来和用户交互以完成某个功能,比如拨号,拍照,发送电子邮件或者是浏览地图, 在移动设备上,Activity通常占据整个屏幕,但Android也支持...
  • Android_Activity_Activity详解

    千次阅读 2013-09-22 20:21:26
    Activity是一个应用组件,用以提供屏幕的交互界面。一个App通常包含多个...一个Activity A可以启动新的Activity B,Activity A将被压入返回栈中,当用户按下后退键退出Activity B后,Activity A将重新获得焦点。
  • Android startActivity源码详解

    千次阅读 2016-03-23 13:08:31
    在Android页面跳转的时候,我们一般都会调用
  • http://my.oschina.net/keeponmoving/blog/60943
  • Activity详解——Activity的xml配置

    千次阅读 2018-05-17 14:51:06
    如下xml中是Activity的xml配置方法的一览以及简介,详细的介绍可以继续往下阅读。 &amp;lt;activity &amp;lt;!--是否允许activity更换从属的任务,比如从短信息任务 切换到浏览器任务,默认false--&...
  • Android中Activity组件详解

    千次阅读 2011-06-08 22:48:00
    1.Activity 的生命周期和J2ME的MIDlet一样,在Android中,Activity的生命周期交给系统统一管理。与MIDlet不同的是安装在Android中的所有的Activity都是平等的。⑴Activity 的状态及状态间的转换在 android 中,...

空空如也

1 2 3 4 5 ... 20
收藏数 50,881
精华内容 20,352
关键字:

activity详解