Android基础
1.Fragment
问题1:Fragment是什么?
Fragment是Android3.0后引⼊的⼀个新的API,他出现的初衷是为了适应⼤屏幕的平板电脑, 当然现在他仍然是平板APP UI设计的宠⼉,⽽且我们普通⼿机开发也会加⼊这个Fragment,我们可以把他看成⼀个⼩型的Activity,⼜称Activity⽚段!
生命周期如下
onAttach():Fragment和Activity相关联时调⽤。可以通过该⽅法获取
Activity引⽤,还可以通过getArguments()获取参数。
onCreate():Fragment被创建时调⽤。
onCreateView():创建Fragment的布局。
onActivityCreated():当Activity完成onCreate()时调⽤。
onStart():当Fragment可⻅时调⽤。
onResume():当Fragment可⻅且可交互时调⽤。
onPause():当Fragment不可交互但可⻅时调⽤。
onStop():当Fragment不可⻅时调⽤。
onDestroyView():当Fragment的UI从视图结构中移除时调⽤。
onDestroy():销毁Fragment时调⽤。
onDetach():当Fragment和Activity解除关联时调⽤。
问题2:FragmentTransaction的4种提交⽅式
1.commit():如果在宿主执⾏了onSaveInstanceSate之后再执⾏该操作,会抛出异常,属于异步事务。
2.commitAllowingStateLoss():如果在宿主执⾏了onSaveInstanceSate之后再执⾏该操作,不会去检查宿主状态、抛出异常。但该操作不会被Activity记录,恢复时也就没办法恢复这些提交操作,所以该操作适⽤于不重要的事务,同属于异步事务。
3.commitNow():会⽴刻执⾏当前提交的事务,属于同步事务。
4.commitNowAllowingStateLoss():具备前两者的特性,既是同步执⾏,也不会检查宿主的状态,有可能该操作不会被正确恢复。
问题3:Fragment + viewpager遇到过什么问题吗?
1、滑动的时候,调⽤setCurrentItem⽅法,要注意第⼆个参数smoothScroll。传false,就是直接跳到fragment,传true,就是平滑过去。
⼀般主⻚切换⻚⾯都是⽤false。
2、禁⽌预加载的话,调⽤setOffscreenPageLimit(0)是⽆效的,因为⽅法⾥⾯会判断是否⼩于1。需要重写setUserVisibleHint⽅法,判断fragment是否可⻅。
3、不要使⽤getActivity()获取activity实例,容易造成空指针,因为如果fragment已经onDetach()了,那么就会报空指针。所以要在onAttach⽅法⾥⾯,就去获取activity的上下⽂。
4、FragmentStatePagerAdapter对limit外的Fragment销毁,⽣命周期为onPause->onStop->onDestoryView->onDestory->onDetach, onAttach->onCreate->onCreateView->onStart->onResume。也就是说切换fragment的时候有可能会多次onCreateView,所以需要注意处理数据。由于可能多次onCreateView,所以我们可以把view保存起来,如果为空再去初始化数据。⻅代码:
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
if (null == mFragmentView) {
mFragmentView = inflater.inflate(getContentViewLayoutID(),null);
ButterKnife.bind(this, mFragmentView);
isDestory = false;
initViewsAndEvents();
}
return mFragmentView;
}
2.Activity
问题1:Activity生命周期的异常情况的2个方法?
1.
onSaveInstanceState(Bundle bundle)
出现异常情况(内存不足)下被调用
保存实例状态,来保存当前的Activity状态信息,可以存储数据,以便于恢复
2.
onRestoreInstanceState(Bundle bundle)
//恢复实例状态
Activity被重新创建的时候会调用,会把onSaveInstanceState保存的Bundle传递进来,而且还会传递给onCreate,都是onSaveInstanceState保存过后传的
3.系统配置发生改变或内存发生改变,会自动调用
onSaveInstanceState
保存Activity状态信息``,Activity
被重新创建之后,会调用onRestoreInstanceState
,会把onSaveInstanceState
保存的Bundle
传递进来,而且还会传递给onCreate
,都是onSaveInstanceState
保存过后传的,数据恢复建议用onRestoreInstanceState
,因为这里面的Bundle不会为空
,onCreate里面的bundle有可能为空
问题2.1:onNewIntent的⽣命周期?
1、只对singleTop,singleTask,singleInstance有效,因为standard每次都是新建,所以不存在onNewIntent。
2、只对startActivity有效,对于从Navigation切换回来的恢复⽆效。
问题2.2:TaskAffinity?
1.TaskAffinity,可以翻译为任务相关性。这个参数标识了一个Activity所需要的任务栈的名字,默认情况下,所有Activity所需的任务栈的名字为应用的包名。当然,我们可以为每个Activity都单独指定TaskAffinity属性,这个属性值必须不能和包名相同,否则就相当于没有指定。TaskAffinity属性主要和singleTask启动模式或者allowTaskReparenting属性配对使用,在其他情况下没有意义。另外,任务栈分为前台任务栈和后台任务栈,后台任务栈中的Activity位于暂停状态,用户可以通过切换将后台任务栈再次调到前台。
2.当TaskAffinity和singleTask启动模式配对使用的时候,它是具有该模式的Activity的目
前任务栈的名字,待启动的Activity会运行在名字和TaskAffinity相同的任务栈中。
3.当TaskAffinity和allowTaskReparenting结合的时候,这种情况比较复杂,会产生特殊的效果。当一个应用A启动了应用B的某个Activity后,如果这个Activity的allowTaskReparenting属性为true的话,那么当应用B被启动后,此Activity会直接从应用A的任务栈转移到应用B的任务栈中。这还是很抽象,再具体点,比如现在有2个应用A和B,A启动了B的一个Activity C,然后按Home键回到桌面,然后再单击B的桌面图标,这个时候并不是启动了B的主Activity,而是重新显示了已经被应用A启动的Activity C,或者说,C从A的任务栈转移到了B的任务栈中。可以这么理解,由于A启动了C,这个时候C只能运行在A的任务栈中,但是C属于B应用,正常情况下,它的TaskAffinity值肯定不可能和A的任务栈相同(因为包名不同)。所以,当B被启动后,B会创建自己的任务栈,这个时候系统发现C原本所想要的任务栈已经被创建了,所以就把C从A的任务栈中转移过来了。
否则,如果不设置allowTaskReparenting为true,则按照上述操作逻辑,应用A打开应用B的Activity C,然后点击home键返回桌面,然后在点击B的桌面图标,则会打开B的主Activity,而不是打开Activity C
问题2.3:Activity4种启动模式?
一个Activity的开启,相当于进栈,一个Activity的关闭相当于出栈。任务栈主要用来维护Activity的;我们平时手机上操作的界面都是任务栈栈顶的那个Activity。
1.standard模式:标准模式。只要打开一个Activity就会创建该Activity的一个实例,并入栈;
这是一种典型的多实例实现,一个任务栈中可以有多个实例,每个实例也可以属于不同的任务栈。在这种模式下,谁启动了这个Activity,那么这个Activity就运行在启动它的那个Activity所在的栈中。比如Activity A启动了Activity B(B是标准模式),那么B就会进入到A所在的栈中。
2.singleTop模式:栈顶复用模式。打开这个Activity之前会先判断当前栈顶是否是该Activity的实例,如果是直接拿来复用,不会创建新的Activity的实例,同时它的onNewIntent方法会被回调。如果栈顶不是,那么会创建新的实例并进栈。
应用场景: 系统短信接收发送界面,IM对话框 ,新闻客户端推送
3.singleTask模式:栈内复用模式。打开这个Activity之前会先判断当前任务栈是否有该Activity的实例,如果没有创建并进栈。如果有,直接复用并将其上方的Activity的实例移除栈,系统也会回调其onNewIntent。
应用场景:系统浏览器的浏览界面, 应用的主界面,可以让子页面全部出栈
4.singleInstance模式:单实例模式。打开这个Activity会单独创建一个新的任务栈来存放该Activity的实例,再次打开该Activity时直接复用这个任务栈中的Activity的实例,不会重新创建。不管是应用程序A开启该Activity或是应用程序B开启该Activity都是使用这个任务栈中的Activity的实例。
应用场景:呼叫来电
场景问题
Activity依次A→B→C→B,
其中B启动模式为singleTask,AC都为standard,⽣命周期分别怎么调⽤?
如果B启动模式为singleInstance⼜会怎么调⽤?
B启动模式为singleInstance不变,A→B→C的时候点击两次返回,⽣命周期如何调⽤。
1、A→B→C→B,B启动模式为singleTask启动A的过程,⽣命周期调⽤是(A)onCreate→(A)onStart→(A)onResume。
再启动B的过程,⽣命周期调⽤是(A)onPause→(B)onCreate→(B)onStart→(B)onResume→(A)onStop。
B→C的过程同上。
C→B的过程,由于B启动模式为singleTask,所以B会调⽤onNewIntent,并且将B之上的实例移除,也就是C会被移出栈。所以⽣命周期调⽤是(C)onPause→(B)onNewIntent→(B)onRestart→(B)onStart→(B)onResume→(C)onStop→(C)onDestory。
2、A→B→C→B,B启动模式为singleInstance
如果B为singleInstance,那么C→B的过程,C就不会被移除,因为B和C不在⼀个任务栈⾥⾯。所以⽣命周期调⽤是
(C)onPause→(B)onNewIntent→(B)onRestart→(B)onStart→(B)onResume→(C)onStop
3、A→B→C,B启动模式为singleInstance,点击两次返回键如果B为singleInstance,A→B→C的过程,⽣命周期还是同前⾯⼀样正常调⽤。但是点击返回的时候,由于AC同任务栈,所以C点击返回,会回到A,再点击返回才回到B。
所以⽣命周期是:
(C)onPause→(A)onRestart→(A)onStart→(A)onResume→(C)onStop→(C)onDestory。
再次点击返回,就会回到B,所以⽣命周期是:
(A)onPause→(B)onRestart→(B)onStart→(B)onResume→(A)onStop→(A)onDestory。
问题3:屏幕旋转时Activity的⽣命周期,如何防⽌Activity重建?
1.如果需要防⽌旋转时候,Activity重新创建的话需要做如下配置:在targetSdkVersion的值⼩于或等于12时,配置
android:configChanges="orientation"
, 在targetSdkVersion
的值⼤于12时,还需配置android:configChanges="orientation|screenSize"
,否则不生效
orientation
:屏幕方向发生了改变,比如旋转了手机屏幕
screenSize
:屏幕的尺寸发生了改变,当旋转手机屏幕,屏幕尺寸会发生变化.这个是API13新加的
keyboardHidden
:键盘的可访问性发生了改变,比如用户调出了键盘
以上3个最常用
2.不配置
android:configChanges="orientation|screenSize"
,切换屏幕的⽣命周期是:
onPause->onStop->onSaveInstanceState->onDestroy->onCreate->onStart->onRestoreInstanceState->onResume
3.配置
android:configChanges="orientation|screenSize"
,切换屏幕的⽣命周期是:
横竖屏切换不会重建Activity
,也不会调用onSaveInstanceState()
和onRestoreInstanceState()
方法
只会调用onConfigurationChanged()
方法,然后Activity的onPasue
,onStop
,onDestroy
,onCreate
,onStart
,onResume
等生命周期方法也不会执行
问题4:onCreate和onStart之间有什么区别?
1、可⻅与不可⻅的区别:前者不可⻅,后者可⻅。
2、执⾏次数的区别:onCreate⽅法只在Activity创建时执⾏⼀次,⽽onStart⽅法在Activity的切换以及按Home键返回桌⾯再切回应⽤的过程中被多次调⽤。因此Bundle数据的恢复在onStart中进⾏⽐onCreate中执⾏更合适。
3、onCreate能做的事onStart其实都能做,但是onStart能做的事onCreate却未必适合做。如前⽂所说的,setContentView和资源初始化在两者都能做,然⽽像动画的初始化在onStart中做⽐较好。
问题5:onStart⽅法和onResume⽅法有什么区别?
1、是否在前台:onStart⽅法中Activity可⻅但不在前台,不可交互,⽽onResume⽅法中Activity在前台。
2、职责不同:onStart⽅法中主要还是进⾏初始化⼯作,⽽onResume⽅法,根据官⽅的建议,可以做开启动画和独占设备的操作。
问题6:onPause⽅法和onStop⽅法有什么区别?
1、是否可⻅:onPause时Activity可⻅,onStop时Activity不可⻅,但Activity对象还在内存中。
2、在系统内存不⾜的时候可能不会执⾏onStop⽅法,因此程序状态的保存、独占设备和动画的关闭、以及⼀些数据的保存最好在onPause中进⾏,但要注意不能太耗时。
问题7:onStop⽅法和onDestroy⽅法有什么区别?
onStop阶段Activity还没有被销毁,对象还在内存中,此时可以通过切换Activity再次回到该Activity,⽽onDestroy阶段Acivity被销毁。
问题8:A启动B与B返回A的生命周期?
A启动B:A--onPause,B--onCreate,B--onStart,B--onResume,A--onStop
B返回A:B--onPause,A---onRestart,A---onStart,A--onResume,B---onStop,B--onDestroy
总结一下吧,不管是A启动B还是B返回A,总是先执行自己的 onPause方法,然后是另外一个页面的一系列生命周期,再是自己的onStop
有图的例子如下
1.MainActivity
跳转 SecondActivity
MainActivity-->onPause()
SecondActivity-->onCreate()
SecondActivity-->onStart()
SecondActivity-->onResume()
MainActivity-->onStop()
2.此时点击返回键,生命周期
SecondActivity-->onPause()
MainActivity-->onRestart()
MainActivity-->onStart()
MainActivity-->onResume()
SecondActivity-->onStop()
SecondActivity-->onDestroy()
问题9:为何设计成先⾛ onPause,等到对⽅ onResume 后再⾛ onStop 呢?
因为处于前台的窗⼝只能有⼀个,为了使跳转到的 Activity 能够前台显示,⾸先得使此前的 Activity 离开前台模式,所以也可以这么说,onPause 对于系统的意义就在于离开前台模式,对于开发者的意义就在于离开前台时有机会做⼀些⼩操作。
2.Service
问题1:、android中进程的优先级?
1、前台进程:即与⽤户正在交互的Activity或者Activity⽤到的Service等,如果系统内存不⾜时前台进程是最晚被杀死的。
2、可⻅进程:可以是处于暂停状态(onPause)的Activity或者绑定在其上的Service,即被⽤户可⻅,但由于失了焦点⽽不能与⽤户交互。
3、服务进程:其中运⾏着使⽤startService⽅法启动的Service,虽然不被⽤户可⻅,但是却是⽤户关⼼的,例如⽤户正在⾮⾳乐界⾯听的⾳乐或者正在⾮下载⻚⾯下载的⽂件等,当系统要空间运⾏时,前两者进程才会被终⽌。
4、后台进程:其中运⾏着执⾏onStop⽅法⽽停⽌的程序,但是却不是⽤户当前关⼼的,例如后台挂着的QQ,这时的进程系统⼀旦没了有内存就会⾸先被杀死。
5、空进程:不包含任何应⽤程序的进程,这样的进程系统是⼀般不会让它存在的。
问题2:服务启动⼀般有⼏种?
1、startService:onCreate()--->onStartCommand() ---> onDestory()如果服务已经开启,不会重复的执⾏onCreate(), ⽽是会调⽤onStartCommand()。⼀旦服务开启就跟调⽤者没有任何关系了。开启者退出了,开启者挂了,服务还在后台⻓期的运⾏,开启者不能调⽤服务⾥⾯的⽅法。
2、bindService:onCreate() --->onBind()--->onunbind()--->onDestory()bind的⽅式开启服务,绑定服务,调⽤者挂了,服务也会跟着挂掉。绑定者可以调⽤服务⾥⾯的⽅法。
问题3:如何管理Service的生命周期
1.startService 开启服务的生命周期
①.onCreate,多次调用startService,该方法也只会调用一次
②.onStartCommand(每调用一下startService ,该方法就会调用)
③.onStart(每调用一下startService ,该方法就会调用)
2.stopService 是关闭服务,手动调用后就会调用 onDestroy方法,当一个服务既被startService
,又被bindService
,如果没有解绑服务,直接调用stopService
是不能关闭的,需要先解绑在关闭服务
3.bindService开启服务,内部会调用onCreate和onBind
unBindService解除Service绑定,内部会调用onUnbind和onDestroy
问题4:为什么bindService可以跟Activity⽣命周期联动?
1、bindService ⽅法执⾏时,LoadedApk 会记录 ServiceConnection 信息。
2、Activity 执⾏ finish ⽅法时,会通过 LoadedApk 检查 Activity 是否存在未注销/解绑的 BroadcastReceiver 和 ServiceConnection,如果有,那么会通知 AMS 注销/解绑对应的 BroadcastReceiver 和 Service,并打印异常信息,告诉⽤户应该主动执⾏注销/解绑的操作。
问题5:直接在Activity中创建⼀个thread跟在service中创建⼀个thread之间的区别?
1.在Activity中被创建:该Thread的就是为这个Activity服务的,完成这个特定Activity交代的任务,主动通知该Activity⼀些消息和事件,Activity销毁后,该Thread也没有存在的意义了。
2.在Service中被创建:这是保证最⻓⽣命周期Thread的唯⼀⽅式,只要整个Service不退出,Thread就可以⼀直在后台执⾏,⼀般在Service的onCreate()中创建,在onDestroy()中销毁。所以,在Service中创建的Thread,适合⻓期执⾏⼀些独⽴于APP的后台任务,⽐较常⻅的就是:在Service中保持与服务器端的⻓连接。
问题6:Service和IntentService的区别?
1.IntentService 继承 Service
2.内部有一个工作线程HanderThread来处理耗时操作,执行完成后会结束,可以启动多次,会加入工作队列,一个一个执行
3.每次启动一个后台任务 就需要启动一次IntentService
4.IntentService内部是通过消息的方式发送给HandlerThread
的,然后由Handler
中的Looper
来处理消息
问题7:启动服务和绑定服务先后次序问题?
start方式开启服务: 长期运行在后台,在设置中可以看到。
bind方式开启服务: 是一个隐形的服务,不会长期运行在后台,生命周期依赖于开启者。
1.第一次bind方式绑定服务,会执行服务生命周期中的 OnCreate和onbind方法,再次绑定,哪个方法都不会调用。
2.bind方式开启的服务是一个隐形的服务,在设置中找不到
3.bind方式开启的服务,生命周期依赖于开启者的Activity,Activity销毁了,bind的这个服务就销毁了。就会执行生命周期中的Ondestroy方法。服务与开启者,不求同生,但求同死。
4.bind方式开启服务,在Activity销毁之前需要解绑,不解绑会报红,但是不报错,为了代码严谨需要在Activity的ondestroy方法中解绑服务。 unbindService();
5.bind方式开启服务,只能解绑一次,再次解绑时,绑定的那个对象已经被销毁了,所以会报错
1.先绑定服务后启动服务,绑定服务会转为运行服务状态,
2.先启动服务后绑定服务,并不会转为绑定服务状态,还是运行服务状态
总结:
1.启动服务的优先级比绑定服务高,不管谁先启动都会转化为运行服务状态
2.服务在其托管的主线程中运行(UI线程)
问题8:aidl?
一句话总结,AIDL帮我们生产了binder对象,同时也生成了跨平台接口的那个转换类 Stub,以及客户端能拿到的proxy代理对象
3.BroadcastReceiver
问题1:⼴播注册⼀般有⼏种,各有什么优缺点?
第⼀种是常驻型(静态注册):当应⽤程序关闭后如果有信息⼴播来,程序也会被系统调⽤,⾃⼰运⾏。
优点: 在android的⼴播机制中,动态注册优先级⾼于静态注册优先级,因此在必要情况下,是需要动态注册⼴播接收者的。缺点: 当⽤来注册的 Activity 关掉后,⼴播也就失效了。
第⼆种不常驻(动态注册):⼴播会跟随程序的⽣命周期。优点: ⽆需担忧⼴播接收器是否被关闭,只要设备是开启状态,⼴播接收器就是打开着的。
问题2:BroadcastReceiver,LocalBroadcastReceiver 区别?
1、与BroadcastReceiver是以 Binder 通讯⽅式为底层实现的机制不同,LocalBroadcastManager 的核⼼实现实际还是 Handler,只是利⽤到了IntentFilter 的匹配功能,⾄于 BroadcastReceiver 换成其他接⼝也⽆所谓,只是顺便利⽤了现成的类和概念⽽已。
2、LocalBroadcastManager因为是 Handler 实现的应⽤内的通信,⾃然安全性更好,效率更⾼。
问题3:⼴播传输的数据是否有限制,是多少,为什么要限制?
1.Intent在传递数据时是有⼤⼩限制的,⼤约限制在1MB之内,你⽤Intent传递数据,实际上⾛的是跨进程通信(IPC),跨进程通信需要把数据从内核copy到进程中,每⼀个进程有⼀个接收内核数据的缓冲区,默认是1M;如果⼀次传递的数据超过限制,就会出现异常。
2.不同⼚商表现不⼀样有可能是⼚商修改了此限制的⼤⼩,也可能同样的对象在不同的机器上⼤⼩不⼀样。
3.传递⼤数据,不应该⽤Intent;考虑使⽤ContentProvider或者直接⽤匿名共享内存,在简单情况下也可以考虑分段传输。
问题4:如何通过⼴播拦截和abort⼀条短信?
可以监听这条信号,在传递给真正的接收程序时,我们将⾃定义的⼴播接收程序的优先级⼤于它,并且取消⼴播的传播,这样就可以实现拦截短信的功能了。
问题5:如何让程序⾃动启动?
定义⼀个Braodcastreceiver,action为BOOT—COMPLETE,当接受到⼴播后启动程序即可。
问题6:静态注册的⼴播是什么时候注册的?
⼿机开机的时候,会重新安装⼀遍所有APP,安装过后,⼿机会扫描data/app放置⽬录,然后就会解析APK⾥⾯的AndroidManifest配置⽂件,并进⾏静态⼴播的注册。
4.ContentProvider
问题1:ContentProvider如何使⽤?
进⾏跨进程通信,实现进程间的数据交互和共享。通过Context 的getContentResolver() 获得实例,通过Uri匹配进⾏数据的增删改查。ContentProvider使⽤表的形式来组织数据,⽆论数据的来源是什么,ConentProvider 都会认为是⼀种表,然后把数据组织成表格。
问题2:说说ContentProvider、ContentResolver、ContentObserver 之间的关系?
1.ContentProvider:管理数据,提供对数据的增删改查操作,数据源可以是数据库、⽂件、XML、⽹络等,ContentProvider为这些数据的访问提供了统⼀的接⼝,可以⽤来做进程间数据共享。
2.ContentResolver:ContentResolver可以为不同的URI操作不同的ContentProvider中的数据,外部进程可以通过ContentResolver与ContentProvider进⾏交互。
3.ContentObserver:观察ContentProvider中的数据变化,并将变化通知给外界。