Android四大组件-Activity


简介

Activity就是每一个应用的界面,凡事显示在app中的界面都是Activity或者由Activity启动。

基本使用

  • 使用as快捷建立Activity

  • 常规创建
  1. 在app/src/main/AndroidManifest.xml注册
  2. 编写java代码继承自Activity或者它的子类

自动创建的Activity如下所示:

就是一个activity的标签

传递数据

我们现在创建两个Activity由MainActivity向SecondActivity传递一个字符串“HelloWorld”

  • 在MianActivity中设置带有数据的intent

  • startActivityForResult启动activity,第二个参数是请求码
  • 重写onActivityResult接受数据

SecondActivity

        setResult(666);
        String hello = getIntent().getBundleExtra("hello").getString("nihao");

设置结果码--->拿到数据

完整代码

public class MainActivity extends AppCompatActivity {
​
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
//在按钮中注册的方法
    public void start(View view) {
        Intent intent = new Intent(MainActivity.this, SecondActivity.class);
        Bundle bundle = new Bundle();
        bundle.putString("nihao", "HelloWorld");
        intent.putExtra("hello", bundle);
        startActivityForResult(intent, 0);
    }
​
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        if (resultCode == 666) {
            System.out.println("世界你好");
        }
    }
}
​
​
​
public class SecondActivity extends AppCompatActivity {
​
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_second);
​
        setResult(666);
        String hello = getIntent().getBundleExtra("hello").getString("nihao");
​
        TextView textView = (TextView) findViewById(R.id.tv);
        textView.setText(hello);
    }
​
//在按钮中注册的方法
    public void finsh(View view) {
        this.finish();
    }
}

生命周期

  1. onCreate方法负责初始化数据、视图、绑定事件的监听
  2. onStart和onStop是从是否可见的角度分析
  3. onResume和onPause是从是否在前台的角度分析
  4. onStart可见不能获得焦点--->onResume可见能获得焦点---->onPause可见不能获得焦点---->onStop不可见不能获得焦点

Android官方周期

正常的生命周期

onCreate---->onStart------>onResume------>onPause----->onStop-----onDestory正好6个生命周期

异常生命周期

用户按主页键

然后再次返回这个activity:

突然来一个电话

生命周期和上面的一样

当要启动的另一个Activity主题色是透明的时候那么这时这个Activity不会调用onStop方法

也就是说它还可见,符合逻辑

系统配置改变比如说屏幕旋转

当前的Activity被销毁重新创建

在屏幕旋转的时候会调用onSaveInstanceState和onRestoreInstanceState用来保存和恢复组件的状态(注意as默认创建的Activity继承自AppCompatActivity,这里的两个方法要使用使用AppCompatActivity中的)

当状态改变调用onSaveInstanceState保存状态然后调用onRestoreInstanceState恢复状态:

旋转屏幕时状态分析

当屏幕发生旋转后数据会保存到savedInstanceState和onCreate方法中的savedInstanceState

protected void onRestoreInstanceState(Bundle savedInstanceState)

橙色线表示屏幕旋转

那么会保存view的哪些信息呢?这要看对应的view的onSaveInstanceState方法,比如EditText的正在编辑的信息就会丢失。

那么怎么屏蔽屏幕旋转的信息呢???

-----------------看法宝-------------------

只要在activity注册的时候加入configChanges标签就可以,注意假如是屏蔽旋转的话应该是orientation|screenSize两个属性

从此妈妈再也不用担心我的学习了,哈哈哈!!!!

锁屏和屏幕解锁

只是调用了onPause和onStop没有销毁Activity

可见性

activity的完整生存期会在 onCreate() 调用和 onDestroy() 调用之间发生。 

activity的可见生存期会在 onStart() 调用和 onStop() 调用之间发生。系统会在activity的整个生存期内多次调用 onStart() 和onStop(), 因为activity可能会在显示和隐藏之间不断地来回切换。 

activity的前后台切换会在 onResume() 调用和 onPause() 之间发生。 因为这个状态可能会经常发生转换,为了避免切换迟缓引起的用户等待,这两个方法中的代码应该相当地轻量化。

activity回收和保存信息

