Android面试复习笔记 1

1. 四大组件

$. Context

Context的父类是Object。子类是ContextWrapper和ContextImpl。ContextWarpper的子类是Application,Service,ContextThemeWrapper(子类是Activity)。

1.1 Activity

a. 生命周期

完整生命周期: 打开 onCreate -> onStart(可见) -> onResume(获得焦点) 关闭-> onPause(失去焦点) -> onStop(不可见) -> onDestroy

最小化然后打开页面: onStop -> onRestart -> onStart

当前页面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

横竖屏切换切换:

  1. 不设置Activity的android:configChanges时,切屏会重新调用各个生命周期
    onPause -> onStop -> onDestroy -> onCreate -> onStart -> onResume
  2. 设置Activity的android:configChanges="orientation"时,切屏先调用完onConfigurationChanged()方法后,重新调用各个生命周期,但只会执行一次,之后只执行onConfigurationChanged方法
  3. 设置Activity的android:configChanges="orientation|keyboardHidden"时,切屏不会重新调用各个生命周期,只会执行onConfigurationChanged方法

b. 启动模式

众所周知当我们多次启动同一个Activity时,系统会创建多个实例,并把它们按照先进后出的原则一一放入任务栈中,当我们按back键时,就会有一个activity从任务栈顶移除,重复下去,直到任务栈为空,系统就会回收这个任务栈。但是这样以来,系统多次启动同一个Activity时就会重复创建多个实例,这种做法显然不合理,为了能够优化这个问题,Android提供四种启动模式来修改系统这一默认行为。

launchMode 说明 应用场景
standard 这个模式是默认的启动模式,即标准模式,在不指定启动模式的前提下,系统默认使用该模式启动Activity,每次启动一个Activity都会重写创建一个新的实例,不管这个实例存不存在,这种模式下,谁启动了该模式的Activity,该Activity就属于启动它的Activity的任务栈中。这个Activity它的onCreate(),onStart(),onResume()方法都会被调用。
singleTop 单一顶部,这个模式下,如果新的activity已经位于栈顶,那么这个Activity不会被重写创建,同时它的onNewIntent方法会被调用,通过此方法的参数我们可以去除当前请求的信息。如果栈顶不存在该Activity的实例,则情况与standard模式相同。需要注意的是这个Activity它的onCreate(),onStart()方法不会被调用,因为它并没有发生改变。 消息推送界面,新闻详情页面等
singleTask 单一任务,在这个模式下,如果栈中存在这个Activity的实例就会复用这个Activity,不管它是否位于栈顶,复用时,会将它上面的Activity全部清出栈,并且会回调该实例的onNewIntent方法。如果不存在,就看taskAffinity属性对应的Task是否存在,如果存在,就把Activity压入该Task内栈里;否则,就新建一个Task,再把Activity压入该Task内栈里。 应用主界面
singleInstance 单一实例,这种模式下的Activity会单独占用一个Task栈,具有全局唯一性,整个系统中就这么一个实例,由于栈内复用的特性,后续的请求均不会创建新的Activity实例,除非这个特殊的任务栈被销毁了。以singleInstance模式启动的Activity在整个系统中是单例的,如果在启动这样的Activiyt时,已经存在了一个实例,那么会将他调度到前台,重用这个实例。 闹钟,浏览器,电话等

c. 跳转传值、Intent

Activity之间的跳转需要使用到Intent组件

  1. 显示跳转
    创建intent对象,设置明确的跳转对象。
  2. 隐式跳转
    没有明确指定开启哪个控件,而是通过action和category等属性信息,系统根据这些信息来进行分析,然后寻找目标。
    例如打开相机,浏览器,电话等。

Activity之间的通过Intent组件附带参数实现传值

  1. 8种基本数据类型及其数组 (byte 字节型、 short 短整型 、 int 整型 、 long 长整型 、 float 浮点型 、double、 boolean 布尔型 、 char 字符型 )
  2. String(String实现了 Serializable )/CharSequence实例类型的数据及其数组
  3. 实现了Parcelable的对象及其数组
  4. 实现了 Serializable 的对象及其数组

