Android四大组件之Activity

提到Android原生开发,使用最多的当属activity和xml。今天我也来聊聊他。

大纲如下图:

image.png
1,activity是什么?

activity的中文含义为“活动”,作用是app用他来与用户产生交互。简单理解他就是安卓app中与用户交互的一个个页面。注意,每一个activity都有自己独立的状态和生命周期。

2,activity的基本状态?

activity有四大基本状态。分别是活动状态——暂停状态——停止状态——销毁状态。和人一样,从出生到死亡。activity是从创建(onCreate())到销毁(onDestroy())。

活动状态

指用户可以与之交互的状态。触发 onResume()后的状态。

暂停状态

指用户任然可见当前activity,但是不能与之交互的状态。触发 onPuased()后的状态。

停止状态

指用户与当前activity不可见(不能与之交互)的状态。触发 onStop()后的状态。

销毁状态

指当前activity被销毁的状态。触发 onDestroy()后的状态。

3,activity的生命周期?

activity的生命周期图如下所示:


image.png

(声明:以下常用和不常用指在activity中覆写(@Override)次数)

onCreate()

生命周期中最常用的回调方法之一。通常在这里做的操作有:1,设置布局:setContentView(R.layout.login);,2,初始化:比如适配器的初始化,比如list的初始化等。3,数据接收。比如从别的activity有intent的传值。需要在当前页面接收的。Intent intent = getIntent(); String aaa==intent.getIntExtra("mmm",0);,4,网络数据请求。比如当前页面是一个列表,可以在onCreate()中请求网络,然后赋值。

onStart()

不常用的回调方法。一般在activity A启动activity B后,B回到A需要做初始化的操作,可以放在这里。

onResume()

不常用的回调方法。

onPause()

不常用的回调方法。

onStop()

不常用的回调方法。

onRestart()

不常用的回调方法。

onDestroy()

生命周期中最常用的回调方法之一。和onCreate()一样,一般是activity中必覆写的两个方法之一。通常操作有:1,资源的回收或者释放。比如使用了广播,需要在这里回收,避免内存泄露。2,如果使用了eventbus,需要在这解除绑定EventBus.getDefault().unregister(this);3,一些页面关闭的时候需要停止的其他操作。

页面跳转生命周期的变化

为了很好的验证页面生命周期的变化,我写了三个测试类(TestLive1Activity和TestLive2Activity和TestLive3Activity),如下:


TestLive1Activity.png

TestLive2Activity.png

TestLive3Activity.png

代码分别如下:

package com.mumu.mmcommon;

import android.annotation.SuppressLint;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.text.TextUtils;
import android.util.Log;
import android.view.View;
import android.widget.Button;

import androidx.annotation.Nullable;

import com.mumu.common.base.BaseActivity;
import com.mumu.dialog.MMAlertDialog;

import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;

/**
 * @author : zlf
 * date    : 2019/8/30
 * github  : https://github.com/mamumu
 * blog    : //www.greatytc.com/u/281e9668a5a6
 * desc    :
 */
