提到Android原生开发,使用最多的当属activity和xml。今天我也来聊聊他。
大纲如下图:
1,activity是什么?
activity的中文含义为“活动”,作用是app用他来与用户产生交互。简单理解他就是安卓app中与用户交互的一个个页面。注意,每一个activity都有自己独立的状态和生命周期。
2,activity的基本状态?
activity有四大基本状态。分别是活动状态——暂停状态——停止状态——销毁状态。和人一样,从出生到死亡。activity是从创建(onCreate())到销毁(onDestroy())。
活动状态
指用户可以与之交互的状态。触发 onResume()后的状态。
暂停状态
指用户任然可见当前activity,但是不能与之交互的状态。触发 onPuased()后的状态。
停止状态
指用户与当前activity不可见(不能与之交互)的状态。触发 onStop()后的状态。
销毁状态
指当前activity被销毁的状态。触发 onDestroy()后的状态。
3,activity的生命周期?
activity的生命周期图如下所示:
(声明:以下常用和不常用指在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),如下:
代码分别如下:
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的生命周期如下:
2,当我点击关闭当前页面(live1)的时候,生命周期变化如下:
3,当我再次进入live1,然后点击按钮跳转到live2页面的时候,生命周期变化如下:
4,当我点击关闭当前页面(live2)的时候,生命周期变化如下:
5,当前处于live1页面,再次点击关闭当前页面(live1)的时候,生命周期变化如下:
由此可以看出,activity的生命周期。
6,当前处于live1页面,点击展示一个弹窗的时候,生命周期变化如下:
说明,弹窗的打开和关闭并不影响当前activity的生命周期。
7,当前处于live1页面,点击展示一个loading的时候,生命周期变化如下:
说明,loading的打开和关闭并不影响当前activity的生命周期。
8,当前处于live1页面,点击打开一个透明的activity3的时候,生命周期变化如下:
将该条与第三条对比,可以看出activity1处于暂停状态(onPause1),然后activity3创建了,直到onResume3,正常情况应该是activity1走onStop()的回调方法。但是没有。因为打开的activity3是透明的,这个时候activity1还是可见状态,只是页面的焦点在activity3身上,不在activity1身上,所以activity1处于暂停状态。
9,现在处于activity3页面,点击关闭当前页面(live3)的时候,生命周期变化如下:
可以看出activity3关闭后回到activity1页面,activity1重新获取焦点,执行onResume()方法。然后activity3被销毁。
10,我再重新打开activity3页面,点击当前页面live3,跳转到live2页面的时候,生命周期变化如下:
因为live2页面不是透明的页面,可以看出,live3走了onPause()的方法,然后开始创建activity2页面,activity2页面获取焦点后,activity1和activity3因为不可见,所都走了onStop()的回调方法。
11,现在是activity2页面上,点击关闭当前页面(live2)后,生命周期变化如下:
可以看出,activity2执行onPause2后,activity1和activity3都执行了onRestart方法,但是只要activity3执行了onResume3,为什么呢?因为当前的焦点在activity3上,activity1是可见,但是无法交互的状态。如下图:
4,activity的后台堆栈?
在讲activity的启动模式之前,应该先了解这个。
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下设置,如下图:
另一种是在跳转的时候的代码中增加,如下图:
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的关系和使用以及跳转,传值等等我会后面单独用一篇文章来讲解。这里不做过多描述。