安卓面试基础(如会必过)

Activity
1、 什么是Activity?
Activity是四大组件之一,他给用户的感受就是一个用户交互界面。一个Activity就是一个可见的界面。
他的特点是:1、可见 2、可交互
他之所以可交互,是因为他同时实现了Window.Callback和KeyEvent.Callback, 可以处理与窗体用户交互的事件和按键事件.这两个特点,是他和service最大的区别。
一个Activity在创建于销毁的过程中,会经历一些生命周期。
如果界面有共同的特点或者功能的时候,还会自己定义一个BaseActivity.
安卓面试基础(如会必过)_第1张图片
2、Activity的生命周期

a、简述一下生命周期
生命周期描述的是一个类 从创建(new出来)到死亡(垃圾回收)的过程中会执行的方法…
在这个过程中 会针对不同的生命阶段会调用不同的方法

Activity从创建到销毁有多种状态,从一种状态到另一种状态时会激发相应的回调方法,这些回调方法包括:onCreate onDestroy onStop onStart onResume onPause onRestart
当从A界面跳转到B界面的时候,A界面会调用onPause onStop B界面会调用onCreate、onStart、onResume等。在回到A界面的时候,A界面会调用onReStart、onStart、onResume
如果B界面是透明的activity,那么进行跳转的时候,A界面是不会调用onStop的,只会调用onPause 再回到A界面的时候,A界面会调用onResume
b、A界面跳转到B界面的时候,再回到A界面,A界面必然会执行的是哪几个方法。
两个Activity之间的跳转必然会执行的是onResume方法,这个具体的应用场景是每次回到该界面的时候,如果界面需要展示最新的数据,那么可以在该方法中实现。
多媒体播放视频的时候, 来了一个电话. onStop() 视频, 视频声音设置为0 , 记录视频播放的位置 mediaplayer.pause();
onResume() 根据保存的状态恢复现场. mediaplayer.start();
c、在屏幕旋转的时候,activity的生命周期是怎样的?
横竖屏进行切换的时候,默认的情况下,Activity会重新的调用onCreate方法。因为竖屏的activity销毁了,再生成一个横屏的activity 。
在AndroidManifest.xml可以进行配置,我们可以通过android:configChanges进行配置。android:configChanges=“orientation|keyboardHidden|screenSize” 配置了之后,横竖屏切换的时候,就不会调用onCreate了,而是调用onConfigurationChanged的方法。
在一些特殊应用中,屏幕的方向是写死的,比如游戏。在AndroidManifest中配置android:screenOrientation=“landscape"就可以了。
d、讲一讲你对activity的理解
e、设置activity的样式为窗口的样式,对生命周期有什么影响?
设置窗口样式,需要在配置文件中增加theme的属性
android:theme=”@android:style/Theme.Dialog"
activity设置为窗口样式的时候,当启动这个activity的时候,之前那个activity是不会走onStop方法的,而是只走到了onPause方法。

3、你后台的Activity被系统 回收如何在被系统回收之前保存当前状态?
安卓面试基础(如会必过)_第2张图片
除了在栈顶的activity,其他的activity在系统资源匮乏的时候,都有可能会被系统回收。这时候系统会调用onSaveInstanceState方法,我们可以往bundle里面存放数据。在activity onCreate里面我们先判断一下bundle是不是为空,如果不为空,就代表这个activity之前被系统回收掉,应该恢复一下现场。我们就可以从bundle里面取值。

4、对android主线程的运用和理解
a、主线程也就是UI线程,四大组件都是运行在主线程中的。
b、主线程中有一个消息队列,主要处理窗口绘制、按钮响应等消息。
c、如果在主线程里面做耗时的操作,会导致窗口绘制等消息得不到及时的处理,从而有可能会报出anr的错误。

安卓面试基础(如会必过)_第3张图片

5、如何避免anr?如何解决anr?
anr是android not response 安卓无响应,这里指的是主线程无响应。将耗时的操作放在子线程中进行可以有效的避免anr。如果出现了anr,我们可以通过log信息以及traces.txt文件进行分析。
traces.txt里面记录的是stack信息。