public class TestLive1Activity extends BaseActivity {
    @BindView(R.id.button_live1_b1)
    Button buttonLive1B2;
    @BindView(R.id.button_live1_b2)
    Button buttonLiveB2;
    @BindView(R.id.button_live1_b3)
    Button buttonLive1B3;
    @BindView(R.id.button_live1_b4)
    Button buttonLive1B4;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_test_live1);
        ButterKnife.bind(this);
        Log.d("mmm", "onCreate1");
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        Log.d("mmm", "onDestroy1");
    }

    @Override
    protected void onResume() {
        super.onResume();
        Log.d("mmm", "onResume1");
    }

    @Override
    protected void onPause() {
        super.onPause();
        Log.d("mmm", "onPause1");
    }

    @Override
    protected void onStop() {
        super.onStop();
        Log.d("mmm", "onStop1");
    }

    @Override
    protected void onStart() {
        super.onStart();
        Log.d("mmm", "onStart1");
    }

    @Override
    protected void onRestart() {
        super.onRestart();
        Log.d("mmm", "onRestart1");
    }

    @OnClick({R.id.button_live1_b1, R.id.button_live1_b2, R.id.button_live1_b3, R.id.button_live1_b4,R.id.button_live1_b5})
    public void onViewClicked(View view) {
        switch (view.getId()) {
            case R.id.button_live1_b1:
                Log.d("mmm", "当前页面为live1,跳转到live2页面");
                startActivity(new Intent(TestLive1Activity.this, TestLive2Activity.class));
                break;
            case R.id.button_live1_b2:
                Log.d("mmm", "当前页面为live1,关闭当前页面");
                finish();
                break;
            case R.id.button_live1_b3:
                Log.d("mmm", "当前页面为live1,展示一个弹窗");
                MMAlertDialog.showDialogImage(TestLive1Activity.this, "https://wx1.sinaimg.cn/mw690/0074tCa2gy1g4alozlyk8j31301tbaou.jpg", false,
                        new DialogInterface.OnClickListener() {
                            @Override
                            public void onClick(DialogInterface dialogInterface, int i) {
                                dialogInterface.dismiss();
                            }
                        }, new DialogInterface.OnClickListener() {
                            @Override
                            public void onClick(DialogInterface dialogInterface, int i) {
                                dialogInterface.dismiss();
                            }
                        });
                break;
            case R.id.button_live1_b4:
                Log.d("mmm", "当前页面为live1,展示一个loading");
                showLoading();
                updateHandler.sendEmptyMessageDelayed(1, 5000);
                break;
            case R.id.button_live1_b5:
                Log.d("mmm", "当前页面为live1,跳转到live3页面");
                startActivity(new Intent(TestLive1Activity.this, TestLive3Activity.class));
                break;
        }
    }

    @SuppressLint("HandlerLeak")
    private Handler updateHandler = new Handler() {
        @Override
        public void dispatchMessage(Message msg) {
            super.dispatchMessage(msg);
            if (msg.what == 1) {
                hideLoading();
            }
        }
    };
}

package com.mumu.mmcommon;

import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;

import androidx.annotation.Nullable;

import com.mumu.common.base.BaseActivity;

import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;

/**
 * @author : zlf
 * date    : 2019/8/30
 * github  : https://github.com/mamumu
 * blog    : //www.greatytc.com/u/281e9668a5a6
 * desc    :
 */
public class TestLive2Activity extends BaseActivity {
    @BindView(R.id.button_live2_b1)
    Button buttonLive2B1;
    @BindView(R.id.button_live2_b2)
    Button buttonLive2B2;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_test_live2);
        ButterKnife.bind(this);
        Log.d("mmm", "onCreate2");
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        Log.d("mmm", "onDestroy2");
    }

    @Override
    protected void onResume() {
        super.onResume();
        Log.d("mmm", "onResume2");
    }

    @Override
    protected void onPause() {
        super.onPause();
        Log.d("mmm", "onPause2");
    }

    @Override
    protected void onStop() {
        super.onStop();
        Log.d("mmm", "onStop2");
    }

    @Override
    protected void onStart() {
        super.onStart();
        Log.d("mmm", "onStart2");
    }

    @Override
    protected void onRestart() {
        super.onRestart();
        Log.d("mmm", "onRestart2");
    }

    @OnClick({R.id.button_live2_b1, R.id.button_live2_b2})
    public void onViewClicked(View view) {
        switch (view.getId()) {
            case R.id.button_live2_b1:
                Log.d("mmm", "当前页面为live2,跳转到live1页面");
                startActivity(new Intent(TestLive2Activity.this, TestLive1Activity.class));
                break;
            case R.id.button_live2_b2:
                Log.d("mmm", "当前页面为live2,关闭当前页面");
                finish();
                break;
        }
    }
}
package com.mumu.mmcommon;

import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;

import androidx.annotation.Nullable;

import com.mumu.common.base.BaseActivity;

import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;

/**
 * @author : zlf
 * date    : 2019/9/2
 * github  : https://github.com/mamumu
 * blog    : //www.greatytc.com/u/281e9668a5a6
 * desc    :
 */
