四大组件 - Activity

定义

Activity实际上只是一个与用户交互的接口

生命周期

1. Activity生命周期中的4种状态

  • Active:当前Activity正处于运行状态,即获得焦点
  • Paused:当前Activity正处于暂停状态,即失去焦点。但仍然没有被销毁,仍然可见。
  • Stopped:当前Activity处于停止状态,Activity不可见,没有被销毁
  • Killed:当前Activity已经被销毁,它的内存里面的成员变量等信息被一并回收

2. Activity生命周期里的方法

  • 3.1 onCreate()
  • 3.2 onStart()
  • 3.3 onResume()
  • 3.4 onPause()
  • 3.5 onStop()
  • 3.6 onDestory()
  • 3.7 onRestart()

3.1 onCreate()

该方法表示Activity正在被创建,这是Activity生命周期的第一个方法。通常在里面进行初始化工作

3.2 onStart()

该方法表示Activity正在被启动,这个时候的Activity已经被创建好了,完全过了准备阶段,但是没有出现在前台,还不能与用户进行交互

3.3 onResume()

该方法表示Activity已经可见了,即出现在前台且可以与用户进行交互了。处于Active状态

3.4 onPause()

该方法表示Activity正在暂停,大多情况下Activity执行完onPause()方法后会继续执行onStop()方法。至于什么情况下会继续执行onStop()方法可以简单的分为两种情况:
1. 当前Activity启动了另外一个Activity或者回切到上一个Activity时就会执行onStop()方法
2. 当前Activity启动了类似于话框的东西时,就值执行onPause()方法,而不会执行onStop()方法

3.5 onStop()

该方法表示Activity即将停止,我们应该在此方法中做一些不那么耗时的轻量级回收操作

3.6 onDestory()

该方法表示Activity要被销毁了,这是Activity生命周期的最后一个阶段,我们可以在该方法里面做一些回收工作和资源释放

3.7 onRestart()

该方法表示Activity正在重新启动。一般情况下,一个存在于后台不可见的Activity变为可见状态,都会执行onRestart()方法,然后再执行onStart()方法

3. Activity的生命周期分析

  • 3.1 正常情况下的生命周期:

    1. Activity启动 → onCreate() → onStart() → onResume() ---------进入Active状态
    2. 点击Home键回到桌面 → onPause() → onStop() -----------进入Stopped状态
    3. 再次回到原Activity → onRestart() → onStart() → onResume() --------又回到Active状态
    4. 退出当前Activity时 → onPause → onStop → onDestroy() ----------Killed状态

  • 3.2 异常情况下的生命周期:

中间涉及两个方法:

  1. onSaveInstanceState() 方法:
    主要用来存储数据(调用的时机在onStop()方法之前)

  2. onRestoreInstanceState() 方法:
    主要用来恢复数据(调用时机在onstart()之后)

3.2.1 因资源配置发生改变导致终止的时候:Activity会被销毁然后重建。

当销毁时,其onPause()、onStop()、onDestory()方法均会被调用。系统会自动调用onSaveInstanceState()方法来保存当前Activity的状态。

当重建时,系统会调用onRestoreInstanceState()方法,并且把onSaveInstanceState()方法所保存的Bundle对象作为参数传递给onRestoreInstanceState()方法和onCreate()方法。然后通过这两个方法来取出之前保存的数据进行恢复。

  • 当异常情况下需要重新创建时,系统会默认为我们保存当前Activity的视图结构,并且在Activity重启后为我们恢复这些数据(例如:文本框输入的数据、ListView滚动的位置)
  • 这些View相关的状态系统都能默认为我们恢复,具体针对某一特定的View系统能为我们恢复哪些数据,就得查看View的源码

关于保存和恢复View层次结构,系统的工作流程:

  • 当Activity被意外终止时,Activity会调用onSaveInstanceState()方法去保存数据。
    1.Activity会委托Window类(PhoneWindow类)去保存数据
    2.Window类会委托它的顶级容器(DecorView类)去保存数据
    3.DecorView类再去通知它的子元素来保存数据

3.2.2 资源内存不足导致优先级低的Activity被杀死

Activity的优先级是指一个Activity对于用户的重要程度,。按照这种规律分为以下等级:

  • 最高优先级:前台Activity
  • 中等优先级:可见但非前台的Activity (Pause状态下的Activity)
  • 最低优先级:完全存在后台的Activity (Stopped状态下的Activity)