6、Activity的数据传递
a、基础的数据类型通过Bundle进行传递
b、传递对象的话,需要该对象实现Serializable或者Parcelable接口,放到bundle进行传递。
c、在Application中进行存储。其他界面要用的话,就直接来application取就可以了。一个应用程序application的实例只有一个。
d、大对象,比如bitmap,我们一般都不传递这个对象,我们传递的一般都是路径就可以了。然后通过URI.fromFile()来传递URI

  1. 如何退出Activity?
    退出activity我们只需要调用finish就可以了。退出activity 会执行 onDestroy()方法。
    如何一次性的退出多个Activity?
    a、抛异常强制退出:
    该方法通过抛异常,使程序Force Close。
    验证可以,但是,需要解决的问题是,如何使程序结束掉,而不弹出Force Close的窗口。
    b、记录打开的Activity:
    每打开一个Activity,就记录下来。放到application里面去存起来。在需要退出时,关闭每一个Activity即可。
    8、Activity的启动模式
    首先我们来看下Task的定义,Google是这样定义Task的:a task is what the user experiences as an “application.” It’s a group of related activities, arranged in a stack. A task is a stack of activities, not a class or an element in the manifest file. 这意思就是说Task实际上是一个Activity栈,通常用户感受的一个Application就是一个Task。从这个定义来看,Task跟Service或者其他Components是没有任何联系的,它只是针对Activity而言的。
    Activity有不同的启动模式, 可以影响到task的分配
    Task,简单的说,就是一组以栈的模式聚集在一起的Activity组件集合。它们有潜在的前后驱关联,新加入的Activity组件,位于栈顶,并仅有在栈顶的Activity,才会有机会与用户进行交互。而当栈顶的Activity完成使命退出的时候,Task会将其退栈,并让下一个将跑到栈顶的Activity来于用户面对面,直至栈中再无更多Activity,Task结束。

standard", “singleTop”, “singleTask”, “singleInstance”。

standard模式, 是默认的也是标准的Task模式,在没有其他因素的影响下,使用此模式的Activity,会构造一个Activity的实例,加入到调用者的Task栈中去,对于使用频度一般开销一般什么都一般的Activity而言,standard模式无疑是最合适的,因为它逻辑简单条理清晰,所以是默认的选择。

而singleTop模式,基本上于standard一致,仅在请求的Activity正好位于栈顶时,有所区别。此时,配置成singleTop的Activity,不再会构造新的实例加入到Task栈中,而是将新来的Intent发送到栈顶Activity中,栈顶的Activity可以通过重载onNewIntent来处理新的Intent(当然,也可以无视…)。这个模式,降低了位于栈顶时的一些重复开销

singleTask,和singleInstance,则都采取的另辟Task的蹊径。
标志为singleTask的Activity,最多仅有一个实例存在,并且,位于以它为根的Task中。所有对该Activity的请求,都会跳到该Activity的Task中展开进行。singleTask,很象概念中的单件模式,所有的修改都是基于一个实例,这通常用在构造成本很大,但切换成本较小的Activity中。最典型的例子,还是浏览器应用的主Activity(名为Browser…),它是展示当前tab,当前页面内容的窗口。它的构造成本大,但页面的切换还是较快的,于singleTask相配,还是挺天作之合的。

singleInstance显得更为极端一些。在大部分时候singleInstance与singleTask完全一致,唯一的不同在于,singleInstance的Activity,是它所在栈中仅有的一个Activity, 这个栈,只有一个activity

activity是运行在任务栈中的,一个activity启动另外一个activity,默认的情况下,新的activity也是运行在同一个任务栈里的。service和广播接收者也是没有任务栈的,所以,他们启动activity的时候,给intent设置flag, Intent的flag添加FLAG_ACTIVITY_NEW_TASK

Service
9、什么是Service以及描述下它的生命周期?
service是一个服务,它是不可见的,同样也是运行在主线程中。它的生命周期的方法有onCreate、onStart、onDestory,它还有一些activity的没有的生命周期方法,onBind和onUnbind
不同的启动方式,生命周期调用的也不同。
启动Service的方式有两种,一种是startService和bindService
a、通过startService
Service会经历 onCreate 到onStart,然后处于运行状态,stopService的时候调用onDestroy方法。
这种方式,activity和service是相互独立的。如果是调用者自己直接退出而没有调用stopService的话,Service会一直在后台运行
b、通过bindService
Service会运行onCreate,然后是调用onBind, 这个时候调用者和Service绑定在一起。调用者退出了,Service就会调用onUnbind->onDestroyed方法。
这种方式,activity就和service相互捆绑在一起了。所谓绑定在一起就共存亡了。调用者也可以通过调用unbindService方法来停止服务,这时候Service就会调用onUnbind->onDestroyed方法。

