Activity的内容
Activity的生命周期
多个Activity交互会调用:
进行横竖屏切换时会将此activity先销毁掉,即经历onPause->onStop->onDestroy方法,然后重新执行此activity的onCreate->onStart->onResume方法。
在activity销毁的时候保存一些状态信息onSaveInstanceState()方法
2种启动方式:
显示和隐式的启动方式,显示启动方式直接指定一个Activity;隐式启动方式指定所要启动的Action标签,可以在AndroidManifest.xml中添加action标签
启动常见系统的ACTION:
Uri uri = Uri.parse("http://www.baidu.com");
intent.setData(uri);*/
/*intent.setAction(intent.ACTION_GET_CONTENT);
intent.setType("image*//*");*/
/*intent.setAction(Intent.ACTION_VIEW);
Uri uri = Uri.parse("tel:123456");
intent.setData(uri);*/
/*intent.setAction(intent.ACTION_SEND);
intent.setType("test/plain");
intent.putExtra(Intent.EXTRA_TEXT, "啦啦啦啦啦");*/
startActivity(intent);
Activity之间的数据交互:
1、直接putExtra
intent.putExtra("name", "luoguofu");
intent.putExtra("age", 23)
2、使用bundle
Bundle bundle = new Bundle();
bundle.putString("name", "lgf");
bundle.putInt("age", 22);
intent.putExtras(bundle);
3、使用对象来传递
需要创建一个类调用Serializable, Serializable 是序列化接口,对象如果实现这个接口的话,就是代表可以序列化,可以序列化的意思你可以这么理解,对象可以作为字节流进行传输或保存。不用它,是不能完成数据传递的,intent和budle都不能携带对象,但能携带实现序列化的对象
Person person = new Person("luo", 21, "居住地址");
Bundle bundle = new Bundle();
bundle.putSerializable("person", person);
4、使用Bitmap来传递图片
其实也主要用到了Bundle
Bundle bundle = new Bundle();
Bitmap bitmap = BitmapFactory.decodeResource(getResources(),R.mipmap.ic_launcher);
bundle.putParcelable("image",bitmap);
intent.putExtras(bundle);
startActivity(intent);
在另一个Activity中写入:
Bitmap bitmap =intent.getParcelableExtra("image");
imageView.setImageBitmap(bitmap);
4.1实现Parcelable就是为了进行序列化,那么,为什么要序列化?
1)永久性保存对象,保存对象的字节序列到本地文件中;
2)通过序列化对象在网络中传递对象;
3)通过序列化在进程间传递对象。
4.2实现序列化的方法
Android中实现序列化有两个选择:一是实现Serializable接口(是JavaSE本身就支持的),一是实现Parcelable接口(是Android特有功能,效率比实现Serializable接口高效,可用于Intent数据传递,也可以用于进程间通信(IPC))。实现Serializable接口非常简单,声明一下就可以了,而实现Parcelable接口稍微复杂一些,但效率更高,推荐用这种方法提高性能。
注:Android中Intent传递对象有两种方法:一是Bundle.putSerializable(Key,Object),另一种是Bundle.putParcelable(Key,Object)。当然这些Object是有一定的条件的,前者是实现了Serializable接口,而后者是实现了Parcelable接口。
4.3选择序列化方法的原则
1)在使用内存的时候,Parcelable比Serializable性能高,所以推荐使用Parcelable。
2)Serializable在序列化的时候会产生大量的临时变量,从而引起频繁的GC。
3)Parcelable不能使用在要将数据存储在磁盘上的情况,因为Parcelable不能很好的保证数据的持续性在外界有变化的情况下。尽管Serializable效率低点,但此时还是建议使用Serializable 。
4.4应用场景
需要在多个部件(Activity或Service)之间通过Intent传递一些数据,简单类型(如:数字、字符串)的可以直接放入Intent。复杂类型必须实现Parcelable接口。
5、大数据传递
使用bundle进行传递数据时,不能大于0.5M,否则会抛出TransactionTooLargeException异常
Task和back stack
当执行某项工作时,任务(task)是与用户相互交互的activity的集合。这些activity被管理在同一个堆中(回退堆(back stack)),在这个堆里存放的activity是被依次打开过的。
当前的activity启动了另外一个activity时,新的activity就被压入堆顶并获取焦点。前一个activity仍在堆里,但是处于停止状态。当activity停止时,系统会保存它停止时用户界面的状态。如果用户按下了返回键,当前的activity就会从堆中被弹出(activity被销毁了)并且先前的activity被恢复了(先前activity的UI状态被系统记住了)。堆中的activity从不会被重新放置,只会从堆中弹出或是压入--activity启动时被压入堆中,用户使用后退键从activity离开时从堆中弹出。后退堆(back stack)本身就和“后进先出”的对象结构执行的操作一样。图表1展示了多个activity之间的进程,用时间轴的方式使得这些行为变得可视化,并展示了每个时间点上后退堆的情况。
图1 在后退堆(back stack)里,如何添加一个新activity任务的展示。当用户按下返回键,当前的activity被销毁,前一个被恢复。
如果用户继续按下返回键,后退堆(back stack)里的activity依次被弹出并显示前一个activity,直到用户回到主屏幕(或者是任务(task)开始时运行的activity)。当堆里所有的activity都被移除时,任务(task)也就被销毁了。
任务(task)可以返回到前台,因此离开时是什么样子的,回来时仍然是什么样子。例如,假设当前任务(task)(Task A)的堆里有三个activity。用户按下Home键,通过应用程序加载器开启了一个新的应用。当主屏幕显示时,Task A进入了后台。当新的应用开启时,系统为新应用创建了一个属于它的新的任务(task)(Task B)。在和新的应用发生完交互后,用户再次回到了主屏幕并打开了先前的应用。这时,Task A回到了前台--它堆里的三个activity都是完整的,并且堆顶部的activity被恢复。此时,用户也可以通过回到主屏幕、点击应用图标来启动Task B(或者从最近应用的屏幕上选择Task B的任务(task))。上面说的就是Android系统里多任务处理的例子。
通过在Manifest中为activtiy注册信息时添加:process 即可分配不同的进程名;
使用activity的getTaskId()方法可以获得当前应用程序的taskId,同一个应用程序下的不同activity默认情况下的taskId都是相同的;
查看任务栈:
在cmd下 adb shell dumpsys activity
Activity的4中启动模式:
你在mainfest里申明一个activity时,你可以使用<activity>元素里的launchMode 属性。
launchMode 属性指定了关于activity如何被加载到任务(task)的说明。有四个可以指定给launchMode 属性的不同的读取模式:
"standard"(默认模式)
默认地,系统在activity开始的任务(task)里给它创建一个新的实例并把intent发送给它。该activity可以被实例化多次,每个实例都可以属于不同的任务(task),并且一个任务(task)里也可以有它的多个实例。
"singleTop"
在当前任务(task)的顶部,如果一个activity的实例已经存在了,那么系统会通过调用该实例的 onNewIntent()方法来把intent发送给它,而不是再创建一个新的实例。activity可以被实例化多次,每个实例都可以属于不同的任务(task),并且一个任务(task)里也可以有它的多个实例(当activity处于后退堆(back stack)的顶部时,不是它的一个现有实例)。
例如,假设一个任务(task)的后退堆(back stack)由根activity A和activity B、C、D组成(D在顶部)。类型D的intent到达了。如果D是默认的启动模式"standard",那么D的一个新实例被启动了,堆里的内容就变为A-B-C-D-D。虽然如此,但是,如果D的启动模式是"singleTop",那么,已存在的D的实例就会通过onNewIntent() 方法收到该intent,这是因为它在堆顶--堆里的内容仍然为A-B-C-D。但是,如果类型B的intent到达,那么即使B的启动模式是"singleTop",系统也仍然会新实例化一个B的实例并把它添加到 堆里。
注意:activity的新实例被创建时,用户可以通过按下返回键返回到先前的activity。但是,当一个activity已经存在的实例处理了一个新的intent,那么,在一个新的intent进入onNewIntent() 方法之前,用户不能通过按下返回键返回activity的状态。
"singleTask"
系统会创建一个新的任务(task)并把activity的实例做为该任务(task)的根。但是,如果该activity的实例在一个单独的任务(task)里已经存在了,那么系统会通过调用它的onNewIntent() 方法来把intent发送给它,而不是再创建一个新的实例。也就是说,在同一时刻,仅仅只会存在该activity的一个实例。singleTask 在启动时系统会搜索任务栈中是否包含该activity,如果包含则调用onNewIntent()方法并将其之上栈中其他的activity全部destroy掉。
注意:尽管在新的任务(task)里启动了该activity,但是按下返回按钮时,用户仍然会回到先前的activity。
"singleInstance"
与"singleTask"类似,不一样的是系统不会把其它的activity发送到拥有"singleInstance"启动模式activity的任务(task)里。以该模式启动的activity在任务(task)只会有一个;任何以该模式启动的activity都会在一个单独的任务(task)里被打开。
其它的例子是Android浏览器应用,它通过在清单文件的<activity>元素里指定singleTask模式来申明浏览器里的activity都应该在它自己单独的任务(task)里打开。这就意味着,如果你的应用发布了一个intent来打开网页浏览器,那么它的activity不会和你的应用放置在同一个任务(task)里。要么是一个新的任务(task),要么如果浏览器已经在后台运行了,那它的任务(task)就会被带到前台来处理该intent。