注:当内存严重不足时,系统会按照优先级去kill掉Activity所在的进程,并在后续通过onSaveInstanceState()方法和onRestoreInstanceState()方法来储存和恢复数据。

  • 3.3 特殊情况下的生命周期

    3.3.1 Activity的横竖屏切换

    与横竖屏生命周期方法有关调用的属性是“ android:configChanges ”,关于它的属性值设置,如下:

    android:configChanges=" orientation " :消除横竖屏的影响
    android:configChanges=" keyboardHidden " :消除键盘的影响
    android:configChanges=" screenSize " :消除屏幕大小的影响
    

    情况 1 当我们设置Activity的 android:configChanges 属性为
    orientation 、(消除横竖屏影响)
    orientation|keyboardHidden(消除横竖屏、键盘的影响)
    或者不设置该属性的时候,其生命周期如下

    启动Activity
    onCreate() → onStart() → onResume()

    由竖屏切换到横屏
    onPause() → onSaveInstanceState() → onStop() → onDestory()
    /////到这里竖屏的已经销毁了,下面开始创建横屏的
    → onCreate() → onStart() → onRestoreInstanceState() → onResume()

    由横屏切换到竖屏(与竖屏切换横屏过程一致)

    • 情况 2 当我们设置其android:configChanges 属性为
      orientation | screenSize
      或 orientation | screenSize | keyboardHidden 时

    启动Activity
    onCreate() → onStart() → onResume()

    由横屏切换竖屏(由竖屏切换横屏):什么也没调用

    • 情况 3 当我们设置为 orientation | screenSize 时
      在进行横竖屏切换的时候调用的方法是onConfiguraionChanged(),而不会回调Activity的任何一个生命周期方法

    屏蔽横竖屏有两种:
    1. xml布局文件设置
    2. java代码中设置

    1.xml布局文件设置:

    android:screenOrientation = " portrait " 始终以竖屏显示
    android:screenOrientation = " landscape " 始终以横屏显示
    

    2.java代码中设置:

    Acticity.this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT)
    //始终以竖屏显示
    Acticity.this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE)
    //始终以横屏显示
    

3.3.2 什么情况下导致Activity的onDestory()方法不执行

当用户后台强杀应用程序时,onDestory()有时会不执行。分两种情况:

  • 情况 1:当前返回栈仅有一个Activity实例,这时候强杀是会执行onDestory()方法的
  • 情况 2:当返回栈里存在多个Actiivty实例时,栈里面的第一个没有销毁的Activity会执行onDestory()方法,其他不会执行。
    例如:从 MainActivity 跳转到 Activity_A 。这时候,从后台强杀,只会执行MainActivity的onDestory()方法,至于Activity_A的onDestory()是不会执行的

Activity的启动模式

说到启动模式,就会联想起 Android任务栈 ,关于Android任务栈:

  • 它是用来储存Activity实例的一种数据结构,Activity的跳转以及回调都与任务栈有关
  • 启动一个Activity后,这个Activity实例就会放进任务栈中,当点击返回键时,位于任务栈顶层的Activity就会被清理出去。
  • 当任务栈不存在任何Activity的实例的时候,系统就会回收这个任务栈,也就是退出程序了。

启动模式的作用

杜绝浪费内存的行为

如果一个Activity频繁启动,那么便会往任务栈里面放进多个相同的实例。这对内存而言不是好事,明明一个Activity实例就可以应付所有的启动需求,实际上缺放了这么多个,造成了内存的浪费。因为此启动模式也就应运而生。

启动模式类型

  • standard
  • singleTop
  • singleTask
  • singleInstance
  • standard启动模式
    系统默认的启动模式。
    每次启动一个Activity就会新建一个实例(不管其实例是否存在)

    假如 Activity_A 启动了 Activity_B ,即 Activity_B 会进入Activity_A 所在的任务栈

    • 注:非Activity的context(ApplicationContext)没有所谓的任务栈。即当用ApplicationContext去启动 standard模式 的Activity会报错。解决方法就是为待启动的Activity指定 FLAG_ACTIVITY_NEW_TASK标记位,这样启动的时候就会为它创建一个新的任务栈。
  • singleTop启动模式

    栈顶复用模式,在这种模式下:
    1. 如果新的Activity已经位于任务栈的栈顶,那么此Activity不会被重新创建。同时它的onNewIntent()方法会被回调,通过此方法的参数我们可以取出当前请求的信息(此时其onCrate()、onStart()方法不会被调用)。
    2. 如果新的Activity在栈中,但不在栈顶。则新的Activity仍然会被创建,并放进其中。

  • singleTask启动模式

    栈内复用模式,这是一种单例模式
    在这种模式下,只要Activity在一个栈中存在,那么多次启动此Activity都不会重新创建实例。和singleTop一样也会回调其onNewIntent()方法。
    当一个具有singleTask模式的Activity请求启动后,系统首先寻找任务栈中是否已存在该Activity的实例,如果已经存在,那么系统就会把它跳到栈顶并调用onNewIntent()方法。否则创建该Activity的实例并压栈