Activity为什么要绑定Service?是因为有些情况下,我们需要调用service里面的方法。startService的方式我们是调用不到Service里面的方法的。

如何让服务长期在后台运行,而activity又可以调用到服务里面的方法?
先startService 然后bindService进行绑定,这个时候就可以调用服务里面的方法了。调用完了之后,你就unBindService,这时候退出界面的时候,服务是一直在后台跑的。

默认情况下,服务是运行在主线程中的,在特殊的情况下,我们可以通过AndroidManifest文件中进行配置android:process="" 这种情况下,服务就在另外一个进程的主线程中。
10. 什么是IntentService?有何优点?
普通的service ,默认运行在ui main 主线程(ID默认是1)
Sdk给我们提供的方便的,带有异步处理的service类,
OnHandleIntent() 处理耗时的操作
11、什么时候需要使用到Service
因为service是具有较高优先级。Android系统会尽量保持拥有service的进程运行,只要在该service已经被启动(start)或者客户端连接(bindService)到它。当内存不足时,需要保持,拥有service的进程具有较高的优先级。所以我们需要使用到服务Service
在某些情况下,比如服务以及onStart了,那么此时服务的优先级会稍微的低一些,这时候还是有可能被系统回收,可以通过startForground提高服务的优先级,这个时候,系统就不会回收这个服务了。
因为服务的优先级较高,所以在一些场景中比较适合使用服务,比如:
a、拥有长连接QQ
b、定时轮询、耗时操作
c、服务里面注册广播接收者。有些广播接收者只能通过代码注册,比如屏幕锁屏、屏幕解锁

广播接收者
12、简单描述一下广播接收者
广播接收者有两类,一种是系统本身就有的,一种是我们自己写的广播接收者。
广播接收者注册的方式也有两种,一种是动态注册,一种是静态注册。
只能用代码注册的广播,这种广播产生的频率是比较高的。比如电量变化的广播,屏幕解锁的广播。电量变化的广播。
广播接收者在注册的时候可以指定优先级,用于提高接收到广播的顺序。
广播一般是用于跨进程通讯的时候。
13、如何发广播
广播分为两种,一种是有序广播,一种是无序广播
有序广播是按顺序被接收的,是可以被拦截和修改里面的数据的。而无序广播则没有接收顺序,也无法修改广播里面的数据。
拦截广播可以使用abortBroadcast()将有序广播给abort掉
数据存储
14、ContentProvider的使用
把自己的数据通过uri的形式共享出去,这个uri是事先约定好的。
android 系统下 不同程序 数据默认是不能共享访问,通过ContentProvider可以将自己应用的数据提供给别的应用。
我们在写内容提供者的时候,需要写一个类继承ContentProvider,然后实现里面的增删改查方法
query(Uri, String[], String, String[], String)
insert(Uri, ContentValues)
update(Uri, ContentValues, String, String[])
delete(Uri, String, String[])
15、Android提供的数据存储方式有哪些(内存:效率快,文件中存储临时文件,开关等)
a、SharedPreferences、sd卡的文件
b、数据库sqlite(大量的数据存储)
c、数据存储到服务器上(http协议访问后台接口传输上去)

View
16、View的绘制流程,自定义控件的使用
View如何绘制到手机上,一般用onDraw(Canvas canvas)在画布上(不过在此之前要 onMeasure和onLayout)
onMeasure->onLayout->onDraw
onMeasure:计算宽和高,调用setMeasuredDimension
onLayout: 计算位置
onDraw: 画在画布上
自定义控件需要在onMeasure、onLayout、onDraw中的某些方法进行修改,这样才能保证自定义的控件能够在正确的位置正确的大小被正确的画出来。
自定义属性的使用?
在values的目录下需要建立一个文件,叫做attrs.xml 这个文件是定义属性规则的。一个属性的名字、取值类型、取值范围
在布局文件中需要加入命名空间,最后在自定义控件中获取这些值。
17、View的事件传递
事件分发dispatchTouchEvent
事件拦截onInterceptTouchEvent{如在桌面中滑动时,返回true时父拦截事件,点击事件 时,点击时返回false时,不拦截事件传递给子控件就响应了点击事件}
事件响应onTouchEvent
事件传递的方向是由父类到子类,事件响应的方向是从子类到父类。

