Activity是Android最重要也是最常用的组件
显示状态:onCreate,onStart,onResume
隐藏状态:onPause,onStop
销毁状态:onDestroy
当启动应用时会有如下方法得到执行onCreate-->onStart-->onResume
onStart是可见但不可交互状态
onResume是可见且可交互状态
当点击Back键时会调用onPause-->onStop-->onDestroy(一个Activity从创建到销毁的全过程,onRestart另说)
onPause是不可交互但可见状态
onStop是不可见且不可交互状态
通过Intent启动另一个Activity观察生命周期
需要注意的是点击button后首先执行的是onPause方法,然后创建另一个Activity,当SecondActivity可见时再执行MainActivity的onStop方法。
点击Back键后同理先执行onPause方法,回到MainActivity,因为MainActivity已经有实例,所以执行onRestart方法替代onCreate,之后依然类似,onStart-->onResume,以及SecondActivity的onStop-->onDestroy。
为什么只是先暂停当前Activity,而不是跳转Activity后再执行onPause-->onStop,或者先onPause-->onStop,然后再创建跳转Activity?
1)如果当前的应用是音乐播放器,当有电话打来时,当前的Activity在接听页面显示之前都不会暂停,不符合交互逻辑。
2)同样的例子,电话页面未显示而当前Activity已经stop,则会出现不可见的黑屏状态,直到接听页面创建并显示完成。
Activity横竖屏切换的生命周期
切换横竖屏时会将当前Activity按正常流程Destroy,然后重新创建Activity
切换横竖屏时,如果有输入框之类的控件,则需要保存竖屏时的状态,比如说有输入框之类的控件而且已经有输入内容,此时切到横屏不应该丢失数据,因此需要调用onSaveInstanceState保存状态信息。在onCerate方法中进行判断参数savedInstanceState是否为空
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); if (savedInstanceState != null) { Log.i("tag", "MainActivity" + savedInstanceState.getString("libo")); } Log.i("tag", "MainActivity onCreate"); button = (Button) findViewById(R.id.button1); button.setOnClickListener(this); } @Override protected void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); Log.i("tag", "MainActivity onSaveInstanceState"); outState.putString("libo", "abc"); }
Activity生命周期的应用——音乐播放
onDestroy方法常用作释放资源
private MediaPlayer mediaPlayer; private int position; //在onCreate方法中初始化 mediaPlayer = MediaPlayer.create(this, R.raw.ifyou); mediaPlayer.start(); //在onPause方法中暂停MediaPlayer,并记录播放进度 @Override protected void onPause() { super.onPause(); Log.i("tag", "MainActivity onPause"); if (mediaPlayer.isPlaying()) { mediaPlayer.pause(); position = mediaPlayer.getCurrentPosition(); Log.i("tag", position+""); } } //在onResume方法中读取进度播放 @Override protected void onResume() { super.onResume(); Log.i("tag", "MainActivity onResume"); if (position != 0) { mediaPlayer.seekTo(position); Log.i("tag", position+""); mediaPlayer.start(); } } //在onDestroy方法中进行资源的释放 @Override protected void onDestroy() { super.onDestroy(); Log.i("tag", "MainActivity onDestroy"); if (mediaPlayer != null) { mediaPlayer.release(); mediaPlayer = null; } }
Intent是Android程序中各组件之间进行交互的一种重要方式,不仅可以指明当前组件想要执行的动作,还可以在不同的组件之间传递数据。一般可被用于启动Activity,启动Service,以及发送广播等。
通过构造Intent,指定需要跳转的Activity。
Intent intent = new Intent(ThirdActivity.this, FourthActivity.class); startActivity(intent);
为将要启动的Activity添加一个Intent过滤器,并指定action标签,指明当前Activity可以响应"libo"这个action。category标签默认为 android.intent.category.DEFAULT,更精确的指明了当前Activity能够响应带有category的Intent。action和category标签内容同时匹配时,这个Activity才能响应。当 category为默认时,可以省略 intent.addCategory() 方法。
<activity android:name="com.example.activity.FourthActivity"> <intent-filter > <action android:name="libo"/> <category android:name="android.intent.category.DEFAULT"/> </intent-filter> </activity>
Intent intent = new Intent(); intent.setAction("libo"); startActivity(intent);隐式启动多用于启动没有源文件的Activity,比如系统的浏览器,拨号,短信等
//打开网页 Intent intent = new Intent(); intent.setAction(Intent.ACTION_VIEW); Uri uri = Uri.parse("http://www.qq.com"); intent.setData(uri); startActivity(intent);
//打开图库 Intent intent = new Intent(); intent.setAction(Intent.ACTION_GET_CONTENT); intent.setType("image/*"); startActivity(intent);
//发送短信 Intent intent = new Intent(); intent.setAction(Intent.ACTION_SEND); intent.setType("text/plain"); intent.putExtra(Intent.EXTRA_TEXT, "hello csdn"); startActivity(intent);
//拨号 Intent intent = new Intent(); intent.setAction(Intent.ACTION_VIEW); Uri uri = Uri.parse("tel:666666"); intent.setData(uri); startActivity(intent);
以上系统应用可以被调用,网页通过setData方法指定Intent操作的数据。另外,还可以通过Intent-Filter配置Data标签,更精确的指定当前活动可以响应什么类型的操作。
Data标签可以配置如下内容:
1.android:scheme 用于指定数据的协议部分,例如http、geo地理位置、tel拨打电话
2.android:host 用于指定数据的主机名部分,例如www.qq.com
3.android:port 用于指定数据的断口部分,一般紧随主机名之后
4.android:path 用指定主机名和端口之后的部分
5.android:mimeType 用于指定可以处理的数据类型。
更多系统的action可以查阅官方文档
通过Intent启动另一个Activity时,可以利用Intent携带一定量的具体数据。
具体方法为putExrta。通过键值对的方式。可以传递常用的8种类型及数组,String,int,double等
Intent intent = new Intent(ThirdActivity.this, FourthActivity.class); intent.putExtra("name", "libo"); intent.putExtra("age", 21); startActivity(intent);在被启动的Activity中需要先进行getintent,获取启动Intent,然后通过getStringExtra等的函数取出数据
Intent intent = getIntent(); if (intent != null) { text.setText(intent.getStringExtra("name") + " " + intent.getIntExtra("age", 0)); }
也可以通过Bundle先进行封装,再通过Intent传递
Intent intent = new Intent(ThirdActivity.this, FourthActivity.class); Bundle bundle = new Bundle(); bundle.putString("name", "libo"); bundle.putInt("age", 21); intent.putExtras(bundle); startActivity(intent);Bundle也可以用于封装对象实例进行传递,不过对象须实现Serializable接口进行序列化(序列化是Java IO中的知识)
public class Person implements Serializable { private String name; private int age; private String address; public Person(String name, int age, String address){ this.name = name; this.age = age; this.address = address; } @Override public String toString() { return "name: " + name + "age: " + age + "address: " + address; } }
Intent intent = new Intent(ThirdActivity.this, FourthActivity.class); Person person = new Person("libo", 21, "xian"); Bundle bundle = new Bundle(); bundle.putSerializable("person", person); intent.putExtras(bundle); startActivity(intent);
Intent intent = getIntent(); if (intent != null) { Person person = (Person) intent.getSerializableExtra("person"); text.setText(person.toString()); }Bundle也可以用于传递图片,但大小不能过大,上限约为0.5M
Intent intent = new Intent(ThirdActivity.this, FourthActivity.class); Bundle bundle = new Bundle(); Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher); bundle.putParcelable("bitmap", bitmap); intent.putExtras(bundle); startActivity(intent); img.setImageBitmap((Bitmap) intent.getParcelableExtra("bitmap"));当Bundle携带数据量过大时会抛出如下错误
!!! FAILED BINDER TRANSACTION !!!如果需要在另一个Activity中使用本Activity的一些比较大的数据,可以考虑SQLite,或者文件
此时启动Activity的方法不是startActivity而是startActivityForResult(Intent intent, int requestCode),request只要保证是唯一值就可以。
Intent intent = new Intent(MainActivity.this, FirstActivity.class); startActivityForResult(intent, 1);
@Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { switch (requestCode) { case 1: if (resultCode == RESULT_OK) { String str = data.getStringExtra("first"); text.setText(str); } break; default: break; } }
Intent intent = new Intent(); intent.putExtra("first", "libo"); setResult(RESULT_OK, intent); finish();
默认是模式,可以创建条件允许的任意多个
如果再次创建的Activity在栈顶,那么就不会再重新创建新Activity,而是执行onNewIntent方法
如果不在栈顶,则跟默认模式相同,还是会再创建新的Activity
MainActivity->Activity->MainActivity(MainActivity默认,Activity singleTask),如果此时再启动Activity则会执行第二个MainActivity的onDestroy方法,即在任务栈中进行出栈,直到Activity处于栈顶。
启动Activity时会处于不同的任务栈中
Main1->First->Main2->First->Main3(Main默认模式,First singleInstance),First被启动两次但是只执行一次onCreate方法并创建一个新的任务栈,其余均为onNewIntent方法。
当First启动Main2时,因为是默认模式,则会寻找Task1,并创建Activity,Main3同样,此时显示的是Main3,单击Back键时会返回到Main2,Main1,最后才是First。
Back会先把此栈中的Activity全部出栈,再把Task2中的Activity出栈。
启动不是由自己开发的一个Activity,不清楚该Activity需要传递哪些数据,除了查看源码之外,完全可以在Activity创建一个静态方法来提示调用者该Activity的详细信息。
public static void activityStart(Context context, String data1, String data2){ Intent intent = new Intent(context, FirstActivity.class); intent.putExtra("data1", data1); intent.putExtra("data2", data2); context.startActivity(intent); }
//启动时,只需一句代码,并且简单完整的传入所需的各个参数 FirstActivity.activityStart(this, "abc", "def");