Activity之间的数据回传
通过startActivityForResult(Intent intent,int requestCode)方法启动,在新页面设置setResult()数据,关闭后在初始页面重写onActivityResult方法来就可得到返回数据。

d. Fragment

  • Fragment可以使你能够将activity分离成多个可重用的组件,每个都有它自己的生命周期和UI。

  • Fragment可以轻松得创建动态灵活的UI设计,可以适应于不同的屏幕尺寸。从手机到平板电脑。

  • Fragment是一个独立的模块,紧紧地与activity绑定在一起。可以运行中动态地移除、加入、交换等。

  • Fragment提供一个新的方式让你在不同的安卓设备上统一你的UI。

  • Fragment 解决Activity间的切换不流畅,轻量切换。

  • Fragment 替代TabActivity做导航,性能更好。

  • Fragment 在4.2.版本中新增嵌套fragmeng使用方法,能够生成更好的界面效果。

  • Fragment做局部内容更新更方便,原来为了到达这一点要把多个布局放到一个activity里面,现在可以用多Fragment来代替,只有在需要的时候才加载Fragment,提高性能

1.生命周期

onAttach - onCreate - onCreateView - onActivityCreated - onStart - onResume - onPause - onStop -  onDestroyView - onDestroy - onDetach

onAttach:onAttach()在fragment与Activity关联之后调调查用。需要注意的是,初始化fragment参数可以从getArguments()获得,但是,当Fragment附加到Activity之后,就无法再调用setArguments()。所以除了在最开始时,其它时间都无法向初始化参数添加内容。

onCreate:fragment初次创建时调用。尽管它看起来像是Activity的OnCreate()函数,但这个只是用来创建Fragment的。此时的Activity还没有创建完成,因为我们的Fragment也是Activity创建的一部分。所以如果你想在这里使用Activity中的一些资源,将会获取不到。比如:获取同一个Activity中其它Frament的控件实例。(代码如下:),如果想要获得Activity相关联的资源,必须在onActivityCreated中获取。

onCreateView:在这个fragment构造它的用户接口视图(即布局)时调用。

onActivityCreated:在Activity的OnCreate()结束后,会调用此方法。所以到这里的时候,Activity已经创建完成!在这个函数中才可以使用Activity的所有资源。如果把下面的代码放在这里,获取到的btn_Try的值将不会再是空的!

onDestroyView:如果Fragment即将被结束或保存,那么撤销方向上的下一个回调将是onDestoryView()。会将在onCreateView创建的视图与这个fragment分离。下次这个fragment若要显示,那么将会创建新视图。这会在onStop之后和onDestroy之前调用。这个方法的调用同onCreateView是否返回非null视图无关。它会潜在的在这个视图状态被保存之后以及它被它的父视图回收之前调用。

onDestroy:当这个fragment不再使用时调用。需要注意的是,它即使经过了onDestroy()阶段,但仍然能从Activity中找到,因为它还没有Detach。

onDetach:Fragment生命周期中最后一个回调是onDetach()。调用它以后,Fragment就不再与Activity相绑定,它也不再拥有视图层次结构,它的所有资源都将被释放。

2.如何添加

1.获取到FragmentManager,在V4包中通过getSupportFragmentManager,在系统中原生的Fragment是通过getFragmentManager获得的。
2.开启一个事务,通过调用beginTransaction方法开启。
3.向容器内加入Fragment,一般使用add或者replace方法实现,需要传入容器的id和Fragment的实例。
4.提交事务,调用commit方法提交。

3.数据传递
①Activit传递数据给Fragment:

在Activity中创建Bundle数据包,调用Fragment实例的setArguments(bundle) 从而将Bundle数据包传给Fragment,然后Fragment中调用getArguments获得 Bundle对象,然后进行解析就可以了

②Fragment传递数据给Activity

在Fragment中定义一个内部回调接口,再让包含该Fragment的Activity实现该回调接口, Fragment就可以通过回调接口传数据了。

