美文网首页
四大组件 - Activity

四大组件 - Activity

作者: 吕注意 | 来源:发表于2019-07-16 16:29 被阅读0次

    定义

    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 文件注册活动中设置

       <activity
         android:name=" .MainActivity "
         .....
         <android:launchMode=" singleInstance ">
       
       </activity>
      
    • 在代码中指定启动模式

      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

          本文链接:https://www.haomeiwen.com/subject/ggezkctx.html