singleTask模式默认具有 clearTop 的效果,即系统将目标Activity跳到栈顶的方法是:将在该Activity上面的Activity全部出栈,以达到跳到栈顶的效果

  • singleInstance启动模式

    单实例模式
    这是一种加强版的 singleTask 模式,此外此种模式的Activity只能单独位于一个任务栈中

    在此模式下的Activity由以下特点:
    1. 具有全局唯一性,即整个系统中只会存在一个这样的实例
    2. 在整个系统中是单例的,如果在启动这样的Activity时,已经存在一个实例,那么会把它所在的任务调度到前台,重用这个实例
    3. 具有独占性,即它会独自占用一个任务栈,被它开启的Activity都会运行在其他任务栈中
    4. 能够在新的任务栈中启动,但不一定开启新的任务栈,也有可能在已有的任务栈中开启

启动模式的使用

  • 在AdnroidMainifest.xml 文件注册活动中设置

     
     
     
    
  • 在代码中指定启动模式

    Intent pack=new Intent(MainActivity.this,Main2Activity.class);
    pack.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    startActivity(pack);
    

Activity组件之间的通信

  • Activity之间的通信
    1. 类静态变量
    2. 全局变量
    3. Intent / Bundle
      Bundle bundle = new Budle();
      bundle.putString("data","数据");  
      
      Intent intent = new Intent(MainActivity.this,Main2Activity.class);
      intent.putExtras(bundle);
      startActivity(intent);
  • Activity与Service之间的通信
    1. 通过调用bindService()方法绑定服务
    2. 启动Service时通过传入Intent对象进行通信

    //在Activity中
      Intent intent = new Intent(MainActivity.this,MyService.class);
      intent.putExtra("data","数据");
      startService(intent); 
    //在Service中
      public int onstartCommand(Intent intent,int flags,int startId){
          String str=intent.getStringExtra("data");
          return super.onStartCommand(intent,flags,startId);
      }
    

    3. CallBack + Handler ,监听服务的进程变化

    Service中的代码:

    public class MyService  extends Service{
        public Callback callback;
    
        public MyService(){}
        
        @Override
        public IBinder onBind(Intent intent){
            return new Binder();
        }
    
        public void  setCallBack(CallBack callBack){
            this.callback = callBack;
        }
    
        public CallBack getCallBack(){
            return  callback;
        }
    
        public interface CallBack{
            void onDataChange(String data);
        }
    
        public class Binder extends android.os.Binder{
            public MyService getMyService(){
                return MyService.this;
            }  
        }
    

    Activity中的代码:

    public class MainActivity extends AppcompatActivity implements ServiceConnection{
    
       public MyService.Binder binder = null;
       private Handler handler = new Handler(){
       
            @Override
            public void handleMessage(Message msg){
                  super.handleMessage(msg);
                  Bundle bundle = msg.getData();
                  String data = budle.getString("data");
    
                  //接下来就是UI更新
            }  
       };
    
    
      @Override
      protected void onCreate(Bundle savedInstanceState){
           super.onCreate(savedInstanceState);
           setContentView(R.layout.activity_main);
      }
    
      @Override
      public void onServiceConnected(ComponentName componentName,IBinder iBinder){
          binder = (MyService.binder) iBinder;
          binder.getMyservice().setCallBack(new MyService.CallBack(){
                //此方法提供给MyService在子线程调用
                @Override
                public void onDataChange(String data){
                      Message message = new Message();
                      Bundle bundle = new Bundle();
                      bundle.putString("data","数据");
                      message.setData(bundle);
                      //通过handler进行异步通信,耗时操作应放在MyService中
                      handler.sendMessage(message); 
                }
          });
      }
      
      @Override  
      public void onServiceDisconnected(ComponentName componentName){
      
      }
    }
    
    • Activity 与 Fragment 之间的通信
      1. Bundle
      在创建 Fragment实例 的时候,调用setArguments()方法将一个Bundle对象传递给 Fragment ,然后在 Fragment 中先去判断是否和当前 Activity 绑定上了,如果绑定上了就可以拿出这个Bundle中的数据

      Activity中的代码:

      Bundle bundle = new Bundle();
      bundle.putString("data","数据");
      
      Fragment fragment = new MyFragment();
      fragment.setArguments(bundle);
      

      MyFragment中的代码:

      if(isAdded()){
      // isAdded()方法判断是否与Activity进行了绑定
      // 因为如果没有进行绑定的话,那么Bundle对象是无法从Activity传递给Fragment的
            Bundle bundle = getArguments();
            String data =bundle.getString("data");
      
      }
      

      2. 直接进行方法调用
      在Activity里通过Fragment的引用,可以直接调用Fragment中定义的任务方法

      MyFragment  myFragment = new MyFragment();
      myFragment.toString("数据");
      

scheme 跳转协议

Android中的一种跳转协议,通过自定义scheme协议,可以非常方便的跳转到app中的各个页面,通过该协议,服务器可以定制化告诉app跳转到哪个页面,可以通过通知栏消息定制化跳转页面,可以通过 H5 页面跳转到相应页面等。

你可能感兴趣的:(四大组件 - Activity)