初识Activity
Posted cynchanpin
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了初识Activity相关的知识,希望对你有一定的参考价值。
此刻。你应该静下心来,在阅读中思考,在思考中进步。读完本篇文章的你一定会有不一样的收获。请让我们共同进步。如有不论什么疑问请留言!
核心内容
- Activity本质是什么
- Activity生命周期
- Activity启动模式
- Activity直接的数据交互
- 如何启动系统的Activity
- Activity启动模式
Activity简单介绍
- Activity是android组件中最基本也是最为常见用的四大组件(Activity,Service服务,ContentProvider内容提供者。BroadcastReceiver广播接收器)之中的一个。
- Activity是一个应用程序组件。提供一个屏幕,用户能够用来交互为了完毕某项任务。
- Activity中全部操作都与用户密切相关,是一个负责与用户交互的组件,能够通过setContentView(View)来显示指定控件,Activity本质能够理解为界面的载体。
- 在一个android应用中,一个Activity通常就是一个单独的屏幕,它上面能够显示一些控件也能够监听并处理用户的事件做出响应。Activity之间通过Intent进行通信。
注:关于Activity的很多其它介绍可查看官方文档或其它文章详细了解…
Activity生命周期
以下的图显示了Activity 的状态转换的方法和实现,矩形框表明Activity在状态转换之间的回调接口,开发者能够重载实现以便运行相关代码。带有颜色的椭圆形表明Activity所处的状态。(简单了解)
在上图中,Activity有三个关键的循环:
整个的生命周期。从onCreate(Bundle)開始到onDestroy()结束。Activity在onCreate()设置全部的“全局”状态,在onDestory()释放全部的资源。
(比如:某个Activity有一个在后台运行的线程,用于从网络下载数据,则该Activity能够在onCreate()中创建线程,在onDestory()中停止线程。)
可见的生命周期,从onStart()開始到onStop()结束。在这段时间,能够看到Activity在屏幕上,虽然有可能不在前台,不能和用户交互。
在这两个接口之间,须要保持显示给用户的UI数据和资源等。(比如:能够在onStart中注冊一个IntentReceiver来监听数据变化导致UI的变动,当不再须要显示时候。能够在onStop()中注销它。onStart(),onStop()都能够被多次调用。由于Activity随时能够在可见和隐藏之间转换。)
前台的生命周期。从onResume()開始到onPause()结束。在这段时间里,该Activity处于全部 Activity的最前面,和用户进行交互。Activity能够常常性地在resumed和paused状态之间切换,(比如:当设备准备休眠时。当一个 Activity处理结果被分发时,当一个新的Intent被分发时。所以在这些接口方法中的代码应该属于非常轻量级的。)
单个Activity生命周期
从运行到按back键退出可分为三个状态(显示状态、隐藏状态、销毁状态)
1、oncreate ——》onstart ——》onResume 显示状态
2、onPause ——》onStop 处于全然隐藏状态
3、onDestory 销毁状态
多个Activity交互时的生命周期
A Activity 打开 B Activity 时(可编写两个详细的Activity实现当中的各个生命周期方法进行測试)
A Activity B Activity
onCreate
onStart
onResume
onPause
onCreate
onStart
onResume
onStop
B Activity点击Back键时(按back键时对当前Activity运行一个销毁操作)
A Activity B Activity
onPause
onRestart
onStart
onResume
onStop
onDestroy
思考:Activity的生命周期为什么是这样的呢?在打开B Activity时为什么不能够先不运行A Activity的onPause方法而在B Activity运行完onCreate、onStart、onResume方法后在运行A Activity的onPause方法呢等等。要分析这些详细问题,就要分析整个Activity的生命周期的设计详细思路。假设我们自己是开发sdk的。那么我们在处理这样的生命周期的时候须要考虑那些详细问题呢?
解答一:为什么要先暂停当前显示的Activity
假设打开一个应用在观看视频的时候,这时有人给我们打了一个电话进来就显示当前电话的一个Activity界面,这样的情况下假设不先运行onPause方法暂停当前的Activity,而是在电话Activity的onResume方法后运行会出现什么问题呢?就有可能当前的电话Activity已经进来的时候视频的声音还是在响等一些问题,这样就给用户感觉非常不好,所以才要这样运行当前Activity的onPause()方法。
(在开发中须要做的就是在onPause方法中推断当前Activity的音频或视频是否在播放,假设播放我们就让其处于暂停状态,暂停当前Activity的一些状态信息。
)
解答二:在打开新Activity的时候,为什么不先运行当前Activity的OnStop方法,而是要先运行新打开Activity的onCreate,onStart,OnResume方法再运行onStop方法
事实上这就是google在设计上给我们做的一种安全保护机制。假设在打开新的Activity时出现一些异常信息有可能会crush掉(crush:由于程序或者各种原因而导致的程序意外退出、俗称“闪退”)所以就是为了保证新打开的Activity能正常显示当前的Activity才会调用onStop方法处于隐藏状态。
屏幕切换与应用场景
1、Activity的屏幕切换(横竖屏切换)
Activity的横竖屏切换对activity生命周期的影响。进行横竖屏切换时会将此activity先销毁掉,即经历onPause->onStop->onDestroy方法。然后又一次运行此activity的onCreate->onStart->onResume方法,所以在再进行横竖屏切换的时须要保存Activity的相关状态使其保持在屏幕切换前后的内容一致,这里使用到的是系统提供onSaveInstanceState()方法,该方法在整个Activity销毁时用于保存当前的一些状态信息(注:onSaveInstanceState()方法的运行是在onPause()方法后。)。信息保存在系统的Bundle对象中,在Activity又一次创建时就能够把保存的数据取出来。(详细操作看例如以下演示样例:)
@Override
protected void onSaveInstanceState(Bundle outState) {
Log.i("TAG","MainActivity onSaveInstanceState");
super.onSaveInstanceState(outState);
outState.putString("name", "nate");
}
然后在onCreate()方法中推断saveInstanceState值是否为空来取出对应的信息
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if(savedInstanceState!=null){
savedInstanceState.get("name");
}
}
对于这样的什么周期的切换时都是通过onSaveInstanceState()方法保存相关的状态信息,假设想取出这个信息时就要在onCreate()方法中推断savedInstanceState不等于空依据不同的key值去取出对应的value。在实际的情况下一般的操作都是对整个Activity不让其做横屏的切换的,假设做横屏切换时我们要做的工作就比較多了还要对横屏的界面布局信息做一些适配工作这样开发周期就比較长。眼下大多数的应用都是仅仅有竖屏状态。
2、生命周期应用场景
接下来就通过“一个Activity”去播放音乐的样例去解说整个Activity生命周期在开发中详细应用。
首先在res中新建一个raw目录存放响应的音频文件res–>raw–>mm.mp3(文件尽量使用英文名)
部分关键代码:
public class MainActivity extends Activity {
private MediaPlayer mediaPlayer;
private int position;// 保存当前播放的位置
@Override
protected void onStart() {
super.onStart();
Log.i("tag", "MainActivity--->onStart()");
}
@Override
protected void onResume() {
super.onResume();
Log.i("tag", "MainActivity--->onResume()");
if (position != 0) {
mediaPlayer.seekTo(position);// 跳到播放的位置
mediaPlayer.start();// 继续播放
}
}
@Override
protected void onPause() {
super.onPause();
Log.i("tag", "MainActivity--->onPause()");
if (mediaPlayer.isPlaying()) {
mediaPlayer.pause();// 暂停
position = mediaPlayer.getCurrentPosition();// 记录当前播放的位置
}
}
@Override
protected void onStop() {
super.onStop();
Log.i("tag", "MainActivity--->onStop()");
}
@Override
protected void onDestroy() {
super.onDestroy();
Log.i("tag", "MainActivity--->onDestroy()");
// 释放资源
if (mediaPlayer != null) {
mediaPlayer.release();
mediaPlayer = null;
}
// ..............
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.i("tag", "MainAcitvity-->onCreate()");
mediaPlayer = MediaPlayer.create(this, R.raw.mydream);
mediaPlayer.start();
}
}
代码解读:上面是”以一个Activity为载体来播放音乐”的。
要播放音乐首先要创建一个MediaPlayer对象,在onCreate()方法中进行播放。此时在该Activity中打开一个新的Activity(假如新的Activity是来电界面)这样的情况下应该把音乐处于暂停状态(即在当前Activity生命周期的onPause方法中推断是否在播放。在播放的话就要暂停播放并记录当前播放的位置。)当从电话界面返回到当前音乐播放的Activity时在指定位置開始播放(即在音乐播放Activity的onResume方法中又一次播放),最后在onDestory方法中释放一些资源。(上面以给出了关键代码,其它相关的代码可自行完好,如有疑问请在文章最后留言!
)
启动Activity(直接启动和匿名启动)
1、直接(显示)启动
//方法1
Intent intent = new intent(FirstActivity.this, SecondActivity.class);
startActivity(intent);
//方法2
Intent intent = new Intent();
ComponentName component = new ComponentName(FirstActivity.this, SecondActivity.class);
intent.setComponent(component);
startActivity(intent);
2、匿名(隐式)启动
假设SecondActivity不是在本应用中而是其它应用的Activity,假设这样的情况下想在FirstActivity中启动SecondActivity我们是无法拿到SecondActivity对于的class所以不能够用显示意图启动。那要如何启动SecondActivity呢,前提是须要在SecondActivity所在的应用中的Manifest文件里对SecondActivity指定了一个intent-filter意图过滤器并配置action与category属性(action取一个url作为名称,category属性用于指定当前动作(action)被运行的环境。环境能够设置为default(缺省)) ,然后依据意图过滤器中的action名来启动该Acticity(SecondActivity)。
例如以下演示样例:
<activity android:name=".SecondActivity">
<intent-filter>
<action android:name = "www.nf.com"></action>
<category android:name="android.intent.category.DEFAULT"></category>
</intent-filter>
</activity>
Intent intent=new Intent();
intent.setAction("www.nf.com");
startActivity(intent);
总结:
对于Activity 的启动,应用场景不同启动方式也会不同。我们使用匿名启动的时候,基本的原因是为了启动系统中的Activity(如:联系人界面,相冊,浏览器等)。显示意图主要是应用于知道Activity的名字的情况下(如:自身应用的Activity)。
启动系统常见的Activity
Intent类已经封装非常多的常量信息都是系统Activity的一些标识(查看官方API文档:Develop-Reference-Intent)
1、启动系统浏览器
intent.setAction(Intent.ACTION_VIEW);
Uri url=Uri.parse("http://baidu.com")
intent.setData(url);
startActivity(intent);
2、启动相冊
Intent intent=new Intent();
intent.setAction(Intent.ACTION_GET_CONTENT);
intent.setType("image/*");
startActivity(intent);
3、启动系统短信
Intent intent=new Intent();
intent.setAction(Intent.ACTION_SEND);
intent.setType("text/plain");
intent.putExtra(Intent.EXTRA_TEXT,"hello world");
startActivity(intent);
4、启动拨号器
Intent intent=new Intent();
intent.setAction(Intent.ACTION_VIEW)
Uri url=Uri.parse("tel:13766257357");
intent.setData(url);
startActivity(intent);
本课程到这里就结束了,假设想更深一步学习可阅读:深入Activity
以上是关于初识Activity的主要内容,如果未能解决你的问题,请参考以下文章
Android 事件分发事件分发源码分析 ( Activity 中各层级的事件传递 | Activity -> PhoneWindow -> DecorView -> ViewGroup )(代码片段
如何在 Activity(非 AppCompatActivity)中打开片段?