onSaveInstanceState方法

  在activity 可能被回收之前 调用,用来保存自己的状态和信息,以便回收后重建时恢复数据(在onCreate()或onRestoreInstanceState()中恢复)。旋转屏幕重建activity会调用该方法,但其他情况在onRause()和onStop()状态的activity不一定会调用 ,下面是该方法的文档说明。

系统灵活的来决定调不调用该方法,但是如果要调用就一定发生在onStop方法之前,但并不保证发生在onPause的前面还是后面。

onRestoreInstanceState方法

  这个方法在onStart 和 onPostCreate之间调用,在onCreate中也可以状态恢复,但有时候需要所有布局初始化完成后再恢复状态。

启动模式

就是启动Activity的方式:

只要在Activity中指定launchMode属性就可以完成启动模式的改变。

在上面的案例中我们从MainActivity到SecondActivity有木有发现不按下结束键只是返回也能返回到MainActivity,我擦MainActivty那家伙还活着呢??让我们探究下正常的启动模式

正常的启动模式

就是先启动的Activity先入栈,出栈是最后出栈,所以当SecondActivity死后,可以看见MianActivity,在MainActivity中添加一个不断重新启动自己的button

然后进入Terminal:adb shell 然后dumpsys activity

查看当前运行的activity:

每一个都在栈中。

新建一个Activity2项目在其中只是设置一个按钮,启动Activity项目中的MianActivity:

发现Activity中的Mian在项目2的栈内,于是有一个结论:

正常模式启动的Activity,谁启动它,它就在那一个栈

跨应用启动Activity代码

    Intent intent = new Intent();
    intent.setClassName("win.haotinayi.activity","win.haotinayi.activity.MainActivity");

就是设置包名,在设置Activity的全名

SingleTop

就是当要启动的Activity恰好在栈顶的时候,那么就不再重复创建:

无论怎么启动都只有一个实例。

SingleTask

栈内单例模式,分为三种情况:

  1. 当有Activity需要的栈时,并且是栈顶,啥也不说了,直接复用
  2. 当有Activity需要的栈时,并且不是栈顶,那么在它上面的全部干掉,自己当大哥
  3. 当没有Activity需要的栈时,创建栈

把MianActivity设置成SingleTask模式,首先打开Activity项目,让两个Activity同时存在:

并且MianActivity不是栈顶,然后在通过Activity2打开MainActivity:

SecondActivity被干掉了,大哥是MianActivity,那么什么是Activity的需要栈呢?默认是包名

使用属性taskAffinity可以改掉,现在来一个恶作剧:

这时再次启动项目发现,项目的栈改变了:

SingleInstance

Activity只能单独存在一个栈中,换句话说就是整个手机就你一个实例

使用Intent来标示启动模式

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

标志的分类

  • FLAG_ACTIVITY_NEW_TASK

  与"singleTask"模式相同,在新的 task 中启动 activity。如果要启动的 activity 已经运行于某 task 中,则那个 task 将调入前台。

  • FLAG_ACTIVITY_SINGLE_TOP

  与 "singleTop"模式相同,如果要启动的 activity位于back stack 顶,系统不会重新创建目标Activity实例,而是直接复用Task栈顶的Activity。

  • FLAG_ACTIVITY_CLEAR_TOP

  此种模式在launchMode中没有对应的属性值。如果要启动的 activity 已经在当前 task 中运行,则不再启动一个新的实例,且所有在其上面的 activity 将被销毁。

Activity优先级

从高到低排序:

  1. 显示且能获得焦点(前台)的Activity
  2. 显示不能获得焦点(非前台),一个打开Dialog的Activity
  3. 不可见,已经处于暂停或者直接onStop后的Activity

当内存不足的时候低优先级的Activity就会被杀掉,如果一个组件没有放在四大组件中,那么很快被杀死,所以后台任务最好放到一个四大组件中,防止被干掉。

注意

Activity的全屏

        // 去除标题栏
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        setContentView(R.layout.activity_main);
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);

requestWindowFeature要在setContentView调用之前否则会崩溃

Activity的公开性

一般设置Activity为非公开的  

<activity  
...... 
android:exported="false" />

注意:非公开的Activity不能设置intent-filter,以免被其他activity唤醒(如果拥有相同的intent-filter)。


It's time for you to begin thinking out of the box