Android几个面试题解答

有人分享了几个面试题,个人觉得题目出得比较全面,故本人有兴趣分析解答一下,同时帮自己理顺一些思路。

[b]题目一:简述Android消息机制原理?[/b]
[b]分析:[/b]这个非常重要,但因为太常见了,所以大家都知道,肯定会想到Handler这个类,不过要说明原理,不是说完Handler怎么用就行了,要把原理说出来,而且只是简述,不能说一大堆,照本宣科,要说自己的理解。
[b]我的解答:[/b]在UI主线程里,有一个Looper对象与一个Message Queue(消息队列),消息队列是放Mesage(消息的),里面包含是待处理的数据,Looper的作用就是不断从消息队列里取出消息,然后交给另一个对象处理,这个对象就是Handler,其handlerMessage函数就是来处理Message的,并且在Looper所在线程里执行。
除此之外Handler的另一个作用是将Message放到Message Queue队列中,这个放置的过程可以在其它子线程来进行;因为Hander与Looper是多对一的关系,所以能保证放到正确的队列,又由于Message中有Hadler对象的引用,所以最后处理消息的Handler就是当初放它进队列的Handler。
子线程中需要手动调用特定的接口,就能产生本线程的消息队列与Looper,运行机制与主线程一样。
最后归纳一下就是:产生消息--放置消息--分发消息(与产生放置过程可以并行)--处理消息

[b]题目二:Android中常用的三种动画是什么?
[/b] [b]分析:[/b]动画一般用得比较多的是用XML定义的动画放在/res/anim/文件夹内,然后使用,或者用代码来处理;有一种简单的就是用多个图片在连续变换产生动画效果;而最新也是功能最强大的是在3.0中引入的属性动画(Property Animation),该动画之所以强大,因为它不止可以应用于View,还可以应用于任何对象。三种动画分别叫:Tween Animation(补间动画)、Frame Animation(帧动画)、Property Animation(属性动画)。
[b]我的解答:[/b]Tween Animation(补间动画)、Frame Animation(帧动画)、Property Animation(属性动画)。
Tween Animation:只能应用于View对象,使视图组件移动、放大、缩小以及产生透明度的变化。
Frame Animation:通过顺序的播放排列好的图片来实现,类似电影。
Property Animation:动画的对象除了View对象,还可以是Object对象,通过改变View对象的实际属性来实现View动画。

[b]题目三:Fragment使用的场景,相比Activity,使用Fragment有什么优缺点?[/b]
[b]分析:[/b]Fragment是3.0版引入的,当时3.0主要为了平板电脑而推出的,平板电脑屏幕大,显示的内容更多,更多的交互,故需要同一界面上实现更多数据的变化,而Fragment主要为了界面切换更方便而产生的。但Fragment不能离开Activity而单独存在,需要以Activity为载体,不用在AndroidManifest.xml中配置。
[b]我的解答:[/b]Fragment主要在需要频繁进行局部界面切换时使用,比如Tab菜单切换界面,或者大屏幕上左边列表来切换右边视图显示等。
与Activity相比,
优点:1.模块化,可以属于多个Activty,动态的加入到Activty或者从Activity移除,实现更多效果与更好的用户体验。
2.不用在AndroidManifest.xml中配置,打包时也可以混淆,能更好的保护我们的源代码。
3.频繁切换多个界面中能利用原有对象与界面数据,效率更高。
缺点:1.因为受Activity生命周期的影响,自己也有单独的生命周期,故使用起来复杂一些。在复杂的变换中,一旦把握不当,容易产生bug。
2.Fragment之间传递与返回数据没有Activity之间方便,有时还得借助Activity来实现,比如让Activity实现接口,然后Fragment调用接口来实现Fragment之间的数据通信。

[b]题目四:谈谈四大组件进程间通信。
[/b] [b]分析:[/b]一般一说到四大组件通信,肯定会想到Intent,但是题目主要讲的是进程间通信,虽然Intent能实现进程间通信,但还不够。
[b]我的解答:[/b]主要有如下几种进程间通信方式:
1.Intent消息通知机制。利用Intent,可以实现 Actvity、Service互相的跨进程调用,Intent中携带了目标组件的特征与要传递的数据,只要符合特征的Activity或Service,不管是不是与打开源在同一进程中,系统会去创建目标组件,并接收传递的数据。
2.AIDL服务。主要利用AIDL接口定义语言,来实现Activity与Service之间进行实时通信。通过AIDL,Activity中能获得Service里onBind回调函数返回的IBinder(AIDL服务对象),Activity再通过调用AIDL服务对象中的函数实现两者间的通信。
3.Broadcast机制。BroadcastReceiver(广播接收器)作为四大组件中的一员,本身就是一种跨进程通讯方式的组成部分。在一个进程中发出广播后,另一个进程可以通过BroadcastReceiver来接收广播,并取出Broadcast中携带的数据,然后进行处理,Intent在此起到了过滤与传递数据的作用。
4.ContentProvider。ContentProvider(内容提供者)主要用来提供进程间读取数据使用,如果在同一应用中,访问数据时虽然也能用ContentProvider,但是没用必要,直接用文件或数据库即可。ContentProvider实际是上对本地数据作了一层封装,只向外提供数据访问接口,这样可以对外控制数据的开放与隐藏。
上面是具体的使用,不过从本质上来说,四种方式的底层都是使用的Binder机制,上面4种方式只是对Binder做了封装,方便使用。