③Fragment与Fragment之间的数据互传

其实这很简单,找到要接受数据的fragment对象,直接调用setArguments传数据进去就可以了。

1.2 Service

a. 说明

Service和Activity都是Context的子类。
Service也是四大组件之一,所以必须在AndroidManifest中配置。
服务是android实现程序后台运行的方案。服务的运行不依赖于任何用户界面,即使程序切到后台或者打开另外一个程序,服务也能够保持运行。
要注意的是,服务并不是运行在一个独立的进程,而是依赖于创建服务时所在的应用进程。当改应用进程被杀死时候,所有依赖该进程的服务也会停止运行。
它默认是在UI线程,所以不能做耗时操作,除非创建子线程来完成。

b. 分类

Service分为本地服务(LocalService)和远程服务(RemoteService):

  1. 本地服务,指的是服务和启动服务的activity在同一个进程,主进程被Kill后,服务便会终止。
  2. 远程服务,指的是服务和启动服务的activity不在同一个进程,为独立的进程。对应进程名格式为所在包名加上你指定的android:process字符串。由于是独立的进程,因此在Activity所在进程被Kill的时候,该服务依然在运行,不受其他进程影响,有利于为多个进程提供服务具有较高的灵活性。
    绑定远程服务:
    1).在服务的内部创建一个内部类,提供一个方法,可以间接调用服务的方法
    2).把暴露的接口文件的扩展名改为.aidl文件 去掉访问修饰符
    3).实现服务的onbind方法,继承Bander和实现aidl定义的接口,提供给外界可调用的方法
    4).在activity 中绑定服务。bindService()
    5).在服务成功绑定的时候会回调 onServiceConnected方法 传递一个 IBinder对象
    6).aidl定义的接口.Stub.asInterface(binder) 调用接口里面的方法

c. 启动方式

分为startService和bindService:

  1. startService启动的服务:主要用于启动一个服务执行后台任务,不进行通信。停止服务使用stopService。

生命周期:onCreate-onStartCommand-onDestroy
特点:
第一次startService会触发onCreate和onStartCommand方法,以后每次startService只会触发onStartCommand。
通过startService启动后,service会一直无限期运行下去,只有外部调用了stopService()或stopSelf()方法时,该Service才会停止运行并销毁。
多次调用,不会多次创建,但会多次启动。
注意事项:
Android 8.0 不再允许后台service直接通过startService方式去启动,官方为我们提供了新的启动服务方法:startForegroundService,使用这个方法启动的 服务必须在5秒内使用startForeground方法以显示新服务的用户可见通知,否则的话将抛出异常:Context.startForegroundService() did not then call Service.startForeground()。

  1. bindService启动的服务:该方法启动的服务可以进行通信。停止服务使用unbindService。

生命周期:onCreate-onBind-onUnbind-onDestroy
特点:第一次bindService会走onCrate,onBind,以后每次bindService都不会触发任何方法。
bindService是可交互服务,前台页面可以调用后台服务的方法。
绑定端销毁时会自动解除绑定。
当没有任何控件与Service绑定时,Service会自行销毁。
多次调用,不会多次创建,也不会多次绑定

要想让Service支持bindService调用方式,需要做以下事情:
1.在Service的onBind()方法中返回IBinder类型的实例。
2.onBInd()方法返回的IBinder的实例需要能够返回Service实例本身。

绑定端要做的事情:
1.创建ServiceConnection类型实例,并重写onServiceConnected()方法和onServiceDisconnected()方法。
2.当执行到onServiceConnected回调时,可通过IBinder实例得到Service实例对象,这样可实现绑定端与Service的连接。
3.onServiceDisconnected回调被执行时,表示绑定端与Service断开连接,在此可以写一些断开连接后需要做的处理。

应用场景:

如果需要启动一个后台服务长期处理某些任务那么就用startService,调用stopService才会停止。
如果想要与正在运行的Service取得联系,那么就要使用bindService,调用unbindService才会停止。或者利用广播通知。

d. IntentService

