安卓基础组件学习之Activity
这是我参与「第四届青训营 」笔记创作活动的第2天
前言
如果看过我之前的文章,可能了解我的一个情况,就不再重述。今天是第二天吧,首先来看看老师今天讲了什么。
- 安卓基础组件
- Activity
- Fragment
- Service
- Broadcast
- ContentProvider
- Android通信组件
- Handler
- Binder
如果想要一次性消化这么多东西是不可能的,这里我们首先来看看Activity,这个东西对我来说并不是很陌生,但对它的理解和认知是肤浅的,在这次课程中也是对它有了更清晰的了解和认知。下面我总结下自己的认识和一些细节,更适合和我一样基础薄弱的人看,如果有错误欢迎大家指出。
什么是Activity
在这节课后我有了一些简单的认识
界面交互
Activity充当着代码和用户交互的任务,我们随便打开一个APP,可以发现它是有一个界面的,那么这个界面就是一个Activity,我们总需要有一个东西让用户不接触到代码,而是代码实现的效果,那么Activity就可以满足这个需求。
布局容器
对于我们而言,创作一个APP是需要一个页面来展示它的,显然布局仅仅是XML文件,我们需要有一个东西使得这个布局的XML文件展示给用户看,此时Activity就可以担起这个责任,绑定布局文件,将布局文件展示在用户面前。
为什么要有Activity
下面是我的个人理解,有问题欢迎指出。
哈哈,好像有点废话,Android也是一个有图形界面的操作系统,如果不是特殊需求,好像我们日常使用APP都要有个界面,我们希望的是通过可视化的界面来享受或者使用程序提供的服务,如果可以,我是会优先选择有图形界面的程序,这已经形成了习惯的。
所以为了让用户能更形象的使用程序,我们需要给用户去展示一个界面,因此我们的程序才需要Activity。
怎么样去使用Activity
我们首先来创建一个APP,这个要使用Android studio。
如图,这个是一个最简单的空白项目,首先打开MainActivity,我们发现它继承了AppCompatActivity,这是个什么东西???
我们按住Ctrl点击AppCompatActivity,结果发现它又继承了FragmentActivity,按照此方法,一直查看它,我们会发现他是继承了Activity的。
因此,在这里我们说的Activity也可以是AppCompatActivity,今后我们开发,更多的是去用AppCompatActivity,而不是直接继承Activity。
那么布局是怎么放进这个容器里并且展示的呢?
我们注意到了setContentView(R.layout.activity_main);,这里其实就是我们的布局文件,那么如果我们去新创建一个类,继承AppCompatActivity,想要换布局,仅仅改动这个布局文件的名称就可以啦。
打开软件会先展示activity_main的布局,也就是启动MainActivity这个类,那么现在我们想在这个页面里弄个按钮,点击后跳转到另一个页面,这样还能体验一下自己创建新activity。
这里我们创建一个新的类,叫BActivity,并且继承AppCompatActivity,留作备用,我们得给他一个布局是不是?那么我们现在再来创建一个布局,就叫activity_b吧。
创建好之后先不动,我们把MainActivity的onCreate方法抄过来(复制粘贴),但是改下布局文件为activity_b,这样我们的准备工作就好了。
但是现在我们还不能去启动这个Activity类,得先完成下注册。
注册
Activity是需要注册的,相信在课堂上你已经听说了,那么我们简单来看看,注册一个新的,实际体验一把这个东西吧。
在课程上相比你已经知道,AndroidManifest.xml里边已经有一个默认的activity了,这个标签里的name发现是MainActivity,除此之外里边还有个intent-filter标签,里边规定了这个类是启动入口,也就是当APP打开时会先打开这个类的页面。
那么我们仿照一个吧?
但是这时就暂时不需要intent-filter标签了,我们直接这么写<activity android:name=".BActivity"/>,就跟在上一个activity标签后面。
这样我们就完成了Activity的注册,这个东西听起来是比较虚的,需要动手试一试,这种新奇感是很不错的。
备用
在体验页面跳转之前,我们先来了解一下,Activity生命周期,这个完事了,我们再来使用刚刚创建的BActivity。
Activity生命周期
生命周期可能有点抽象,我的理解就是一个Activity类,从运行到彻底结束,期间会经历的一些阶段。
老师已经给我们讲过了,如果你和我一样,可能基础比较薄弱,这时可能就在想,知道这玩意做什么?我当时也是这么想的,但其实慢慢的发现,这个很重要,会让你的程序更加细节。
伏笔?
我们的大项目是做个极简版抖音,我们发现切换页面视频会暂停,切换回来又要继续播放,这里其实也会用到生命周期的方法。
正常的生命周期
这个叫法是我在其他文章里看到的,也就是正常情况下一个Activity类会经历的过程。
图片是我们学员手册里的,我英语不太好,不懂图片里的解释。
所以我们按照这份中文文档来看看,现在我们去MainActivity,实现一下这些方法。
public class MainActivity extends AppCompatActivity {
protected String TAG = "A_Activity";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.i(TAG,"onCreate");
}
@Override
protected void onRestart() {
super.onRestart();
//onStop后恢复显示前onRestart
Log.i(TAG,"onRestart");
}
...............省略其他方法,自行补充
}
Log.i(TAG,"onResume");是打印日志,帮助我们观察这个方法是否执行了。
当APP启动后马上打印出来了这三个方法里的日志,这对应着流程表上的前三步。
现在我们把APP返回到桌面上来
发现它执行了onPause()和onStop()
诶,为什么会这样呢?显然我们的大返回是个过程,界面是一部分一部分消失的,这个过程就造成了activity的部分被遮挡,导致了onPause()被触发。
现在我们在APP后台打开它。
I/A_Activity: onRestart
I/A_Activity: onStart
I/A_Activity: onResume
这时就对上我们前面的流程了,因为acitiviy此时是onStop(),但返回展示视图时就执行onRestart()
特别的生命周期
onSaveInstanceState()和onRestoreInstanceState()
他们是当Activity出现非正常关闭时调用的,分别是保存数据和恢复数据。
这里我们也体验一把。按照上面方式覆写这两个方法,覆写后我们发现是利用Bundle来储存数据的。
如图,我们在MainActivity里写了这两个方法,我们就选取这个旋转屏幕测试
按照课上的说法没有配置旋转时,这样会导致重建Activity,事实上也是如此,我们看下图。
我们注意到这里销毁了,然后重新创建了MainActivity,同时也把临时存储的数据输出了。
还有很多方法这里就不演示了。
Activity启动
在执行这个操作之前,我们先来给页面做个按钮。现在我们打开activity_main的布局文件,在里边设置一个/两个button。
点击按钮准备
<Button
android:id="@+id/AActivity_Button1"
android:text="跳转 A Activity"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
</Button>
当我们输入 <B 就会发现有提示,按照提示生成就可以啦,这里我有两个按钮,所以会做两个ID。 这样还没完事,我们需要给他设置监听点击事件。
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button button1 = findViewById(R.id.AActivity_Button1);
button1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
}
});
......第二个按钮仿照写
}
如此,我们在MainActivity里为button设置了一个点击事件,仍然备用。
启动模式
Activity启动模式有很多种,这里我想挨个体验一圈。
standard模式
<activity
android:name=".BActivity"
android:launchMode="standard" />
像是这样launchMode可以设置不同的启动方式,这里第一次测试,我给BActivity和MainActivity都如此设置。
这里我直接使用显式启动
我们把两个按钮的点击事件这样设置一下,然后运行
视频操作:我点击第一个按钮,再点击第二个按钮。
因为GIF压缩了下,导致这个点第一个按钮的跳转动画看不到了,实际上是跳转了的。
那么我需要返回几次才能退出APP? 答案是3次
我们来看看栈里
通过刚刚的操作,我们向任务栈里共加入了3个实例,就是MainActivity,MainActivity,BActivity
可见,standard模式无论如何都会创建一个新的Activity放在栈顶。
SingleTop模式
栈顶复用,我们把BActicity的模式换为SingleTop
点击第一个按钮,点击第一个按钮,点击第二个按钮
猜猜退出需要几次? 答案是2次
当Acticity模式为SingleTop,而且位于栈顶时,再启动这个Acticity时就不会再创建了,而是去复用当前Acticity,同时还会调用onNewIntent()。
但如果这样启动,A打开B,B打开A,就又可以复用了。
如此,老师总结的不能连续复用就是这个意思
SingleTask模式
不允许同个栈内重复这个是老师课上总结的
我们来尝试
给BActivity也设置两个按钮,功能和MainActivity里一样,让他们具备相互跳转的能里 然后我们给BActivity换为SingleTask模式,MainActivity为standard。
进行下面的操作
点击按钮2,点击按钮1,点击按钮1,点击按钮2,点击按钮1
现在猜猜需要几次返回? 答案是3次
实际上刚刚一堆跳转,最后栈里只有这几个实例。
这就是站内复用
点击按钮2,点击按钮1,点击按钮1,点击按钮2
再次点击按钮2时发现BActivity栈里有,于是就会把挡住这个BActivity的实例从栈里销毁释放,此时BActivity就暴露出来显示给用户,那么我们最后又点击了 点击按钮1 这样就会在BActivity上再创建MainActivity,因为MainActivity的模式是standard。
结尾
好啦这就是我今天的收获,如果有错误欢迎指出来。