[b] 题目五:关于刷新ListView,如何在不使用notifyDataChanged刷新局部数据?[/b]
[b]分析:[/b]notifyDataChanged函数来刷新ListView时会强制ListView调用getView来刷新每个Item的内容,在某些情况下会损失效率,那能不能只想刷新某一个或几个Item呢,肯定是可以的,比如我们想改变一个TextView里的显示内容,只要用setText重新赋值即可,而Item即是一个View,其实只要想办法对View里的子View进行重新设置属性即可,关键点就是拿到子Item的根View。
[b]我的解答:[/b]第一步,通过位置找到想要刷新的Item的根View;第二步:对根View里的子View作数据更新。
//得到第一个可显示控件的位置,
int firtvisiblePosition = listView.getFirstVisiblePosition();
int lastVisiblePosition = listView.getLastVisiblePosition();

if ( needFlushItemIndex >= firtvisiblePosition && needFlushItemIndex <= lastVisiblePosition ) {
//得到某一子项的根View
View rootItemView = listView.getChildAt(needFlushItemIndex - firtvisiblePosition);
//设置需要刷新子View的属性
......
}


[b]题目六:Android系统是如何确定进程优先级的高低?[/b]
[b]我的解答:[/b]1.Active(活动)进程具有最高优先级,比如存在与用户正在交互的Activity;存在正在执行onReceive事件处理程序的Broadcast Receiver;存在正在执行onStart、onCreate、onDestroy事件处理程序的Service;存在正在运行、且已被标记为前台运行的Service;
2.可见进程,例如Activity被一个对话框部分遮挡,它所在进程具有第二高的优先级;
3.启动Service进程,已经启动Service的进程,具有第三高的优先级;
4.后台进程,不可见,并且没有任何正在运行的Service或Activity的进程,具有第四高优先级;
5.空进程,如果一个进程里没有包含任何app,那么这个进程的优先级是最低;

[b]题目七:分别说说View与ViewGroup事件分发流程。[/b]
[b]分析:[/b]View与ViewGroup事件分发主要指Touch事件的分发与处理,在发生触摸事件时,系统会直接或间接调用相关的回调函数,并通过函数的返回值来判断进一步的事件分发,开发者可以在函数里加入逻辑并返回true or false来进行事件分发控制。
其主要涉及到三个回调函数,
public boolean dispatchTouchEvent(MotionEvent ev)、
public boolean onInterceptTouchEvent(MotionEvent ev)、
public boolean onTouchEvent(MotionEvent ev)。其中最基本的View没有onInterceptTouchEvent函数。
系统一般会直接调用dispatchTouchEvent函数,dispatchTouchEvent函数中再调用其它几个函数。系统最初是调用Activity的dispatchTouchEvent函数,dispatchTouchEvent函数中再一级一级调用下层的函数,如果低一级的函数返回true,则上层的函数都会直接返回true,表示此事件被低一级的View处理了。

[b]我的解答:[/b]
View的事件分发流程:
1.如果View不是ENABLED或者没有注册OnTouchListener或者执行OnTouchListener.onTouch函数时返回false,则执行onTouchEvent函数,并捕捉其返回值。
2.如果onTouchEvent函数返回false则事件交给上层继续处理。
3.如果onTouchEvent函数返回true或者OnTouchListener.onTouch函数返回true,则表示事件已处理完毕,不需要由上层View处理。

ViewGroup的事件分发流程:
1.首先判断ViewGroup的onInterceptTouchEvent()函数的返回值,为true则子View的事件都被拦截;接下来由ViewGroup处理,流程同View事件分发流程。
2.onInterceptTouchEvent()函数返回false,则遍历其子View,判断子View是不是在点击范围内,只有在点击范围内的子View才会继续进行处理。
3.子View如果处理了该事件,则处理完成。
4.子View如果没有处理该事件,由ViewGroup负责处理,接下来同View事件分发流程。


[b]题目八:涉及到数据库升级,如果想保留数据,加入数据表结果有更新(增加字段),如何实现(谈谈思路)。[/b]
[b]分析:[/b]数据库升级时一般情况下系统会回调SQLiteOpenHelper类的onUpgrade函数,在该函数中实现对表的操作即可。
如果增加字段,sql语法有ALTER TABLE XX ADD COLUMN的DDL定义语言,如果在表末尾加一个字段,原有数据不会被清除,如果是想在表中间加字段,则可以采用加表转移数据的方法。
[b]我的解答:[/b]
两种情况:
如果在表末尾加字段,直接采用ALTER TABLE XX ADD COLUMN进行增加即可,原有数据默认会保存。
如果在表中或表首加字段,则采用数据转移的方式,首先将原表重命名,再新建一个与原表相同名称的表,再将原表的数据导入到新表,最后删除原表即可。

[b]题目九:Android中动态加载的原理及使用场景。[/b]
[b]我的解答:[/b]动态加载原理:利用DexClassLoader,可动态加载的内容包括 apk、dex、jar等,并利用反射调用插件包内的类的方法。
使用场景:应用不想升级而达到更新目的时,可从服务器下载新内容,再动态加载达到应用功能更新;应用需要加密时,可在执行时进行解密后动态加载。

[b]题目十:谈谈你对Android开发的看法,如何提高用户体验(流量/电量/缓存/UI/编程规范),性能优化方面的经验。[/b]
[b]我的解答:[/b] 对于Android应用层开发来说主要还是对sdk的了解及java基础,除此之外关键在于有整体思维与精益求精的心思。
性能优化可以采用一些高效的开源框架,比如Volley、gson等;多用Android提供的数据结构,比如SparseArray、Parcelable等;尽量减少View的嵌套层次;Service执行完后应stop掉;大量图片操作应采用缓存机制;没必要的对象不要产生,不用的及时释放;循环语句采用最优方式。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值