IntentService,是Service的子类,比普通的Service增加了额外的功能,是用来处理异步请求的一个类。

Service本身存在两个问题:
Service不会专门启动一条单独的进程,Service与它所在应用位于同一个进程中;
Service也不是专门一条新线程,因此不应该在Service中直接处理耗时的任务;

IntentService特征:
IntentService会创建独立的工作线程来处理所有耗时任务。所有请求处理完它会自动停止。
它可以启动多次,每一个耗时任务都会以队列形式在onHandleIntent回调方法中执行,每次只执行一个。
IntentService内部封装了HandlerThread 和 Handler。

使用方法:
创建IntentService时只需要实现他的构造方法和onHandlerIntent方法即可。在onHandlerIntent方法中进行耗时操作。

e. 如何保证Service不被杀死?

  1. 在onStartCommand方法中,返回START_STICKY。

START_NOT_STICKY
如果返回START_NOT_STICKY,表示当Service运行的进程被Android系统强制杀掉之后,不会重新创建该Service。

START_STICKY
如果返回START_STICKY,表示Service运行的进程被Android系统强制杀掉之后,Android系统会将该Service依然设置为started状态(即运行状态),但是不再保存onStartCommand方法传入的intent对象,然后Android系统会尝试再次重新创建该Service,并执行onStartCommand回调方法,但是onStartCommand回调方法的Intent参数为null,也就是onStartCommand方法虽然会执行但是获取不到intent信息。
比如一个用来播放背景音乐功能的Service就适合返回该值。

START_REDELIVER_INTENT
如果返回START_REDELIVER_INTENT,表示Service运行的进程被Android系统强制杀掉之后,与返回START_STICKY的情况类似,Android系统会将再次重新创建该Service,并执行onStartCommand回调方法,但是不同的是,Android系统会再次将Service在被杀掉之前最后一次传入onStartCommand方法中的Intent再次保留下来并再次传入到重新创建后的Service的onStartCommand方法中,这样我们就能读取到intent参数。只要返回START_REDELIVER_INTENT,那么onStartCommand重的intent一定不是null。如果我们的Service需要依赖具体的Intent才能运行(需要从Intent中读取相关数据信息等),并且在强制销毁后有必要重新创建运行,那么这样的Service就适合返回START_REDELIVER_INTENT。

2.提高Service的优先级

在AndroidManifest.xml文件中对于intent-filter可以通过android:priority = "1000"这个属性设置最高优先级,1000是最高值,如果数字越小则优先级越低,同时适用于广播。

3.提升Service进程的优先级

当系统进程空间紧张时,会依照优先级自动进行进程的回收。
Android将进程分为5个等级,按照优先级由高到低依次为:
1).前台进程 Foreground process
2).可视进程 Visible process
3).服务进程 Serviceground process
4).后台进程 Background process
5).空进程 Empty process
可以使用startForeground将service放到前台状态,这样低内存时,被杀死的概率会低一些。

4.系统广播监听Service状态

在onDestroy方法里重启Service
当service走到onDestroy()时,发送一个自定义广播,当收到广播时,重新启动service。

5.将APK安装到/system/app,变身为系统级应用

1.3 BroadcastReceiver

BroadcastReceiver广播接收器:主要用于接收系统或者app发送的广播事件。

a. 广播的注册方式

  1. 静态注册(在AndroidManifest.xml清单文件中注册)
    静态注册依附于清单文件,只要APP启动过一次,所静态注册的广播就会生效,无论当前的APP处于停止使用还是正在使用状态。只要相应的广播事件发生,系统就会遍历所有的清单文件,通知相应的广播接收者接收广播,然后调用广播接收者的onReceiver方法。

  2. 动态注册(在代码中注册)
    动态注册方式依赖于所注册的组件,当APP关闭后,组件对象都不在了动态注册的代码都不存在了,所动态注册监听的action自然不在生效。

$ 区别:
静态注册的广播传播速度要远远慢于动态注册的广播。

$ 优先级:
动态注册的广播接收器优先级高于静态注册的。
动态注册的广播接收器优先级按照注册先后顺序排序。
静态注册的广播接收器优先级按照包名顺序扫描顺序排序。