public class TestLive3Activity extends BaseActivity {
    @BindView(R.id.button_live3_b1)
    Button buttonLive3B1;
    @BindView(R.id.button_live3_b2)
    Button buttonLive3B2;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_test_live3);
        ButterKnife.bind(this);
        Log.d("mmm", "onCreate3");
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        Log.d("mmm", "onDestroy3");
    }

    @Override
    protected void onResume() {
        super.onResume();
        Log.d("mmm", "onResume3");
    }

    @Override
    protected void onPause() {
        super.onPause();
        Log.d("mmm", "onPause3");
    }

    @Override
    protected void onStop() {
        super.onStop();
        Log.d("mmm", "onStop3");
    }

    @Override
    protected void onStart() {
        super.onStart();
        Log.d("mmm", "onStart3");
    }

    @Override
    protected void onRestart() {
        super.onRestart();
        Log.d("mmm", "onRestart3");
    }

    @OnClick({R.id.button_live3_b1, R.id.button_live3_b2})
    public void onViewClicked(View view) {
        switch (view.getId()) {
            case R.id.button_live3_b1:
                Log.d("mmm", "当前页面为live3,跳转到live2页面");
                startActivity(new Intent(TestLive3Activity.this, TestLive2Activity.class));
                break;
            case R.id.button_live3_b2:
                Log.d("mmm", "当前页面为live3,关闭当前页面");
                finish();
                break;
        }
    }
}
1,当我从MainActivity第一次跳转到TestLive1Activity的时候,TestLive1Activity的生命周期如下:
第一次跳转到TestLive1Activity.png
2,当我点击关闭当前页面(live1)的时候,生命周期变化如下:
关闭当前页面(live1).png
3,当我再次进入live1,然后点击按钮跳转到live2页面的时候,生命周期变化如下:
跳转到live2页面.png
4,当我点击关闭当前页面(live2)的时候,生命周期变化如下:
关闭当前页面(live2).png
5,当前处于live1页面,再次点击关闭当前页面(live1)的时候,生命周期变化如下:
关闭当前页面(live1).png

由此可以看出,activity的生命周期。

6,当前处于live1页面,点击展示一个弹窗的时候,生命周期变化如下:
展示一个弹窗.png

说明,弹窗的打开和关闭并不影响当前activity的生命周期。

7,当前处于live1页面,点击展示一个loading的时候,生命周期变化如下:
展示一个loading.png

说明,loading的打开和关闭并不影响当前activity的生命周期。

8,当前处于live1页面,点击打开一个透明的activity3的时候,生命周期变化如下:
打开一个透明的activity3.png

将该条与第三条对比,可以看出activity1处于暂停状态(onPause1),然后activity3创建了,直到onResume3,正常情况应该是activity1走onStop()的回调方法。但是没有。因为打开的activity3是透明的,这个时候activity1还是可见状态,只是页面的焦点在activity3身上,不在activity1身上,所以activity1处于暂停状态。

9,现在处于activity3页面,点击关闭当前页面(live3)的时候,生命周期变化如下:
关闭当前页面(live3).png

可以看出activity3关闭后回到activity1页面,activity1重新获取焦点,执行onResume()方法。然后activity3被销毁。

10,我再重新打开activity3页面,点击当前页面live3,跳转到live2页面的时候,生命周期变化如下:
image.png

因为live2页面不是透明的页面,可以看出,live3走了onPause()的方法,然后开始创建activity2页面,activity2页面获取焦点后,activity1和activity3因为不可见,所都走了onStop()的回调方法。

11,现在是activity2页面上,点击关闭当前页面(live2)后,生命周期变化如下:
关闭当前页面(live2).png

可以看出,activity2执行onPause2后,activity1和activity3都执行了onRestart方法,但是只要activity3执行了onResume3,为什么呢?因为当前的焦点在activity3上,activity1是可见,但是无法交互的状态。如下图:


image.png
4,activity的后台堆栈?

在讲activity的启动模式之前,应该先了解这个。


