0.Android手机操作系统的四层架构?
Applications , Application Framework , Android RunTime Libraries , Liunx Kernel
架构框架以此从上到下:
- Applications(应用程序(应用层)) Android会同一系列核心应用程序包一起发布,该应用程序包包括 email客户端,SMS短消息程序,日历,地图,浏览器,联系人管理程序等.所有的应用程序都是使用 JAVA 语言编写的.
-
Application FrameWork(应用程序扩展层(框架)) 由于 Android 的手机操作系统是基于Liunx 2.6 系统之上封装而成.所以开发人员可也以直接访问核心程序所使用的API框架,该核心应用程序的API 框架设计简化了组件的重用, 任何一个核心应用程序(模块)都暴露出它的功能作用,并且其他应用程序也都可以使用该核心应用程序(模块)的功能(不过的遵守该核心应用程序框架的安全性限制).同样,该应用 程序的重用机制也使用户方便使用应程序的相关组件.
API 框架隐藏的核心应用程序是一系列的应用程序的服务和系统应用,其中包括如下:
(Android 手机中的View 是最基本的一个 UI 类)
丰富而又可扩展的视图(手机界面所显示的组件(Activity 上所显示的))组件,可以用
来构建应用程序 如:(视图)Views, 网格(grids), 文本框(text boxes), 按钮(button), 放
置图片区(imageview),文本编辑区 (edittext), 文本显示区(textview )等等
- Android RunTime Libraries (Android 系统运行库);
- Liunx Kernel (Android 系统最底层核心系统 Liunx)
1.进程和线程什么关系?(面试中很常见的面试题之一)
答:每个应用程序都有一个进程,进程用来处理各种各样的任务的.一个进程中至少有一个线程,如果任务多了,一个进程可以有多个线程,多个线程同步进行工作,即同步处理各种任务.进程的内存空间,对于线程来说是共享的 他们共享这些资源.
打个比喻 : 将应用程序看成是公司的老板,他要去找一个懂安卓开发的人,他把这个任务交给他的秘书去做,他的秘书相当于一个进程,因为老板都会有秘书嘛,然后秘书觉得找一个懂安卓的人很难,然后他就将这个任务交给人事部或研发部的人去找,这些个人事部或研发部的人相当于一个线程,那么找一个懂安卓开发的人就很容易了.
那线程呢?
面试官why are you so diao?让我喘口气啊倒是
"线程间通信这个吧就是消息传递机制MessageQueue 啊 Loop 啊 Handler 啊 "
handler 处理收到的消息和发送的消息 消息队列就是MessageQueue 每个线程都有一个Looper 用来读取MessageQueue中的消息
2.CPU
这货是计算机的核心,他会算数(承载计算任务)
但是它也是普通人 一次只能运行一个东东
进程--->这货就是CPU一次只能运行一个的那个东东
一个进程运行的时候 其他进程处于非运行状态
线程--->一个进程可以有很多线程 他们协同完成一个任务
进程的内存空间 对于线程来说是共享的 他们共享这些资源
但是某些共享是有条件的 有的只让一个线程用 有的让几个线程用 其他人想用 需要给哥等着
防止等着的人插队怎么办 那就要加上一层锁 比如一个房间 进去一个线程 锁上门 防止别人进入 让他们在外面排队 给哥等着
这个锁叫互斥锁 防止多个线程同时写一块内存
还有的让几个人用 那怎么办呢 就在门口放几把钥匙 进去的人拿一把 锁上门 直到门口钥匙木有了 就进不去了 只能给哥等着了
这些钥匙 叫做信号量 保证多个线程不会冲突
3.什么是ANR 如何避免它?
ANR:Application Not Responding,五秒
在Android中,活动管理器和窗口管理器这两个系统服务负责监视应用程序的响应。当出现下列情况时,Android就会显示ANR对话框了:
- 对输入事件(如按键、触摸屏事件)的响应超过5秒
- 意向接受器(intentReceiver)超过10秒钟仍未执行完毕
- Android应用程序完全运行在一个独立的线程中(例如main)。这就意味着,任何在主线程中运行的,需要消耗大量时间的操作都会引发ANR。因为此时,你的应用程序已经没有机会去响应输入事件和意向广播(Intent broadcast). 因此,任何运行在主线程中的方法,都要尽可能的只做少量的工作。特别是活动生命周期中的重要方法如onCreate()和 onResume()等更应如此。潜在的比较耗时的操作,如访问网络和数据库;或者是开销很大的计算,比如改变位图的大小,需要在一个单独的子线程中完成 (或者是使用异步请求,如数据库操作)。但这并不意味着你的主线程需要进入阻塞状态已等待子线程结束 -- 也不需要调用Therad.wait()或者Thread.sleep()方法。取而代之的是,主线程为子线程提供一个句柄(Handler),让子线程 在即将结束的时候调用它。使用这种方法涉及你的应用程序,能够保证你的程序对输入保持良好的响应,从而避免因为输入事件超过5秒钟不被处理而产生的ANR。这种实践需要应用到所有显示用户界面的线程,因为他们都面临着同样的超时问题。
简单回答:
在Android上,如果你的应用程序有一段时间响应不够灵敏,系统会向用户显示一个对话框,这个对话框称作应用程序无响应(ANR:Application Not Responding)对话框。用户可以选择让程序继续运行,但是,他们在使用你的应用程序时,并不希望每次都要处理这个对话框。因此,在程序里对响应性能的设计很重要,这样,系统不会显示ANR给用户。
4.简要解释一下Activity、 Intent 、Intent filter、Service、Broadcast、BroadcaseReceiver
一个Activity呈现了一个用户可以操作的可视化用户界面
一个Service不包含可见的用户界面,而是在后台无限地运行,可以连接到一个正在运行的服务中,连接后,可以通过服务中暴露出来的接口与其进行通信
一个BroadcastReceiver是一个接收广播消息并作出回应的component,broadcast receiver没有界面
intent:content provider在接收到ContentResolver的请求时被激活。
activity, service和broadcast receiver是被称为intents的异步消息激活的。
一个intent是一个Intent对象,它保存了消息的内容。对于activity和service来说,它指定了请求的操作名称和待操作数据的URI
Intent对象可以显式的指定一个目标component。如果这样的话,android会找到这个component(基于manifest文件中的声明)并激活它。但如果一个目标不是显式指定的,android必须找到响应intent的最佳component。
它是通过将Intent对象和目标的intent filter相比较来完成这一工作的。一个component的intent filter告诉android该component能处理的intent。intent filter也是在manifest文件中声明的。
5.什么是IntentService?有何优点?
普通的service ,默认运行在ui main 主线程 , Sdk给我们提供的方便的,带有异步处理的service类, 异步处理的方法 OnHandleIntent() 可以在此方法中处理耗时的操作.
优点如下:
- Acitivity的进程,当处理Intent的时候,会产生一个对应的Service
- Android的进程处理器现在会尽可能的不kill掉你
- 非常容易使用
6.什么是Activity?
四大组件之一,一般的,一个用户交互界面对应一个activity, activity 是Context的子类,同时实现了window.callback和keyevent.callback, 可以处理与窗体用户交互的事件. 我开发常用的的有ListActivity , PreferenceActivity 等…如果界面有共同的特点或者功能的时候,还会自己定义一个BaseActivity.
7.请描述一下Activity生命周期。
生命周期描述的是一个类从创建(new出来)到死亡(垃圾回收)的过程中会执行的方法.在这个过程中会针对不同的生命阶段会调用不同的方法Activity从创建到销毁有多种状态,从一种状态到另一种状态时会激发相应的回调方法,这些回调方法包括:oncreate ondestroy onstop onstart onresume onpause 其实这些方法都是两两对应的:
onCreate创建与onDestroy销毁;
onStart可见与onStop不可见;
onResume可编辑(即焦点)与onPause;
这6个方法是相对应的,那么就只剩下一个onRestart方法了,这个方法在什么时候调用呢?答案就是:在Activity被onStop后,但是没有被onDestroy,在再次启动此Activity时就调用onRestart(而不再调用onCreate)方法;如果被onDestroy了,则是调用onCreate方法。
最后讲自己项目中的经验,比如说豆瓣客户端每次进入某个界面的时候要刷新列表,这个刷新列表的操作 就放在onStart()的方法里面.这样保证每次用户看到的数据都是最新的.多媒体播放, 播放来电话. onStop() 视频, 视频声音设置为0 , 记录视频播放的位子 onStart() 根据保存的状态恢复现场.
8.两个Activity之间跳转时必然会执行的是哪几个方法。
一般情况比如说有两个activity,分别叫A,B ,当在A里面激活B组件的时候, A 会调用 onPause()方法,然后B 调用onCreate() ,onStart(), OnResume() , 这个时候B覆盖了窗体, A会调用onStop()方法. 如果B呢 是个透明的,或者是对话框的样式, 就不会调用onStop()方法
9.Android工程下面有个gen目录,该目录下有个R.java文件,该文件的作用是什么,能不能修改,为什么?
答:作用->该文件相当于项目的字典,项目中所涉及到的用户界面、字符串、图片、声音等资源都会在该文件中创建一个唯一ID编号,这些编号为整形,以16进制自动生成。项目要使用这些资源时,会通过这个类得到资源的引用。因为是系统自动生成,所以不能够被修改.
10.把文件名为“图片1.jpg”的一张图片放到android工程下的res- drawable-mdpi下,会不会报错,为什么?
答:会报错,因为文件名只能为a-z,0-9和下划线。如果名称合适是不会报错的.因为使用Android系统的手机可能采用不同的分辨率,所以在开发的时候会要求有不同分辨率的图片,drawable-hdpi存高分辨率的,drawable-mdpi存中等分辨率的,drawable-ldpi存低分辨率的,所以,你要把相同的图片用图片处理软件处理成不同的分辨率的图片,然后分别保存,当然了,如果你嫌麻烦,也可以在三个目录下保存相同的图片,这样也没有问题,但是不符合开发的初衷。
11.Bitmap.Config下的几个图片质量参数
Bitmap.Config ALPHA_8
Bitmap.Config ARGB_4444
Bitmap.Config ARGB_8888
Bitmap.Config RGB_565
简要解释下每个参数的含义 。
A R G B
透明度 红色 绿色 蓝色
Bitmap.Config ARGB_4444 16 每个像素 占四位
Bitmap.Config ARGB_8888 32 每个像素 占八位
Bitmap.Config RGB_565 16 R占5位 G占6位 B占5位 没有透明度(A)
12.res和Assets的区别?
assets和res目录都能存放资源文件,但是与res不同的是,assets支持任意深度的子目录,在它里面的文件不会在R.java里生成任何资源ID
13.setOnTouchEvent 返回值为true 和 false有何区别?
返回true表示这个消息已经被处理结束,后续的handler不再接收到这个消息
Return true if you have consumed the event, false if you haven't.
The default implementation always returns false.
14.阐述android:padding和android:layout_margin的异同?
(1)不同点:android:padding 是站在父View 的角度描述问题,它规定它里面的内容必须与这个父View 边界的距离。android:layout_margin 则是站在自己角度描述问题,规定自己和其他(上下左右)的 View 之间的距离 , 如果一级只有一个View,那么他的效果基本上就和padding一样。
(2)相同点:如同一级只有一个View,那么android:layout_margin的效果基本上就和android:padding一样
15.关于ContenValues类说法
他和Hashtable比较类似,也是负责存储一些名值对,但是他存储的名值对当中的名是String类型,而值都是基本类型
16.关于Android dvm的进程和Linux的进程,应用程序的进程否为同一个概念?
DVM指dalivk的虚拟机.每一个Android应用程序都在它自己的进程中运行,都拥有一个独立的Dalvik虚拟机实例.而每一个DVM都是在Linux 中的一个进程,所以说可以认为是同一个概念.
17.Android项目工程下面的assets目录的作用是什么?
主要放置多媒体等数据文件
18.关于res/raw目录
这里的文件是原封不动的存储到设备上不会转换为二进制的格式
19.对android NDK的理解
- NDK是一系列工具的集合
- NDK 提供了一份稳定、功能有限的 API 头文件声明。
- 使 “Java+C” 的开发方式终于转正,成为官方支持的开发方式
- NDK 将是 Android 平台支持 C 开发的开端
20.在android中,请简述jni的调用过程
- 安装和下载Cygwin,下载 Android NDK
- 在ndk项目中JNI接口的设计
- 使用C/C++实现本地方法
- JNI生成动态链接库.so文件
- 将动态链接库复制到java工程,在java工程中调用,运行java工程即可
21.handler机制的原理
andriod提供了Handler和Looper来满足线程间的通信。Handler先进先出原则。Looper类用来管理特定线程内对象之间的消息交换(Message Exchange)。
- Looper: 一个线程可以产生一个Looper对象,由它来管理此线程里的Message Queue(消息队列)。
- Handler: 你可以构造Handler对象来与Looper沟通,以便push新消息到Message Queue里;或者接收Looper从Message Queue取出所送来的消息。
- Message Queue(消息队列):用来存放线程放入的消息。
- 线程:UI thread 通常就是main thread,而Android启动程序时会替它建立一个Message Queue。
22.说说mvc模式的原理以及它在android中的运用
android的官方建议应用程序的开发采用mvc模式。何谓mvc?mvc是model,view,controller的缩写,mvc包含三个部分:
- 模型(model)对象:是应用程序的主体部分,所有的业务逻辑都应该写在该层。
- 视图(view)对象:是应用程序中负责生成用户界面的部分。也是在整个mvc架构中用户唯一可以看到的一层,接收用户的输入,显示处理结果。
- 控制器(control)对象:是根据用户的输入,控制用户界面数据显示及更新model对象状态的部分,控制器更重要的一种导航功能,想用用户出发的相关事件,交给m哦得了处理。
android鼓励弱耦合和组件的重用,在android中mvc的具体体现如下:
- 视图层(view):一般采用xml文件进行界面的描述,使用的时候可以非常方便的引入,当然,如何你对android了解的比较的多了话,就一定可以想到在android中也可以使用javascript+html等的方式作为view层,当然这里需要进行java和javascript之间的通信,幸运的是,android提供了它们之间非常方便的通信实现。
- 控制层(controller):android的控制层的重任通常落在了众多的acitvity的肩上,这句话也就暗含了不要在acitivity中写代码,要通过activity交割model业务逻辑层处理,这样做的另外一个原因是android中的acitivity的响应时间是5s,如果耗时的操作放在这里,程序就很容易被回收掉。
- 模型层(model):对数据库的操作、对网络等的操作都应该在model里面处理,当然对业务计算等操作也是必须放在的该层的。
23.请介绍下Android的数据存储方式。
Android提供了5种方式存储数据:
- 使用SharedPreferences存储数据;位置 :
/data/data/包名/shared_preps
- 文件存储数据; 需要访问权限,位置 :
/data/data/包名/files
- SQLite数据库存储数据;
- 使用ContentProvider存储数据;
- 网络存储数据;
Android 中的数据存储都是私有的,其他应用程序都是无法访问的,除非通过ContentResolver获取其他程序共享的数据。
24.请介绍下ContentProvider是如何实现数据共享的。
一个程序可以通过实现一个Content provider的抽象接口将自己的数据完全暴露出去,而且Content providers是以类似数据库中表的方式将数据暴露。Content providers存储和检索数据,通过它可以让所有的应用程序访问到,这也是应用程序之间唯一共享数据的方法。要想使应用程序的数据公开化,可通过2种方法:创建一个属于你自己的Content provider或者将你的数据添加到一个已经存在的Content provider中,前提是有相同数据类型并且有写入Content provider的权限。
如何通过一套标准及统一的接口获取其他应用程序暴露的数据?Android提供了ContentResolver,外界的程序可以通过ContentResolver接口访问ContentProvider提供的数据。
25.SIM卡的EF文件有何作用?
SIM卡的文件系统有自己规范,主要是为了和手机通讯,SIM卡本身可以有自己的操作系统,EF就是作存储并和手机通讯用的.
26.一条最长的短信息约占多少byte?
中文70(包括标点),英文160,160个字节,这个说法不准确,跟手机制式,运营商等信息有关.
做实验,看源码
ArrayList<String> msgs = sms.divideMessage(message);
for (String msg : msgs) {
sms.sendTextMessage(phoneNumber, null, msg, pi, null);
}
27.Android中的动画有哪几类,它们的特点和区别是什么?
两种. 一种是Tween动画.还有一种是Frame动画.
- Tween动画,这种实现方式可以使视图组件移动.放大.缩小以及产生透明度的变化;
- 控制View的动画
- alpha(AlphaAnimation) 渐变透明
- scale(ScaleAnimation) 渐变尺寸伸缩
- translate(TranslateAnimation)画面转换、位置移动
- rotate(RotateAnimation)画面转移,旋转动画
- 控制一个Layout里面子View的动画效果
- layoutAnimation(LayoutAnimationController)
- grid Animation(GridLayoutAnimationController)
- 控制View的动画
- Frame动画,传统的动画方法,通过顺序的播放排列好的图片来实现,类似电影.
28.什么是嵌入式实时操作系统,Android 操作系统属于实时操作系统吗?
嵌入式实时操作系统是指当外界事件或数据产生时,能够接受并以足够快的速度予以处理,其处理的结果又能在规定的时间之内来控制生产过程或对处理系统作出快速响应,并控制所有实时任务协调一致运行的嵌入式操作系统.
主要用于工业控制,军事设备,航空航天等领域对系统的响应时间有苛刻的要求,这就需要使用实时系统.又可分为软实时和硬实时两种,而Android是基于linux内核的,因此属于软实时.
29.ArrayList和Vector的区别
- Vector是线程安全的,ArrayList是线程不安全的
- ArrayList效率更高,Vector速度慢
- 当需要增加空间大小的时候,ArrayList增加原来的一半,Vector增加原来的一倍。
30.TCP和UDP的区别?
31.实现多线程的方式和区别?
32.排序算法有哪些?编写任意一个排序算法的程序。
33.写出listview中一些常用的优化
如果一个listView不做任何的优化,而且有很多的条目,当我们快速的拖动listView的界面的时候,就不断的GCGC(Garbage Collection )垃圾回收,当GC到某个时候就会(OOM)outofmemory内存溢出,应用程序也就会随之挂掉,产生这个问题的原因是什么呢?我们知道listView的特点是每产生一个条目就会调用一次getView方法,如果我们不进行优化,每一次调用都要执行getView方法中的所有语句,而且会在最上面的条目移出界面的时候回收掉这个对象,这样是比较浪费资源的。
这时候我们就会想,如果在条目移出界面的时候不对它进行回收,而是拿回来再次使用,这样不就优化了ListView的效率了吗?幸好,一向给力的谷歌工程师为我们提供了ListView自身的缓存机制,它会缓存条目中的一个条目,当界面最上方的这个条目显示完成之后,就会出现一个缓存条目,也就是BaseView中getView方法中的convertView ,convertView的作用其实就是一个已经被系统回收的历史缓存View对象,我们可以利用这个对象就没有必要再重新去xml文件中去解析布局了。判断传进来的参数convertView是否为null,如果为null就创建convertView并返回,如果不为null,则直接使用。
这是第一种优化方法,简单的说就是复用历史缓存的View对象,减少view对象创建的次数。
第二种优化方法是减少findViewById()的次数,findViewById是一个相对比较耗性能的操作,因为每次在getVIew的时候,都需要重新的findViewById,重新找到控件,然后进行控件的赋值以及事件相应设置。这样其实在做重复的事情,因为的getView中,其实包含有这些控件,而且这些控件的id还都是一样的,也就是其实只要在view中findViewById一次,后面无需要每次都要findViewById了。解决这个问题的方法就是把item里面的控件封装成一个javaBean,当item条目被加载的时候就去找到对应的控件 。
前两种优化方式是最一般的优化,一般我们使用listView的时候都会用到这两个优化方法,但是只有这两种方式还远远不够,比如当listView的View对象中有图片资源的时候,就会占用大量的内存,这样就很容易造成内存溢出,对于这种情况有两种优化方法,
分批加载和分页加载,
我把这两种方法看成是利用时间不同的优化和利用空间的不同的优化。分批加载,我们每次只加载一定数量,就像是在不同的时间段加载一次。而分页加载,就像是把一定数量的条目放在不同的空间,利用这两种思想来实现分批加载和分页加载。
分批加载主要解决的是用户体验的问题,如果数据量过大,用户等待的时间就会很长,而且也会出现Anr异常。比如我们要从数据库中读取100条数据,如果一次性读取,就需要很长的时间,但是这时我们修改sql语句,指定从那一条开始获取数据,一共获取多少数据,sql语句是:
"selectphone,mode from blacknumber limit ? Offset ?",new String[]{String.valueOfa(maxNumber),String.valueOf(StateIndex)}
新获取的数据加到集合的末尾即可。
说分页加载,它的实现思路是这样的,实现OnScrollListener接口,重写onScrollStateChanged和onScroll方法,使用onScroll方法实现“滑动”后处理检查是否还有新纪录,如果有,调用addFooterView,添加记录到adapter,adapter调用notifyDataSetChanged更新数据;如果没有新纪录了,把自定义的mFooterView去掉,使用onScrollStateChanged可以检测是否滚到最后一行且停止滚到然后执行加载。
还有一种优化方式是利用图片异步加载的方法,实现思路是:
1.先从内存缓存中获取图片显示(内存缓冲)
2.获取不到的话从SD卡里获取(SD卡缓冲,从SD卡获取图片是放在子线程里执行的,否则快速划瓶的话会不够流畅)
3.都获取不到的话从网络下载图片并保存到SD卡同时加入内存并显示(视情况看是否要显示)
我们在使用listview的时候可能会出现图片乱跳(错位)的问题:
图片错位问题的本质源于我们的listview使用了缓存convertView,假设一种场景,一个listview一屏显示九个item,那么在拉出第十个item的时候,事实上该item是重复使用了第一个item,也就是说在第一个item从网络中下载图片并最终要显示的时候,其实该item已经不在当前显示区域内了,此时显示的后果将可能在第十个item上输出图像,这就导致了图片错位的问题。所以解决之道在于可见则显示,不可见则不显示。在ImageLoader里有个imageViews的map对象,就是用于保存当前显示区域图像对应的url集,在显示前判断处理一下即可。
34.“==”和equals方法有什么区别?
“==”操作符专门用来比较两个变量的值是否相等,也就是用于比较变量所对应的内存中所存储的数值是否相同。equals方法用于比较两个独立对象的内容是否相同。比如,要比较一个字符串对象的引用对象变量的地址值是否相同,就用"==",而要比较字符串对象中的内容是否相同,则用equals方法。
35.静态变量和实例变量的区别?
静态变量属于类,也称为类变量,它可以通过类名直接调用使用。
实例变量属于某个对象的属性,必须创建了实例对象,才能使用实例对象去调用实例变量。
36.Integer与int的区别?
- int是java提供的8种基本数据类型之一。
- Integer是java为int提供的封装类。
- int的默认值为0,而Integer的默认值为null.
37.OverLoad(重载)和Override(重写)的区别?
- 重载表示同一个类中可以有多个名称相同的方法,但这些方法的参数列表各不相同。
- 重写表示子类中的方法可以与父类中的某个方法的名称和参数完全相同。
38.抽象类与接口的区别?
- 抽象类可以有构造方法,接口中不能有构造方法。
- 抽象类中可以有普通成员变量,接口中没有普通成员变量。
- 抽象类中可以包含非抽象方法,接口中的所有方法必须都是抽象的。
- 抽象类中可以包含静态方法,接口中不能包含静态方法。
- 抽象类中的抽象方法的访问类型可以是public,protected,接口中的抽象方法只能是public类型的,并且默认即为public abstract类型。
39.String和StringBuffer的区别?
String的长度是不可以改变的,StringBuffer的长度是可变的。
40.final,finally,finalize的区别?
- final是一个修饰符,用于修饰属性,方法和类,分别表示属性不可变,方法不可覆盖,类不可以被继承。
- finally是异常处理语句结构的一部分,它里面的代码一定会执行。
- finalize是Object类的一个方法,在垃圾回收器执行的时候会调用被回收对象的此方法,可以覆盖这个方法提供垃圾收集时的其他资源回收,例如关闭文件。
41.运行时异常和一般异常的异同?
异常表示程序运行过程中可能出现的非正常状态。
- 运行时异常表示虚拟机的通常操作中可能遇到的异常,是一种常见运行错误。
- java编译器要求方法必须声明抛出可能发生的非运行时异常,但并不要求必须声明抛出未被捕获的运行时异常。
42.error和exception有什么区别?
- error表示恢复不是不可能但很困难的情况下的一种严重问题。比如内存溢出。程序是不可能处理这样的情况。
- exception表示一种设计或实现问题,如果程序运行一直正常,那么exception就不会发生。
43.sleep()和wait()的区别?
- sleep是线程类Thread的方法,调用它时将导致线程暂停执行指定的时间,将执行机会给其他线程,但监控状态依然保持,到时间后会自动恢复。调用sleep方法不会释放对象锁。
- wait是Object类的方法,调用它时将导致本线程放弃对象锁,进入等待此对象的等待锁定池,只有针对此对象发出notify方法(或notifyAll)后,本线程才进入对象锁定池准备获得对象锁进入运行状态。
44.HashMap和Hashtable的区别?
- HashMap是线程不安全的,Hashtable是线程安全的。
- HashMap可以接受null作为键和值,Hashtable不可以接受null作为键和值。
45.List和Map的区别?
- List是存储单列数据的集合,Map是存储键和值这样的双列数据的集合。
- List中存储的数据是有顺序的,并且数据可以重复。
- Map中存储的数据是没有顺序的,它的键不能重复,值可以有重复。
46.Collection和Collections的区别?
- Collection是集合类的上级接口,继承于它的接口主要有List和Set.
- Collections是针对集合类的一个工具类,它里面提供了一系列的静态方法实现对各种集合的搜索,排序,线程安全化等操作。
47.堆与栈的区别?
- 栈用于存放方法内部的局部变量。当方法结束时,分配给此方法的栈会释放出来。
- 堆用于存放用new产生的数据和数组。它不会随方法的结束而消失。
48.简述synchronized和java.util.concurrent.locks.Lock的异同?
- 主要相同点:Lock能完成synchronized所实现的所有功能
- 主要不同点:Lock有比synchronized更精确的线程语义和更好的性能。
- synchronized会自动释放锁,而Lock一定要求程序员手工释放,并且必须在finally从句中释放。
- Lock还有更强大的功能,例如,它的tryLock方法可以非阻塞方式去拿锁。
50.以下代码片段输出?
public class A{
static{
System.out.println("1") ;
}
public A(){
System.ot.println("A") ;
}
}
public class B extends A{
static{
System.out.println("2") ;
}
public B(){
System.ot.println("B") ;
}
}
问题:
A ab = new B() ;//这里会输出什么 1 2 a b
ab = new B() ;//这里会输出什么 a b
原因 : 静态代码块只调用一次
51.请写出冒泡排序(原理、实现)(高级程序员)
冒泡排序:bubbleSort
原理:将数组中的元素,进行两两相比较,然后将较小的数向上移就好比是水泡向上冒
public static void bubbleSort(int[] arr) {
for (int x = 0; x < arr.length - 1; x++) { // 控制循环次数
for (int y = 0; y < arr.length - 1 - x; y++) {
if (arr[y] > arr[y + 1]) {
int temp = arr[y];
arr[y] = arr[y + 1];
arr[y + 1] = temp;
}
}
}
}
52.xml的几种解析方式区别是?
- SAX,速度最快,但无法进行深层次解析
- DOM4J,可以进行深层解析,效率低于SAX但高于其他解析方式
- DOM,可以进行深层解析,效率低于DOM4J
- JDOM,可以进行深层解析,效率低于DOM4J
53.多线程的几种实现方式?
- 继承Thread父类
- 实现Runnable接口
54.UML图中五种常用的图分别是?
用例图 类图 序列图 行为图 交互图 ER图
55.数据结构分为哪两种结构?
- 线性结构:线性表、栈、队列、串、…
- 非线性结构:树、图、…
56.TCP与UDP的区别?
- 1.基于连接与无连接
- 2.对系统资源的要求(TCP较多,UDP少)
- 3.UDP程序结构较简单
- 4.流模式与数据报模式
- 5.TCP保证数据正确性,UDP可能丢包,TCP保证数据顺序,UDP不保证
57.通过startService()和bindService()启动service,service的生命周期上有哪些不同?
通过startService()启动服务:会调用如下生命周期方法:
onCreate()---->onStart()---->onDestory()
如果是调用bindService()启动服务:会调用如下生命周期方法:
onCreate()---->onBind---->onUnBind()---->onDestory()
不同点在于:当采用startService()方法启动服务,访问者与服务之间是没有绑定在一起的,访问者退出,服务还在运行,而采用bindService()方法启动服务时,访问者与服务是绑定在一起的,即访问者退出,服务也就终止,解除绑定。
58.Activity的void onSavelnstanceState(Bundle outState)有什么作用?如何使用?
作用:在系统回收Activty之前保存Activity当前的状态,可用于存放程序临时性的一些数据到磁盘中。
我们可以将要保存的数据存放在bundle对象中。outState.putString(key, value);
59.请简述Android中UI thread、handler、Message Queue、Looper之间的关系
Andriod提供了 Handler 和 Looper 来满足线程间的通信。Handler遵循先进先出的原则。
在单线程环境中,UI thread 为主线程,默认会创建一个Looper对象及由其管理的MessageQueue, MessageQueue用来存放Message对象。
你可以构造Handler对象来与Looper沟通,Handler通过sendMessage()将Message传递给Looper,Looper会将消息放入MessageQueue中。
当Looper看到MessageQueue中含有Message,就将其广播出去。Handler对象收到消息后,调用handlerMessage()对其进行处理。
60.请简述SurfaceView和View的区别
surfaceView它是在一个新起的单独线程中重新绘制画面而View必须在UI的主线程中更新画面。
那么在UI的主线程中更新画面,可能会引发问题,比如你更新画面的时间过长,那么你的主UI线程会被你正在画的函数阻塞。那么将无法响应输入的请求,将会导致引发ANR异常!
当使用surfaceView 由于是在新的线程中更新画面所以不会阻塞你的UI主线程。但这也带来了另外一个问题,就是事件同步。比如你触屏了一下,你需要surfaceView中thread处理,一般就需要有一个event queue的设计来保存touch event,这会稍稍复杂一点,因为涉及到线程同步。
61.wait和sleep的比较?
sleep方法有:sleep(long millis),sleep(long millis, long nanos),调用sleep方法后,当前线程进入休眠期,暂停执行,但该线程继续拥有监视资源的所有权。到达休眠时间后线程将继续执行,直到完成。若在休眠期另一线程中断该线程,则该线程退出。
wait方法有:wait(),wait(long timeout),wait(long timeout, long nanos),调用wait方法后,该线程放弃监视资源的所有权进入等待状态;
wait():等待有其它的线程调用notify()或notifyAll()进入调度状态,与其它线程共同争夺监视。wait()相当于wait(0),wait(0, 0)。
wait(long timeout):当其它线程调用notify()或notifyAll(),或时间到达timeout亳秒,或有其它某线程中断该线程,则该线程进入调度状态。
wait(long timeout, long nanos):相当于wait(1000000*timeout + nanos),只不过时间单位为纳秒。
62.请描述下Activity的生命周期?
63.如果后台的Activity由于某原因被系统回收了,如何在被系统回收之前保存当前状态?
利用onSaveInstanceState()方法保存状态 , 除了在栈顶的activity,其他的activity都有可能在内存不足的时候被系统回收,一个activity越处于栈底,被回收的可能性越大.
当你的程序中某一个Activity A在运行时,主动或被动地运行另一个新的Activity B,这个时候A会执行onSaveInstanceState()。B完成以后又会来找A,这个时候就有两种情况:一是A被回收,二是A没有被回收,被回收的A就要重新调用onCreate()方法,不同于直接启动的是这回onCreate()里是带上了参数savedInstanceState;而没被收回的就直接执行onResume(),跳过onCreate()了。
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putLong("id", 1234567890);
}
public void onCreate(Bundle savedInstanceState) {
//判断 savedInstanceState是不是空.
//如果不为空就取出来
super.onCreate(savedInstanceState);
}
64.如何退出Activity?如何安全退出已调用多个Activity的Application?
对于单一Activity的应用来说,退出很简单,直接finish()即可。(用户点击back键 就是退出一个activity 退出activity 会执行 onDestroy()方法 .当然,也可以用killProcess()和System.exit()这样的方法。
但是,对于多Activity的应用来说,在打开多个Activity后,如果想在最后打开的Activity直接退出,上边的方法都是没有用的,因为上边的方法都是结束一个Activity而已。
那么,有没有办法直接退出整个应用呢?
在2.1之前,可以使用ActivityManager的restartPackage方法。
它可以直接结束整个应用。在使用时需要权限android.permission.RESTART_PACKAGES。注意不要被它的名字迷惑。可是,在2.2,这个方法失效了。在2.2添加了一个新的方法,killBackgroundProcesses(),需要权限 android.permission.KILL_BACKGROUND_PROCESSES。可惜的是,它和2.2的restartPackage一样,根本起不到应有的效果。
另外还有一个方法,就是系统自带的应用程序管理里,强制结束程序的方法,forceStopPackage()。
它需要权限android.permission.FORCE_STOP_PACKAGES。并且需要添加android:sharedUserId="android.uid.system"属性.同样可惜的是,该方法是非公开的,他只能运行在系统进程,第三方程序无法调用。因为需要在Android.mk中添加LOCAL_CERTIFICATE := platform。而Android.mk是用于在Android源码下编译程序用的。从以上可以看出,在2.2,没有办法直接结束一个应用,而只能用自己的办法间接办到。现提供几个方法,供参考:
- 抛异常强制退出:该方法通过抛异常,使程序Force Close。验证可以,但是,需要解决的问题是,如何使程序结束掉,而不弹出Force Close的窗口。//安全结束进程 android.os.Process.killProcess(android.os.Process.myPid());
- 记录打开的Activity:每打开一个Activity,就记录下来。在需要退出时,关闭每一个Activity即可。List<Activity> lists ; 在Application 全集的环境里面 lists = new ArrayList<Activity>();每一个activity在执行oncreate()方法的时候 lists.add(this);
Ondestory() lists.remove(this);lists.add(activity);for(Activity activity: lists){
activity.finish();
}
- 发送特定广播:在需要结束应用时,发送一个特定的广播,每个Activity收到广播后,关闭即可。
//给某个activity 注册接受广播的意图 registerReceiver(receiver, filter) //如果接受到的是 关闭activity的广播 就调用finish()方法 把当前的activity finish()掉
- 递归退出 : 在打开新的Activity时使用startActivityForResult,然后自己加标志,在onActivityResult中处理,递归关闭。OnActivityResult();
除了第一个,都是想办法把每一个Activity都结束掉,间接达到目的。
但是这样做同样不完美。
你会发现,如果自己的应用程序对每一个Activity都设置了nosensor,在两个Activity结束的间隙,sensor可能有效了。
但至少,我们的目的达到了,而且没有影响用户使用。
为了编程方便,最好定义一个Activity基类,处理这些共通问题。
65.如何启用Service,如何停用Service。
Android中的service类似于windows中的service,service一般没有用户操作界面,它运行于系统中不容易被用户发觉,可以使用它开发如监控之类的程序。
一.步骤
- 继承Service类 public class SMSService extends Service { }
- 在AndroidManifest.xml文件中的<application>节点里对服务进行配置:<service android:name=".DemoService" />
二.Context.startService()和Context.bindService , 服务不能自己运行,需要通过调用Context.startService()或Context.bindService()方法启动服务。这两个方法都可
以启动Service,但是它们的使用场合有所不同。
- 使用startService()方法启动服务,调用者与服务之间没有关连,即使调用者退出了,服务仍然运行。使用bindService()方法启用服务,调用者与服务绑定在了一起,调用者一旦退出,服务也就终止。
- 采用startService()方法启动服务,在服务未被创建时,系统会先调用服务的onCreate()方法,
接着调用onStart()方法。如果调用startService()方法前服务已经被创建,多次调用startService()方法并不会导致多次创建服务,但会导致多次调用onStart()方法。采用startService()方法启动的服务,只能调用Context.stopService()方法结束服务,服务结束时会调用onDestroy()方法。
- 采用bindService()方法启动服务,在服务未被创建时,系统会先调用服务的onCreate()方法,
接着调用onBind()方法。这个时候调用者和服务绑定在一起,调用者退出了,系统就会先调用服务的onUnbind()方法,
。接着调用onDestroy()方法。如果调用bindService()方法前服务已经被绑定,多次调用bindService()方法并不会
导致多次创建服务及绑定(也就是说onCreate()和onBind()方法并不会被多次调用)。如果调用者希望与正在绑定的服务
解除绑定,可以调用unbindService()方法,调用该方法也会导致系统调用服务的onUnbind()-->onDestroy()方法。
三.Service的生命周期 , Service常用生命周期回调方法如下:
- onCreate() 该方法在服务被创建时调用,该方法只会被调用一次,无论调用多少次startService()或bindService()方法,服务也只被创建一次。
- onDestroy() 该方法在服务被终止时调用。
- Context.startService()启动Service有关的生命周期方法
- onStart() 只有采用Context.startService()方法启动服务时才会回调该方法。该方法在服务开始运行时被调用。多次调用startService()方法尽管不会多次创建服务,但onStart() 方法会被多次调用。
- Context.bindService()启动Service有关的生命周期方法
- onBind()只有采用Context.bindService()方法启动服务时才会回调该方法。该方法在调用者与服务绑定时被调用,当调用者与服务已经绑定,多次调用Context.bindService()方法并不会导致该方法被多次调用。
- onUnbind()只有采用Context.bindService()方法启动服务时才会回调该方法。该方法在调用者与服务解除绑定时被调用。
备注:
- 采用startService()启动服务
Intent intent = new Intent(DemoActivity.this, DemoService.class);
startService(intent); - 采用Context.bindService()启动服务
Intent intent = new Intent(DemoActivity.this, DemoService.class);
bindService(intent, conn, Context.BIND_AUTO_CREATE);
//unbindService(conn);//解除绑定
66.注册广播有几种方式,这些方式有何优缺点?
Android广播机制(两种注册方法), 在android下,要想接受广播信息,那么这个广播接收器就得我们自己来实现了,我们可以继承BroadcastReceiver,就可以有一个广播接受器了。有个接受器还不够,我们还得重写BroadcastReceiver里面的onReceiver方法,当来广播的时候我们要干什么,这就要我们自己来实现,例如我们可以搞一个信息防火墙。具体的代码:
public class SmsBroadCastReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Bundle bundle = intent.getExtras();
Object[] object = (Object[]) bundle.get("pdus");
SmsMessage sms[] = new SmsMessage[object.length];
for (int i = 0; i < object.length; i++) {
sms[0] = SmsMessage.createFromPdu((byte[]) object[i]);
Toast.makeText(context, "来自" + sms[i].getDisplayOriginatingAddress() + " 的消息是:" + sms[i].getDisplayMessageBody(), Toast.LENGTH_SHORT).show();
}
//终止广播,在这里我们可以稍微处理,根据用户输入的号码可以实现短信防火墙。
abortBroadcast();
}
}
当实现了广播接收器,还要设置广播接收器接收广播信息的类型,这里是信息:android.provider.Telephony.SMS_RECEIVED
我们就可以把广播接收器注册到系统里面,可以让系统知道我们有个广播接收器。
这里有两种注册方式,一种是代码动态代码注册:
//生成广播处理
smsBroadCastReceiver = new SmsBroadCastReceiver();
//实例化过滤器并设置要过滤的广播
IntentFilter intentFilter = new IntentFilter("android.provider.Telephony.SMS_RECEIVED");
//注册广播
BroadCastReceiverActivity.this.registerReceiver(smsBroadCastReceiver, intentFilter);
一种是在AndroidManifest.xml文件中配置广播
...
<!--广播注册-->
<receiver android:name=".SmsBroadCastReceiver">
<intent-filter android:priority="20">
<action android:name="android.provider.Telephony.SMS_RECEIVED"/>
</intent-filter>
</receiver>
...
<!-- 权限申请 -->
<uses-permission android:name="android.permission.RECEIVE_SMS"/>
两种注册类型的区别是:
- 第一种不是常驻型广播,也就是说广播跟随程序的生命周期。
- 第二种是常驻型,也就是说当应用程序关闭后,如果有信息广播来,程序也会被系统调用自动运行。
67.请谈谈Android引入广播机制的用意?
- 从MVC的角度考虑(应用程序内) 其实回答这个问题的时候还可以这样问,android为什么要有那4大组件,现在的移动开发模型基本上也是照搬的web那一套MVC架构,只不过是改了点嫁妆而已。android的四大组件本质上就是为了实现移动或者说嵌入式设备上的MVC架构,它们之间有时候是一种相互依存的关系,有时候又是一种补充关系,引入广播机制可以方便几大组件的信息和数据交互。
- 程序间互通消息(例如在自己的应用程序内监听系统来电)
- 效率上(参考UDP的广播协议在局域网的方便性)
- 设计模式上(反转控制的一种应用,类似监听者模式)
68.什么情况会导致Force Close ?如何避免?能否捕获导致其的异常?
一般像空指针啊,可以看起logcat,然后对应到程序中 来解决错误 .
69.横竖屏切换时候Activity的生命周期?(实际验证与以下描述不太相符,都会重新调用一次生命周期方法)
这个生命周期跟清单文件里的配置有关系
- 不设置Activity的android:configChanges时,切屏会重新调用一次各个生命周期,切横屏时会执行一次,切竖屏时会执行两次
- 设置Activity的android:configChanges="orientation"时,切屏还是会重新调用各个生命周期,切横、竖屏时只会执行一次
- 设置Activity的android:configChanges="orientation|keyboardHidden"时,切屏不会重新调用各个生命周期,只会执行onConfigurationChanged方法
一般在游戏开发中, 屏幕的朝向都是写死的.
70.如何将SQLite数据库(dictionary.db文件)与apk文件一起发布?
可以将dictionary.db文件复制到Android工程中的res/raw目录中。所有在res/raw目录中的文件不会被压缩,这样可以直接提取该目录中的文件。
71.如何打开res/raw目录中的数据库文件?
在Android中不能直接打开res/raw目录中的数据库文件,而需要在程序第一次启动时将该文件复制到手机内存或SD卡的某个目录中,然后再打开该数据库文件。复制的基本方法是使用getResources().openRawResource方法获得res/raw目录中资源的 InputStream对象,然后将该InputStream对象中的数据写入其他的目录中相应文件中。在Android SDK中可以使用SQLiteDatabase.openOrCreateDatabase方法来打开任意目录中的SQLite数据库文件。
72.AIDL的全称是什么?如何工作?能处理哪些类型的数据?
AIDL的英文全称是Android Interface Define Language
当A进程要去调用B进程中的service时,并实现通信,我们通常都是通过AIDL来操作的
A工程:
首先我们在net.blogjava.mobile.aidlservice包中创建一个RemoteService.aidl文件,在里面我们自定义一个接口,含有方法get。ADT插件会在gen目录下自动生成一个RemoteService.java文件,该类中含有一个名为RemoteService.stub的内部类,该内部类中含有aidl文件接口的get方法。
说明一:aidl文件的位置不固定,可以任意 , 然后定义自己的MyService类,在MyService类中自定义一个内部类去继承RemoteService.stub这个内部类,实现get方法。在onBind方法中返回这个内部类的对象,系统会自动将这个对象封装成IBinder对象,传递给他的调用者。其次需要在AndroidManifest.xml文件中配置MyService类,代码如下:
<!-- 注册服务 -->
<service android:name=".MyService">
<intent-filter>
<!-- 指定调用AIDL服务的ID -->
<action android:name="net.blogjava.mobile.aidlservice.RemoteService" />
</intent-filter>
</service>
为什么要指定调用AIDL服务的ID ? 就是要告诉外界MyService这个类能够被别的进程访问,只要别的进程知道这个ID,正是有了这个ID,B工程才能找到A工程实现通信。
说明:AIDL并不需要权限
B工程:首先我们要将A工程中生成的RemoteService.java文件拷贝到B工程中,在bindService方法中绑定aidl服务 , 绑定AIDL服务就是将RemoteService的ID作为intent的action参数。
说明:如果我们单独将RemoteService.aidl文件放在一个包里,那个在我们将gen目录下的该包拷贝到B工程中。如果我们将RemoteService.aidl文件和我们的其他类存放在一起,那么我们在B工程中就要建立相应的包,以保证RmoteService.java文件的包名正确,我们不能修改RemoteService.java文件
bindService(new Inten("net.blogjava.mobile.aidlservice.RemoteService"), serviceConnection, Context.BIND_AUTO_CREATE);
ServiceConnection的onServiceConnected(ComponentName name, IBinder service)方法中的service参数就是A工程中MyService类中继承了RemoteService.stub类的内部类的对象。
73.请解释下在单线程模型中Message、Handler、Message Queue、Looper之间的关系。
- Handler简介:一个Handler允许你发送和处理Message和Runable对象,这些对象和一个线程的MessageQueue相关联。每一个线程实例和一个单独的线程以及该线程的MessageQueue相关联。当你创建一个新的Handler时,它就和创建它的线程绑定在一起了。这里,线程我们也可以理解为线程的MessageQueue。从这一点上来看,Handler把Message和Runable对象传递给MessageQueue,而且在这些对象离开MessageQueue时,Handler负责执行他们。
Handler有两个主要的用途:
+ 确定在将来的某个时间点执行一个或者一些Message和Runnable对象。
+ 在其他线程(不是Handler绑定线程)中排入一些要执行的动作。
Scheduling Message,即(1),可以通过以下方法完成:
+ post(Runnable):Runnable在handler绑定的线程上执行,也就是说不创建新线程。
+ postAtTime(Runnable,long):
+ postDelayed(Runnable,long):
+ sendEmptyMessage(int):
+ sendMessage(Message):
+ sendMessageAtTime(Message,long):
+ sendMessageDelayed(Message,long):
+ post这个动作让你把Runnable对象排入MessageQueue,MessageQueue收到这些消息的时候执行他们,当然以一定的排序。sendMessage这个动作允许你把Message对象排成队列,这些Message对象包含一些信息,Handler的hanlerMessage(Message)会处理这些Message.当然,handlerMessage(Message)必须由Handler的子类来重写。这是编程人员需要作的事。
当posting或者sending到一个Hanler时,你可以有三种行为:当MessageQueue准备好就处理,定义一个延迟时间,定义一个精确的时间去处理。后两者允许你实现timeout,tick,和基于时间的行为。
当你的应用创建一个新的进程时,主线程(也就是UI线程)自带一个MessageQueue,这个MessageQueue管理顶层的应用对象(像activities,broadcast receivers等)和主线程创建的窗体。你可以创建自己的线程,并通过一个Handler和主线程进行通信。这和之前一样,通过post和send message来完成,差别在于在哪一个线程中执行这个方法。在恰当的时候,给定的Runnable和Message将在Handler的MessageQueue中被Scheduled。
- Message简介:Message类就是定义了一个信息,这个信息中包含一个描述符和任意的数据对象,这个信息被用来传递给Handler.Message对象提供额外的两个int域和一个Object域,这可以让你在大多数情况下不用作分配的动作。尽管Message的构造函数是public的,但是获取Message实例的最好方法是调用Message.obtain(),或者Handler.obtainMessage()方法,这些方法会从回收对象池中获取一个。
- MessageQueue简介:
这是一个包含message列表的底层类。Looper负责分发这些message。Messages并不是直接加到一个MessageQueue中,而是通过MessageQueue.IdleHandler关联到Looper。
你可以通过Looper.myQueue()从当前线程中获取MessageQueue。
- Looper简介:
Looper类被用来执行一个线程中的message循环。默认情况,没有一个消息循环关联到线程。在线程中调用prepare()创建一个Looper,然后用loop()来处理messages,直到循环终止。
大多数和message loop的交互是通过Handler。
下面是一个典型的带有Looper的线程实现。
class LooperThread extends Thread {
public Handler mHandler;
public void run() {
Looper.prepare();
mHandler = new Handler() {
public void handleMessage(Message msg) {
// process incoming messages here
}
};
Looper.loop();
}
}
74.你如何评价Android系统?优缺点。
Android平台手机 5大优势:
一、开放性 (开源 ophone 阿里云( 完全兼容android) 乐os )
在优势方面,Android平台首先就是其开发性,开发的平台允许任何移动终端厂商加入到Android联盟中来。显著的开放性可以使其拥有更多的开发者,随着用户和应用的日益丰富,一个崭新的平台也将很快走向成熟。开放性对于Android的发展而言,有利于积累人气,这里的人气包括消费者和厂商,而对于消费者来讲,随大的受益正是丰富的软件资源。开放的平台也会带来更大竞争,如此一来,消费者将可以用更低的价位购得心仪的手机。
二、挣脱运营商的束缚
在过去很长的一段时间,特别是在欧美地区,手机应用往往受到运营商制约,使用什么功能接入什么网络,几乎都受到运营商的控制。从去年iPhone 上市 ,用户可以更加方便地连接网络,运营商的制约减少。随着EDGE、HSDPA这些2G至3G移动网络的逐步过渡和提升,手机随意接入网络已不是运营商口中的笑谈,当你可以通过手机IM软件方便地进行即时聊天时,再回想不久前天价的彩信和图铃下载业务,是不是像噩梦一样?互联网巨头Google推动的Android终端天生就有网络特色,将让用户离互联网更近。
三、丰富的硬件选择 (mtk android)
这一点还是与Android平台的开放性相关,由于Android的开放性,众多的厂商会推出千奇百怪,功能特色各具的多种产品。功能上的差异和特色,却不会影响到数据同步、甚至软件的兼容,好比你从诺基亚 Symbian风格手机 一下改用苹果 iPhone ,同时还可将Symbian中优秀的软件带到iPhone上使用、联系人等资料更是可以方便地转移,是不是非常方便呢?
四、不受任何限制的开发商
Android平台提供给第三方开发商一个十分宽泛、自由的环境,不会受到各种条条框框的阻扰,可想而知,会有多少新颖别致的软件会诞生。但也有其两面性,血腥、暴力、情色方面的程序和游戏如可控制正是留给Android难题之一。
五、无缝结合的Google应用
如今叱诧互联网的Google已经走过10年度历史,从搜索巨人到全面的互联网渗透,Google服务如地图、邮件、搜索等已经成为连接用户和互联网的重要纽带,而Android平台手机将无缝结合这些优秀的Google服务。
再说Android的5大不足:
一、安全和隐私
由于手机 与互联网的紧密联系,个人隐私很难得到保守。除了上网过程中经意或不经意留下的个人足迹,Google这个巨人也时时站在你的身后,洞穿一切,因此,互联网的深入将会带来新一轮的隐私危机。
二、首先开卖Android手机的不是最大运营商
众所周知,T-Mobile在23日,于美国纽约发布 了Android首款手机G1。但是在北美市场,最大的两家运营商乃AT&T和Verizon,而目前所知取得Android手机销售权的仅有 T-Mobile和Sprint,其中T-Mobile的3G网络相对于其他三家也要逊色不少,因此,用户可以买账购买G1,能否体验到最佳的3G网络服务则要另当别论了!
三、运营商仍然能够影响到Android手机
在国内市场,不少用户对购得移动定制机不满,感觉所购的手机被人涂画了广告一般。这样的情况在国外市场同样出现。Android手机的另一发售运营商Sprint就将在其机型中内置其手机商店程序。
四、同类机型用户减少 (山寨化严重)
在不少手机论坛都会有针对某一型号的子论坛,对一款手机的使用心得交流,并分享软件资源。而对于Android平台手机,由于厂商丰富,产品类型多样,这样使用同一款机型的用户越来越少,缺少统一机型的程序强化。举个稍显不当的例子,现在山寨机泛滥,品种各异,就很少有专门针对某个型号山寨机的讨论和群组,除了哪些功能异常抢眼、颇受追捧的机型以外。
五、过分依赖开发商缺少标准配置
在使用PC端的Windows Xp系统的时候,都会内置微软Windows Media Player这样一个浏览器程序,用户可以选择更多样的播放器,如Realplay或暴风影音等。但入手开始使用默认的程序同样可以应付多样的需要。在 Android平台中,由于其开放性,软件更多依赖第三方厂商,比如Android系统的SDK中就没有内置音乐 播放器,全部依赖第三方开发,缺少了产品的统一性。
75.嵌入式操作系统内存管理有哪几种, 各有何特性?
页式,段式,段页,用到了MMU,虚拟空间等技术
76.java中如何引用本地语言?
可以用JNI(java native interface java 本地接口)接口 。
77.谈谈Android的IPC(进程间通信)机制
IPC是内部进程通信的简称, 是共享"命名管道"的资源。Android中的IPC机制是为了让Activity和Service之间可以随时的进行交互,故在Android中该机制,只适用于Activity和Service之间的通信,类似于远程方法调用,类似于C/S模式的访问。通过定义AIDL接口文件来定义IPC接口。Servier端实现IPC接口,Client端调用IPC接口本地代理。
78.请解释下Android程序运行时权限与文件系统权限的区别
- 运行时权限Dalvik (android授权)
- 文件系统 (linux 内核授权)
79. View的刷新?
- 在需要刷新的地方,使用handle.sendmessage发送信息,然后在handle的handleMessage里面执行invaliate或者postinvaliate.
- android中实现view的更新有两个方法,一个是invalidate,另一个是postInvalidate,其中前者是在UI线程自身中使用,而后者在非UI线程中使用。
80.Android系统中GC在什么情况下会出现内存泄漏呢?(内存泄漏是指分配出去的内存无法回收了(导致内存资源耗尽),一个是收不回,一个是要的太多给不了,系统负担不起。)
- 数据库的cursor没有关闭
- 构造adapter时,没有使用缓存contentview
- 衍生listview的优化问题-----减少创建view的对象,充分使用contentview,可以使用一静态类来优化处理getview的过程
- Bitmap对象不使用时采用recycle()释放内存
- 调用registerReceiver后未调用unregisterReceiver()。
- 未关闭InputStream/OutputStream。
- Context泄漏。
- activity中的对象的生命周期大于activity
- 调试方法: DDMS==> HEAPSZIE==>dataobject==>[Total Size]
81.通过Intent传递一些二进制数据的方法有哪些?
- 使用Serializable接口实现序列化,这是Java常用的方法。
- 实现Parcelable接口,这里Android的部分类比如Bitmap类就已经实现了,同时Parcelable在Android AIDL中交换数据也很常见的。
82.Activity和Task的启动模式有哪些? 每种含义是什么?
有关在AndroidManifest.xml中的android:launchMode定义,主要有standard、singleTop、singleTask和singleInstance,同时对于android:taskAffinity这些问题大家也要了解,Android开发网在以前的文章中讲过,不过很多开发者仍然不是很清楚,这些基础问题我们以后仍然会再次总结。
83.Intent的几种有关Activity启动的方式有哪些,你了解每个含义吗?
Intent的一些标记有FLAG_ACTIVITY_BROUGHT_TO_FRONT 、FLAG_ACTIVITY_CLEAR_TOP、FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET、FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS、FLAG_ACTIVITY_MULTIPLE_TASK和FLAG_ACTIVITY_NEW_TASK 等。每种含义大家看SDK文档和具体跑下这样你的记忆会更深刻些。
84.Android都有哪些XML解析器,都熟练掌握吗?
这里XmlPull、SAX和DOM相信做过Web开发的都已经滚瓜烂熟了。
85.说说HashSet和HashTable的区别
HashSet相对于HashMap就是不能存放重复的数据,对于HashTable来说,存放的数据不能出现key或value为null这样的情况。
86.android的操作系统根据进程的优先级 把进程分为了若干个等级
- Foreground process 前台进程 ,就是用户可以看到的,优先级是最高的,即便是在内存不足的时候,系统也不会去杀死这个进程
- Visible process 可见进程 , 如果内存不足,会把比可见进程优先级低的进程给杀死
- Service process 如果一个程序只有一个后台的服务
- Background process 没有服务的进程 ,并且我们用户看不见这个进程
- Empty process 没有任何活动组件的进程 . 为了在使用这个进程的时候,能够更快的创建出来,所以默认情况不会杀死一个进程,那么这个进程就是一个empty的进程。
87.隐式、显式Intent的区别
- 显式意图 , 通过名字指明目标组件(这个组件名字字段component name field, 前面提到过, 有一个数值集)。既然组件名称通常不为其他应用程序的开发者所了解,显式意图典型的被用作应用程序的内部消息-例如一个活动启动 , 一个附属服务或姊妹活动
- 隐式意图 , 不命名目标组件(组件名称字段为空)。隐式意图经常用来激活其他应用程序的组件。
88.DDMS和TraceView的区别?
DDMS是一个程序执行查看器,在里面可以看见线程和堆栈等信息,TraceView是程序性能分析器,Traceview是android平台配备一个很好的性能分析的工具。它可以通过图形化的方式让我们了解我们要跟踪的程序的性能,并且能具体到method。。
89.Dalvik和标准Java虚拟机之间的主要差别?
Dalvik和标准Java虚拟机(JVM)之间的首要差别之一,就是Dalvik基于寄存器,而JVM基于栈。
Dalvik和Java之间的另外一大区别就是运行环境——Dalvik经过优化,允许在有限的内存中同时运行多个虚拟机的实例,并且每一个 Dalvik应用作为一个独立的Linux进程执行。
- 虚拟机很小,使用的空间也小;
- Dalvik没有JIT编译器;
- 常量池已被修改为只使用32位的索引,以简化解释器;
- 它使用自己的字节码,而非Java字节码。
90.简述SoundPool类和MediaPlayer的使用有什么要注意的地方?
91.简述什么是双缓冲?
闪烁是图形编程的一个常见问题。当进行复杂的绘制操作时会导致呈现的图像闪烁或具有其他不可接受的外观。双缓冲的使用解决这些问题。双缓冲使用内存缓冲区来解决由多重绘制操作造成的闪烁问题。当使用双缓冲时,首先在内存缓冲区里完成所有绘制操作,而不是在屏幕上直接进行绘图。当所有绘制操作完成后,把内存缓冲区完成的图像直接复制到屏幕。因为在屏幕上只执行一个图形操作,所以消除了由复杂绘制操作造成的图像闪烁问题。
在android中实现双缓冲,可以使用一个后台画布backcanvas,先把所有绘制操作都在这上面进行。等图画好了,然后在把backcanvas拷贝到
与屏幕关联的canvas上去,如下:
Bitmap bitmapBase = new Bitmap()
Canvas backcanvas = new Canvas(bitmapBase)
backcanvas.draw()...//画图
Canvas c = lockCanvas(null);
c.drawbitmap(bitmapBase);//把已经画好的图像输出到屏幕上
unlock(c)....
92.SQLite支持事务吗?添加删除如何提高性能?
SQLite作为轻量级的数据库,比MySQL还小,但支持SQL语句查询,提高性能可以考虑通过原始经过优化的SQL查询语句方式处理.
93.View、SurfaceView、GLSurFaceView 有什么区别
- view最基础的,必须在UI主线程内更新画面,速度较慢。
- SurfaceView 是view的子类 类似使用双缓机制 快速刷新界面 速度比view快
- GLSurfaceView 是SurfaceView的子类openGL专用的
94.以下代码正确吗?
interface A{
int x = 0;
}
class B {
int x = 1;
}
class C extends B implements A{
public void printX(){
System.out.println(x);
}
}
public class Main{
public static void main(String[] args){
new C().printX();
}
}
问输出结果是?
答案是编译不通过,报错The field x is ambiguous(字段x是不明确的 )
95.String a = "a";String b = "a";问a==b是否为true?
为true
96.同一个程序,但不同的Activity是否可以放在不同的Task任务栈中?
可以. 比方说在激活一个新的activity时候, 给intent设置flag , Intent的flag添加FLAG_ACTIVITY_NEW_TASK(intent.setFlag()),这个被激活的activity就会在新的task栈里面…
97.系统上安装了多种浏览器,能否指定某浏览器访问指定页面?
找到对应的浏览器的意图,传递数据URI , 激活这个意图
98.请继承SQLiteOpenHelper实现:
1)创建一个版本为1的“diaryOpenHelper.db”的数据库,
2)同时创建一个 "diary"表(包含一个_id主键并自增长,topic字符型100长度,content字符型1000长度)
3)在数据库版本变化时请删除diary表,并重新创建出diary表。
public class MyDbHelper extends SQLiteOpenHelper {
public final static String DATABASENAME = "diaryOpenHelper.db";
public final static int DATABASEVERSION = 1;
//创建数据库
public MyDbHelper(Context context, String name,
SQLiteDatabase.CursorFactory factory, int version) {
super(context, DATABASENAME, factory, DATABASEVERSION);
}
//创建表等机构性文件
@Override
public void onCreate(SQLiteDatabase db) {
String sql = "create table diary" + "(" + "_id integer primary key autoincrement," + "topic varchar(100)," + "content varchar(1000)" + ")";
db.execSQL(sql);
}
//若数据库版本有更新,则调用此方法
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
String sql = "drop table if exists diary";
db.execSQL(sql);
this.onCreate(db);
}
}
99.为什么要用ContentProvider?它和sql的实现上有什么差别?
- 屏蔽数据存储的细节,对用户透明,用户只需要关心操作数据的uri就可以了
- 不同app之间共享,操作数据
- Sql也有增删改查的方法.
- 但是contentprovider 还可以去增删改查本地文件.
100.什么时候使用Service?
拥有service的进程具有较高的优先级,官方文档告诉我们,Android系统会尽量保持拥有service的进程运行,只要在该service已经被启动(start)或者客户端连接(bindService)到它。当内存不足时,需要保持,拥有service的进程具有较高的优先级。
- 如果service正在调用onCreate, onStartCommand或者onDestory方法,那么用于当前service的进程相当于前台进程以避免被killed。
- 如果当前service已经被启动(start),拥有它的进程则比那些用户可见的进程优先级低一些,但是比那些不可见的进程更重要,这就意味着service一般不会被killed.
- 如果客户端已经连接到service (bindService),那么拥有Service的进程则拥有最高的优先级,可以认为service是可见的。
- 如果service可以使用startForeground(int, Notification)方法来将service设置为前台状态,那么系统就认为是对用户可见的,并不会在内存不足时killed。
如果有其他的应用组件作为Service,Activity等运行在相同的进程中,那么将会增加该进程的重要性。
1.Service的特点可以让他在后台一直运行,可以在service里面创建线程去完成耗时的操作.
2.Broadcast receiver捕获到一个事件之后,可以起一个service来完成一个耗时的操作.
3.远程的service如果被启动起来,可以被多次bind, 但不会重新create. 索爱手机X10i的人脸识别的service可以被图库使用,可以被摄像机,照相机等程序使用.
101.LayoutInflater 的创建方法?
- 系统服务LayoutInflater inflater = (LayoutInflater)Context.getSystemService(LAYOUT_INFLATER_SERVICE);
- 使用静态的from()方法LayoutInflater layoutInflater=LayoutInflater.from(Context);
- 使用Activity中的getLayoutInflater()方法,返回填充器LayoutInflater layoutInflater=getLayoutInflater();
102.res/raw与assets的区别
- res/raw不能有子文件,自动在R中生成ID,调用 Resources.openResource方法,控制文件流进行操作。
- assets,可以有子文件,必须要提供一个文件名和文件目录,使用AssetManager来打开文件操作。不需要提供一个资源ID。
103.调用与被调用:我们的通信使者Intent
Intent就是意图的意思 ,应用程序间使用Intent进行交流,打个电话啦,来个电话啦都会发Intent, 这个是Android架构的松耦合的精髓部分,大大提高了组件的复用性,比如你要在你的应用程序中点击按钮,给某人打电话,很简单啊,看下代码先:
Intent intent = new Intent();
intent.setAction(Intent.ACTION_CALL);
intent.setData(Uri.parse("tel:" + number));
startActivity(intent);
扔出这样一个意图,系统看到了你的意图就唤醒了电话拨号程序,打出来电话。什么读联系人,发短信啊,邮件啊,统统只需要扔出intent就好了,这个部分设计地确实很好啊。
那Intent通过什么来告诉系统需要谁来接受他呢?通常使用Intent有两种方法,第一种是直接说明需要哪一个类来接收代码如下:
Intent intent = new Intent(this, MyActivity.class);
intent.getExtras().putString("id", "1");
tartActivity(intent);
第一种方式很明显,直接指定了MyActivity为接受者,并且传了一些数据给MyActivity,在MyActivity里可以用getIntent()来得到这个intent和数据。
第二种就需要先看一下AndroidMenifest中的intentfilter的配置了
<intent-filter>
<action android:name="android.intent.action.VIEW"/>
<action android:value="android.intent.action.EDIT" />
<action android:value="android.intent.action.PICK" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="vnd.android.cursor.dir/vnd.google.note" />
</intent-filter>
这里面配置用到了action, data, category这些东西,那么聪明的你一定想到intent里也会有这些东西,然后一匹配不就找到接收者了吗?
action其实就是一个意图的字符串名称。上面这段intent-filter的配置文件说明了这个Activity可以接受不同的Action,当然相应的程序逻辑也不一样咯,提一下那个 mimeType,他是在ContentProvider里定义的,你要是自己实现一个ContentProvider就知道了,必须指定 mimeType才能让数据被别人使用。
总结一句,就是你调用别的界面不是直接new那个界面,而是通过扔出一个intent,让系统帮你去调用那个界面,这样就多么松藕合啊,而且符合了生命周期被系统管理的原则。
想知道category都有啥,Android为你预先定制好的action都有啥等等,请亲自访问官方链接Intent
ps:想知道怎么调用系统应用程序的同学,可以仔细看一下你的logcat,每次运行一个程序的时候是不是有一些信息比如:
Starting activity: Intent { action=android.intent.action.MAINcategories={android.intent.category.LAUNCHER} flags=0x10200000comp={com.android.camera/com.android.camera.GalleryPicker} } , 再对照一下Intent的一些set方法,就知道怎么调用咯,希望你喜欢:)