b. 广播的分类

  1. 无序广播

是一种完全异步执行的广播,在广播发出之后,所有的BroadcastReceiver几乎在同一时刻收到这个广播消息,它们之间没有先后顺序,这种广播的效率较高,并且不能被拦截。
发送方法 sendBroadcast()

  1. 有序广播

是一种完全同步的广播,在广播发出后只能有一个BroadcastReceiver能接收到这个广播消息,当这个BroadcastReceiver中的逻辑执行完毕后,广播才能继续向下传递。所以这个广播是有顺序的,所以这种广播也是可以被拦截的,如果被拦截了后面的BroadCastReceiver则不能收到广播消息了。
发送方法 sendOrderedBroadcast()

  1. 本地广播

上面介绍的前两者都是全局广播,任何一方发出广播本手机的任何一个程序都能收到对应的广播。
本地广播是局部的广播基于本程序的广播,其他的程序无法收到这个广播。

本地广播接收者进行注册,必须在代码中注册,清单文件注册是无效的。
拿到LocalBroadcastManager对象,对固定的Receiver进行注册,成为本地广播接收者。
使用LocalBroadcastManager发送广播。

  1. sticky广播

sticky粘性的意思。这种广播一般不会终止,只要有符合条件的广播接收者能接收广播,那么就会发送给他广播。永远不会终止发送广播,除非某个广播接收者告诉它不要再发送广播了。
使用时添加权限 <user-permission android:name="android.permission.BROADCAST_STICKY"/>
发送 sendStickyBroadcast()
停止 removeStickyBroadcast()

1.4 ContentProvide

a. 简介

内容提供者,为储存和获取数据提供统一接口,可用于跨进程通信,进行数据交互共享。
ContentProvider的底层是采用 Android中的Binder机制。
案例:利用手机自带数据库存储数据。访问手机相册照片。获取手机通讯录。

b. 延伸

在Android安全模型中,一个应用程序编写的文件无法被其他任何应用程序所读写。每个程序都有自己的Linux用户ID和数据目录(data/data/包名),以及其受保护的内存空间。Android程序可通过下面两种方式进行彼此间的通信:
1.IPC(Inter-Process Communication,进程间通信):一个进程使用AIDL(接口定义语言)和Ibinder接口声明一个任意的API。调用该API时,将在进程间安全且有效地对参数进行编组,这项先进技术用于对后台Service线程进行远程过程调用。
2.ContentProvider:ContentProvider 为安卓四大组件之一,进程中系统中将它们本身注册为某些数据类型的提供者。请求信息时,Android就会通过一个固定的API调用这些进程,以它们认为合适的方式查询或修改内容。

c. 使用方式

因为无论数据的来源是什么,ContentProvider都会认为它是一种表,故使用时候,常常将其与SQLiteOpenHelper结合起来。
1.首先需要在mainfast.xml注册,需要加入android:authorities属性。
2.然后根据需求定义一个类,继承ContentProvider,重写增删改查的方法。
3.最后利用ContentResolver通过对应URI获取数据。

d. 使用场景

1.获取通讯录
2.获取相机拍照照片
自Android 7.0后系统禁止应用向外部公开file://URI ,因此需要FileProvider来向外界传递URI。
FileProvider是ContentProvider的一个子类,用于应用程序之间私有文件的传递。传递的形式是content : //Uri,使用时需要在清单文件中注册。然后在res目录下新建一个xml文件夹,并且创建一个xml,指明文件路径。我们在代码中获取URI的方法就是FileProvider.getUriForFile(“上下文”,“清单文件中的authorities的值”,“共享的文件”)

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,761评论 5 460
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,953评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,998评论 0 320
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,248评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,130评论 4 356
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,145评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,550评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,236评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,510评论 1 291
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,601评论 2 310
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,376评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,247评论 3 313
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,613评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,911评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,191评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,532评论 2 342
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,739评论 2 335

推荐阅读更多精彩内容