盗的图.png
1,activity后台堆栈遵循先进后出的原则。
2,如图,activity的后台堆栈可以比作是一个圆桶,activity可以比作是一张张饼,圆筒的面积刚好存放一张饼。我第一个放进去的饼是在桶的最底部的。然后一张张饼放进去。最后放进去的就在圆桶的最上面。要想把最底部的一张饼拿出来,就要把上面的饼一张张拿出来。才可以拿最后的那一张饼。。activity也是一样的。
3,activity后台堆栈是app一开始有了第一个activity的时候就一同创建的。当这第一个activity被移除的时候,堆栈中就没有activity了,这个时候app也就退出了。
5,activity的启动模式?

activity有四种启动模式,分别是:standard,singleTop,singleTask,singleInstance。

1,standard(标准模式——默认启动模式)

每一个activity被创建的时候,都有一个标签,就是启动模式。默认情况下,activity的启动模式是standard。该模式下,新建的activity会遵循先进后出的原则一个个的被放进堆栈中。不会判断该activity是否已经存在于栈内。

2,singleTop(栈顶复用模式)

如果新建的activity的启动模式是该模式,那么在他不会发生跳转。举例:activity A(standard模式)跳转到activity B(singleTop模式),再由activity B跳转到activity B,那么不会发生新的跳转。如果activity A跳转到activity A,则可以跳转,因为在activity A跳转到activity A的时候,后一个activity A是新建的另一个,这时候栈内有两个activity A。

3,singleTask(栈内复用模式)

如果新建的activity的启动模式是该模式,那么在另一个activity打开该activity的时候,会检测该activity是否在栈内,如果在,则直接弹出栈内的那个activity的上面的所有activity,并打开该activity,如果不在则新建一个放入栈顶。

4,singleInstance(全局唯一模式)

如果新建的activity的启动模式是该模式,那么在另一个activity打开该activity的时候会为该activity新建一个堆栈,然后将该activity放入该栈内。如果这时候有跳转到一个非该模式的activity后,堆栈会发生改变,再次跳转到该activity的时候,如果该activity没有被销毁,那么会重新唤醒该堆栈,打开该activity。

5,activity的启动模式该如何设置呢?

一种是在AndroidManifest.xml中对应的activity下设置,如下图:


image.png

另一种是在跳转的时候的代码中增加,如下图:


image.png
6,activity的跳转与传值?

一般来说,activity的跳转有三种:显示跳转,隐式跳转,和arouter跳转

1,显示跳转
//                //显示跳转1
//                startActivity(new Intent(TestLive3Activity.this, TestLive2Activity.class));
//                //显示跳转2
//                Intent intent=new Intent(TestLive3Activity.this, TestLive2Activity.class);
//                startActivity(intent);
//                //显示跳转3
//                Intent intent=new Intent();
//                intent.setClass(TestLive3Activity.this, TestLive2Activity.class);
//                startActivity(intent);
//                //显示跳转4—带返回值
//                Intent intent=new Intent();
//                intent.setClass(TestLive3Activity.this, TestLive2Activity.class);
//                startActivityForResult(intent,111);
2,隐式跳转
//先在manifest中配置action
<activity
            android:name=".TestLive2Activity"
            android:launchMode="standard"
            android:screenOrientation="portrait">
            <intent-filter>
                <action android:name="live2" />
                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>
        </activity>
//再在跳转的时候设置action
Intent intent=new Intent();
                intent.setAction("live2");
                startActivity(intent);
3,arouter跳转(阿里路由框架,适用于不同包名下的activity的跳转)

具体使用可参考我如下文章:

7,activity和fragment的关系?

fragment依附于activity,并有自己的生命周期,面试的时候经常被问到fragment的生命周期,说实话,记不住。activity和fragment的关系和使用以及跳转,传值等等我会后面单独用一篇文章来讲解。这里不做过多描述。

如果有发现错误欢迎指正我及时修改,如果有好的建议欢迎留言。如果觉得对你有帮助欢迎给小星星,谢谢。
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,968评论 6 482
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,601评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 153,220评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,416评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,425评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,144评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,432评论 3 401
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,088评论 0 261
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,586评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,028评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,137评论 1 334
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,783评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,343评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,333评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,559评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,595评论 2 355
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,901评论 2 345

推荐阅读更多精彩内容