1.Activity
四大组件之一,通常一个用户交互界面对应一个activity。activity是Context的子类,同时实现了window.callback和keyevent.callback,可以处理与窗体用户交互的事件。
1.1生命周期
onCreate:当Activity第一次启动调用
onDestory:当Activity销毁的时候调用
onStart:当Activity变成可见调用
onStop:当Activity不可见调用
onResume:当Activity可以交互调用这个方法 当界面上的按钮被点击的时候调用
onPause:当Activity不可以交互调用这个方法 当界面上的按钮不可以点击
onRestart:当界面重新启动的时候调用
Activity创建调用的顺序是:onCreate ---> onStart ---> onResume ---> onPause ---> onStop ---> onDestory
还有一个onRestart,其中onRestart是在Acitivity被onStop后,但是没有被onDestory,在再次启动此Activity时调用的(而不再调用onCreate)方法;如果被onDestory了,则是调用onCreate方法。
几种情况:
1.点击Home键回到主界面(Activity不可见):onPause ---> onStop
2,当我们再次回到原Activity时: onRestart ---> onStart ---> onResume
onRestart:已经启动的activity,又从桌面回到activity时,再次启动
3.退出当前Activity时: onPause ---> onStop ---> onDestory
1.2Activity的四种状态:running / paused / stopped / killed
1.runnig:用户可以点击,activity处于栈顶状态。
2.paused:activity失去焦点的时候,被一个非全屏的activity占据或者被一个透明的activity覆盖,这个状态的activity并没有销毁,它所有的状态信息和成员变量仍然存在,只是不能够被点击。(除了内存紧张的情况,这个activity有可能被回收)
3.stopped:这个activity被另外一个activity完全覆盖,但是这个activity的所有状态信息和成员变量仍然存在(除了内存紧张)
4.killed:这个activity已经被销毁,其所有的状态信息和成员变量已经不存在了。
1.3Android进程优先级:前台 / 可见 / 服务 / 后台 / 空
- 前台进程:Foreground process
用户正在交互的Activity(onResume())
当某个Service绑定正在交互的Activity
被主动调用为前台Service(startForeground())
组件正在执行生命周期的回调(onCreate()、onStart()、onDestory())
BroadcastReceiver正在执行onReceive() - 可见进程:Visible process
我们的Activity处在onPause()(没有进入onStop())
绑定到前台Activity的Service - 服务进程:Service process
简单的startService()启动。 - 后台进程:Background process
对用户没有直接影响的进程 --- Activity处于onStop()的时候。
android:process=":xxx" - 空进程:Empty process
不含有任何的活动的组件。(Android设计的,处于缓存的目的,为了第二次启动更快,采取的一个权衡)
1.4两个Activity之间跳转必然会执行的是哪几个方法:
1、一般情况比如说有两个activity,分别叫A、B ,当在A里面激活B组件的时候,A 会调用 onPause()方法,然后B 调用onCreate、onStart、 OnResume,这个时候B覆盖了窗体,A会调用onStop方法. 。
2、如果B是个透明的界面,或者是对话框的样式,,就不会调用onStop方法。
1.5 横竖屏切换的生命周期变化:
这个生命周期跟清单文件里的配置有关系:
1、不设置Activity的android:configChanges时,切屏会销毁当前Activity,然后重新加载,重新调用各个生命周期。onPause ---> onStop ---> onDestory ---> onCreate --->onStart ---> onResume。
2、设置Activity的android:configChanges="orientation|keyboardHidden|screenSize"时,切屏不会重新调用各个生命周期,只会执行 onConfigurationChanged 方法。
1.6 Activity的四种启动模式:
清单文件中可以配置每个activity的启动模式,例如:
android:launchMode="standard"
(1) standard 标准模式:
特点:此模式不管有没有已存在的实例,都生成新的实例。每次调用startActivity()启动Activity时都会创建一个新的Activity放在栈顶,每次返回都会销毁实例并出栈,可以重复创建。
(2) singleTop 单一顶部模式:
特点:会检查任务栈栈顶的Activity,如果发现栈顶已经存在实例,就不会创建新的实例,直接复用。但如果不在栈顶,那么还是会创建新的实例。
应用场景:浏览器书签的页面,流氓的网站,避免创建过多的书签页面
(3) singleTask 单一任务模式:
特点:这种模式不会检查任务栈的栈顶,检查当前任务栈,如果发现有实例存在,直接复用。任务栈中只有一个实例存储(把当前activity上面的所有的其它activity都清空,复用这个已经存在的activity)
应用场景:浏览器浏览页面的Activity,播放器播放的activity。
(4) singleinstance 单一实例模式
特点:系统会为这个Activity单独创建一个任务栈,这个任务栈里面只有一个实例存在并且保证不再有其它activity实例进入。
应用场景:来电页面。
1.7scheme跳转协议:
Android中的scheme是一种页面内跳转协议,是一种非常好的实现机制,通过定义自己的scheme协议,可以非常方便跳转app中的各个页面;通过scheme协议,服务器可以定制化告诉app跳转哪个页面,可以通过通知栏消息定制化跳转页面,可以通过H5页面跳转页面等。
关于scheme跳转协议,可以查看下面的博客,站在巨人的肩膀上,才能看得更远
Android产品研发(十一)-->应用内跳转Scheme协议
1.8 如果后台的activity由于某原因被系统回收了,如何在被系统回收之前保存当前状态:
除了在栈顶的activity,其他的activity都有可能在内存不足的时候被系统回收,一个activity越处于栈底,被回收的可能性就越大。
一般来说,调用 onPause()和 onStop()方法后的 activity 实例仍然存在于内存中,activity 的所有信息和状态数据不会消失,当 activity 重新回到前台之后,所有的改变都会得到保留。但是当系统内存不足时, 调用onPause()和onStop()方法后的 activity可能会被系统摧毁,,此时内存中就不会存有该 activity 的实例对象了。如果之后这个 activity 重新回到前台,之前所作的改变就会消失。
为了避免此种情况,我们可以覆写onSaveInstanceState()
方法。onSaveInstanceState()方法接受一个 Bundle 类型的参数,开发者可以将状态数据存储到这个 Bundle 对象中,这样即使 activity 被系统摧毁,当用户重新启动这个 activity 而调用它的onCreate()方法时,上述的 Bundle 对象会作为实参传递给 onCreate()方法,开发者可以从 Bundle 对象中取出保存的数据,然后利用这些数据将 activity 恢复到被摧毁之前的状态。
但是有些情况用上面这种方式是解决不了的,比如说我们正在播放一个视频,结果手机突然没电了,我们想在手机充电之后,还能返回到我们之前播放的位置,就可以仿照WPS等软件的保存机制,可以在播放视频的时候,每隔一段时间保存当前进度到一个文件中(不能是内存),这样即使没电了,但是我们之前的某个时间有保存当前进度,所以仍然能够回到之前播放的位置。
2.Fragment
Fragment,俗称碎片,自Android 3.0开始被引进并大量使用。作为Activity界面的一部分,Fragment的存在必须依附于Activity,并且与Activity一样,拥有自己的生命周期,同时处理用户的交互动作。同一个Activity可以有一个或多个Fragment作为界面内容,并且可以动态添加、删除Fragment,灵活控制UI内容,也可以用来解决部分屏幕适配问题。
从上图可以看到Fragment比Activity多了几个额外的生命周期回调方法:
2.1 Fragment与Activity之间是如何传值的:
- Activity向Fragment传值:
步骤:
要传的值,放到bundle对象里;
在Activity中创建该Fragment的对象fragment,通过调用
fragment.setArguments()传递到fragment中;
在该Fragment中通过调用getArguments()得到bundle对象,就能得到里面的值。 - Fragment向Activity传值:
第一种:
在Activity中调用getFragmentManager()得到fragmentManager,,调用findFragmentByTag(tag)或者通过findFragmentById(id)
FragmentManager fragmentManager = getFragmentManager();
Fragment fragment = fragmentManager.findFragmentByTag(tag);
第二种:
通过回调的方式,定义一个接口(可以在Fragment类中定义),接口中有一个空的方法,在fragment中需要的时候调用接口的方法,值可以作为参数放在这个方法中,然后让Activity实现这个接口,必然会重写这个方法,这样值就传到了Activity中
2. 2Fragment与Fragment之间是如何传值的:
第一种:
通过findFragmentByTag得到另一个的Fragment的对象,这样就可以调用另一个的方法了。
第二种:
通过接口回调的方式。
第三种:
通过setArguments,getArguments的方式。
2.3FragmentTransaction的add和replace的区别:
1.add + hide + show的方式:
其实add是一层层添加上去的,通过show去显示当前界面,hide去隐藏其他的界面,这时候的FrameLayout是会有很多层的。Fragment A 切换到Fragment B,然后再由Fragment B 切换到Fragment A 的时候,Fragment A 的所有生命周期是不会走的,只会调用onHiddenChanged(boolean isHidden),也就是说hide和show只是把其他界面隐藏,当前界面显示的效果,并不会走生命周期方法。
2.replace的方式:
其实replace是会替换掉原有的,所以这种方式的FrameLayout是只有一层的,再如上面的方式切换fragment,Fragment A会依次走生命周期方法:onAttach ---> onViewCreated ---> onActivityCreated ---> onStart。但是如果添加代码 ft.addToBackStack(null),生命周期方法onAttach方法就不会走。
2.4Fragment如何实现类似Activity的压栈和出栈效果的:
Fragment的事物管理器内部维持了一个双向链表结构,该结构可以记录我们add或者replace的Fragment,然后当我们按返回键的时候,会自动帮我们实现出栈操作。
2.5 FragmentPagerAdapter与FragmentStatePagerAdapter的区别:
一. 由于FragmentStatePagerAdapter在destoryItem的时候调用mCurTransaction.remove(fragment),会回收内存的,而页面比较多的时候,就比较消耗内存,所以FragmentStatePagerAdapter适合于页面比较多的情况。
二. FragmentPagerAdapter在destoryItem的时候调用mCurTransaction.detach(fragment),没有回收内存,只是将fragment与activity的UI进行分离,所以FragmentPagerAdapter适合于页面比较少的情况。