18、ListView的优化
listView是由item充填,每个item都是有getView返回的(如果有千百个item,就会有千百个inflate会很占内存的所以系统就给提供了convertView)
重用了convertView,减少了inflate的次数
使用ViewHolder,减少findViewById的次数,很大程度上的减少了内存的消耗。
安卓面试基础(如会必过)_第4张图片
19、布局的优化(就是提高UI的流程度)
优化布局层次。不要不断的嵌套LinearLayout ,多使用RelativeLayout 尽可能的减少布局的层次。如:左边是图片,右边是文字的,可以就使用一个TextView来完成。drawableLeft。
ViewStub(延时加载的view,当使用时才加载)、include(提取一个basePager.xml),listview子元素高度的计算

其他
20、线程间的通讯
Handler是用来进行线程间的通信。
Looper是用来管理所属线程的消息队列MessageQueue的
每一个线程都需要有一个looper,每一个looper管理一个MessageQueue
Handler.sendMessage的意思是将某一个message放到MessageQueue中去,looper是个死循环,不断的读MessageQueue中的新消息。
要让looper的死循环运行起来,得调用Looper.loop()方法。
我们通常都会在子线程中,发一个消息到主线程中的messagequeue中去。
21、内存泄露的查找
内存泄漏本身不会产生什么危害,真正有危害的是内存泄漏的堆积。Android应用内存泄漏的的原因有以下几个:
0、register之后没有unregister
1查询数据库后没有关闭游标cursor file没有close
2 构造Adapter时,没有使用 convertView 重用
3 Bitmap对象不在使用时调用recycle()释放内存
4 对象被生命周期长的对象引用,如activity被静态集合引用导致activity不能释放
内存泄漏如何解决:
生成hprof文件可以通过adt的工具也可以通过代码生成。debug的dump方法
22、如何处理大图片,图片缓存

  1. 有效加载大图片,合理设置BitmapFactory.Options的inSampleSize值,减少图片内存占用;
  2. 仅请求图片的大小,inJustDecodeBounds = true,仅请求图片大小,而不会加载图片到内存;
  3. 缓存图片,内存缓存LruCache
    23、描述一下AIDL的原理
    AIDL的全称是android interface definition language 接口定义语言。它所做的事情就是跨进程范围另外一个服务里面的方法的。跨进程范围另外一个服务里面的方法。
    在手机卫士中挂断电话用到过AIDL。我们要获取手机系统的电话服务,用到了aidl 它其实工作的原理就是绑定到一个远程的服务上。然后这个远程服务会返回回来一个代理对象。
    这个代理对象里面的方法,就是我们定义的aidl
    aidl的写法也非常简单,主要分两种。调用系统服务的话,直接找到那个服务的aidl拷贝到我们的项目中就可以了。另外一种是我们自己写aidl,主要注意的一点是aidl是没有访问修饰符的。因为aidl本身就是公开的,就是为了给别人调用的,不需要私有的private方法。
    其实呢,在实际的开发过程中,比较少会写这个aidl,特别是写app,几乎用不到 做rom的时候,倒会遇到。那也比较少。但是你得懂它相关的知识是吧。
    在面试的时候,这个也是经常被用的。所以大家要熟悉这个问题的回答方法。
    我以前在中兴面试别人的时候,只要他能回答上几个关键点,我就会让他过我这关噢。
    1、跨进程 2、aidl在服务端和客户端都需要有一份 3、通过绑定的方式获取远程服务对象的代理IBinder,就可以调用相关的方法。
    跨进程:可用Aidl,广播,隐式意图,或者自己写一个跨进程的一个进程将数据定时存入sd 卡中,然后另一个进程定时从sd卡里面取出数据。

你可能感兴趣的:(安卓基础,安卓)