每一个Activity组件都是一个单独的界面,承载着与用户交互的任务。也是应用最基本的功能之一,在不同界面之间切换,并实现不同的功能。
每一个程序必须要有一个Activity作为入口(Manifest文件中将其<category>标签设置为LAUNCHER),然后通过界面控制到达其他的界面。
Activity是具有生命周期的,在不同生命周期会执行其中回调方法。所有的方法在自己的Activity中可以进行重写。安卓中添加新的Activity可以通过AS进行选择新建不同的类型,以减少部分代码量。
下面的文章中对Activity做了不错的介绍。并通过简单的LOG打印日志可以清晰看到各执行Activity和切换Activity的执行顺序。
参考:https://www.cnblogs.com/caobotao/p/4987015.html
配合下面官方给的生命周期图,对Activity做一个初步的理解。
1.当我们打开一个Activity,执行onCreated方法,进入created(已创建)状态,这时候大概会去内存中将Activity类需要的资源全部申请成功。
2.第二步会接着执行onStart方法,进入started(已启动)状态。这时候我们便可以看到这个界面,但是是无法进行操作的,这时候整个界面已经渲染完成。
3.第三步执行onResume方法,进入resumed(Resume有重新开始,继续的意思,然而在第一次创建时并没有继续,重新,所以个人认为用focused(已获取焦点)或running(运行中)似乎更恰当)状态,此时获取了应用的焦点,我们才能对界面进行操作,至此Activity才算是正常的启动并提供服务了,若没有其他操作应用将保持此状态。
以上三步是Activity创建后固定顺序执行的步骤对应三个状态。在图片中有个状态转换需要调用的方法名,可以认为调用控制Activity的生命状态。
4.paused(暂停)状态。官方定义是partially visible(部分可见)。即界面被遮挡了,并且未全部遮挡,比如一些弹框等。此时遮挡界面将会获得应用的焦点,而原本的界面失去焦点无法操作,此时界面显示的渲染依然都在。
5.stopped(停止)状态。官方定义是hidden(隐藏的)。当界面被完全覆盖时,前台渲染已经销毁了,只有内存中Activity的对象等还存在。
6.Destroyed(已销毁的)状态。销毁的执行大致有三种情况:1.系统内存不足时自动销毁停止,暂停状态的Activity. 2.调用finish()方法。销毁时会根据当前状态顺序执行 onPause()->onStop->onDestroy(),如处于stopped状态就只调用onDestroy。
对于Activity的生命周期必须进行管理,否则很容易发生OOM(Out of memory)的异常。比如频繁切换(startActivity()方法),10次左右就会发生OOM,导致程序奔溃(模拟器会停止运行,使用真机调试会报错,到不影响程序运行)。
Activity界面切换使用方法startActivity (Intent intent)。
基本的写法就是 startActivity(new Intent(ActivityBefore.this, ActivityAfter.class)); ActivityBefore就是切换前的Activity类,ActivityAfter是切换后的目标Activity类。
在进行Activity切换时需要对Activity生命周期进行管理避免造成OOM。在不再需要使用的Activity中调用finish函数,销毁并收回占用的内存及资源。
需求中数字选择界面可以选择1到9,选择进入书写界面,书写界面有返回按钮,点击后调用startActivity切换回数字选择界面。此时若进入数字1书写界面,然后返回数字选择界面,然后重复选择剩余数字切换界面,在切换第九个数字时便会出现OOM异常。内存情况如下。每次新点开一个数字书写界面,内存会不断被占用而不被释放,最终导致内存溢出。
因为从数字书写界面返回后,我们可以认为此界面不会再被使用,因为此界面没有任何信息需要储存,重新选择进入时我们只需要重新创建即可,此时避免Activity切换造成的内存溢出可以做两种处理:
1.在调用startActivity进行切换后,调用finish()函数,将不需要使用的Activity销毁,此时会根据Activity当前状态去选择执行pause,stop,destroy函数,如处于stopped状态就只调用onDestroy。。
2.若使用手机自带返回事件,如返回键,触发后会顺序执行pause,stop,destroy三个函数,对Activity进行销毁。
安卓使用任务栈管理Activity,startActivity的作用是将另一个Activity放置到栈顶,当前Activity并未销毁,而是位于栈顶第二位,此时按下返回键便可以重回栈顶。而使用finish(),则会将其移出栈,按下返回键也无法返回。
参考:https://www.cnblogs.com/whieenz/p/8047139.html
管理Activity时,还需要注意Activity中对象的回收,如bitmap,thread,handler等等,避免Activity无法被正常回收。
此部分内容还未细究
可参考:https://blog.csdn.net/chen825919148/article/details/23843049
为了很好的监测内存溢出的情况,使用LeakCanary进行监测。而其使用也非常简单。
1.在Module的build.gradle文件中增加依赖包,此时要重新build项目。
dependencies {
.......//其他依赖包
debugCompile 'com.squareup.leakcanary:leakcanary-android:1.5.4'
releaseCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.5.4'
}
2.自定义Application类。
若LeakCanary引用有问题,则build发生异常,尝试重新build即可,使用就只要在1中添加依赖就可以,不需要其他任何操作。自定义Application类后,在Manifest文件中<application>标签中的 android:name 属性 更改为自定义类,如 android:name=“com.example.wangjy.application.App”
import com.squareup.leakcanary.LeakCanary;
import com.squareup.leakcanary.RefWatcher;
public class App extends Application {
private RefWatcher refWatcher;
@Override
public void onCreate() {
// 程序创建的时候执行
super.onCreate();
refWatcher = LeakCanary.install(this);
}
public static RefWatcher getRefWatcher(Context context){
App application = (App)context.getApplicationContext();
return application.refWatcher;
}
}
3.进行调用
在需要监测的Activity中增加
RefWatcher refWatcher = App.getRefWatcher(this);
refWatcher.watch(this);
为了方便使用,可以使用继承,在父类中进行监测。
最后关于Activity之间的参数传递。
最常用最基本的就是基本数据类型的传递。
使用intent传递即可。
在调用startActivity之前,先使用intent.putExtra(key,value)设置传递的参数。key是参数名,value是参数值。如(“what”,“abcd”)
在接收参数时,调用getIntent().get + 数据类型+ Extra(key)
如:
SelectActivity(跳转前,发送方)中
Intent goWrite = new Intent(SelectActivity.this, WriteActivity.class);
goWrite.putExtra("num", num);
startActivity(goWrite);
WriteActivity(跳转后,接收方)中
num = getIntent().getIntExtra("num", -1);