Android面试题:基本常识
1. 什么是ANR,如何避免它?
在Android上,如果你的应用程序有一段时间响应不够灵敏,系统会向用户显示一个对话框,这个对话框称作应用程序无响应(ANR:Application Not Responding)对话框。用户可以选择让程序继续运行,但是,他们在使用你的应用程序时,并不希望每次都要处理这个对话框。因此,在程序里对响应性能的设计很重要,这样,系统不会显示ANR给用户。不同的组件发生ANR的时间不一样,主线程(Activity、Service)是5秒,BroadCastReceiver是10秒。
解决方案:
将所有耗时操作,比如访问网络,Socket通信,查询大量SQL语句,复杂逻辑计算等都放在子线程中去,然后通过handler.sendMessage()、runonUITread()、AsyncTask等方式更新UI。无论如何都要确保用户界面操作的流畅度。如果耗时操作需要让用户等待,那么可以在界面上显示进度条。
2. 谈谈Android的优点和不足之处
优点:
- 开放性,开源,免费,可定制
- 挣脱运营商束缚
- 丰富的硬件选择
- 不受任何限制的开发商
- 无缝结合的Google应用
缺点:
- 安全问题、隐私问题
- 同质化严重
- 运营商对Android手机仍然有影响
- 山寨化严重
- 过分依赖开发商,缺乏标准配置
3. 一条最长的短信息约占多少byte?
在国内的三大运营商通常情况下中文70(包括标点),英文160个。对于国外的其他运行商具体多长需要看运营商类型了。
android内部是通过如下代码进行判断具体一个短信多少byte的。
ArrayList<String> android.telephony.SmsManager.divideMessage(String text)
4. sim卡的EF文件有何作用?
基本文件EF(Elementary File)是SIM卡文件系统的一部分。
文件 | 文件标识符 | 文件缩写 | 中文名称 | 文件作用 |
---|---|---|---|---|
MF | 3F00 | 根目录 | 备注:所有非ETSI GSM协议中规定的应用文件由各厂家自行定义在根目录下(如:PIN1,PIN2…) | |
EFICCID | 2FE2 | ICCID | SIM卡唯一的识别号 | 包含运营商、卡商、发卡时间、省市代码等信息 |
DFGSM | 7F20 | GSM目录 | 备注:根据ETSIGSM09.91的规定Phase2(或以上)的SIM卡中应该有7F21并指向7F20,用以兼容Phase1的手机 | |
EFLP语言选择 | 6F05 | LP | 语言选择文件 | 包含一种或多种语言编码 |
EFIMSI | 6F07 | IMSI | 国际移动用户识别符 | 包含SIM卡所对应的号段,比如46000代表135-139号段、46002代表1340-1348 |
EFKC语音加密密钥 | 6F20 | Kc | 计算密钥 | 用于SIM卡的加密、解密 |
EFPLMNsel网络选择表 | 6F30 | PLMNsel | 公共陆地网选择 | 决定SIM卡选择哪种网络,在这里应该选择中国移动的网络 |
EFHPLMN归属地网络选择表 | 6F31 | HPLMN | 两次搜索PLMN的时间间隔 | 两次搜索中国移动的网络的时间间隔 |
EFACMmax最大计费额 | 6F37 | ACMmax | 包含累积呼叫表的最大值 | 全部的ACM数据存在SIM卡中,此处取最大值 |
EFSST SIM卡服务表 | 6F38 | SST | SIM卡服务列表 | 指出SIM卡可以提供服务的种类,哪些业务被激活哪些业务没有开通 |
EFACM累加计费计数器 | 6F39 | ACM | 累计呼叫列表 | 当前的呼叫和以前的呼叫的单位总和 |
EFGID1分组识别1 | 6F3E | GID1 | 1级分组识别文件 | 包含特定的SIM-ME组合的标识符,可以识别一组特定的SIM卡 |
EFGID2分组识别2 | 6F3F | GID2 | 2级分组识别文件 | 包含特定的SIM-ME组合的标识符,可以识别一组特定的SIM卡 |
EFPUCT单位价格/货币表 | 6F41 | PUCT | 呼叫单位的价格和货币表 | PUCT是与计费通知有关的信息,ME用这个信息结合EFACM,以用户选择的货币来计算呼叫费用 |
EFCBMI小区广播识别号 | 6F45 | CBMI | 小区广播信息标识符 | 规定了用户希望MS采纳的小区广播消息内容的类型 |
EFSPN服务提供商 | 6F46 | SPN | 服务提供商名称 | 包含服务提供商的名称和ME显示的相应要求 |
EFCBMID | 6F48 | CBMID | 数据下载的小区广播消息识别符 | 移动台将收到的CBMID传送给SIM卡 |
EFSUME | 6F54 | SUME | 建立菜单单元 | 建立SIM卡中的菜单 |
EFBCCH广播信道 | 6F74 | BCCH | 广播控制信道 | 由于BCCH的存储,在选择小区时,MS可以缩小对BCCH载波的搜索范围 |
EFACC访问控制级别 | 6F78 | ACC | 访问控制级别 | SIM卡有15个级别,10个普通级别,5个高级级别 |
EFFPLMN禁止网络号 | 6F7B | FPLMN | 禁用的PLMN | 禁止选择除中国移动以外的其他运营商,比如中国联通、中国卫通等 |
EFLOCI位置信息 | 6F7E | LOCI | 位置信息 | 存储临时移动用户识别符、位置区信息等内容 |
EFAD管理数据 | 6FAD | AD | 管理数据 | 包括关于不同类型SIM卡操作模式的信息。例如:常规模式(PLMN用户用于GSM网络操作),型号认证模式(允许ME在无线设备的认证期间的特殊应用);小区测试模式(在小区商用之前,进行小区测试),制造商特定模式(允许ME制造商在维护阶段进行特定的性能自动测试) |
EFPHASE阶段 | 6FAE | PHASE | 阶段标识 | 标识SIM卡所处的阶段信息,比如是普通SIM卡还是STK卡等 |
DFTELECOM | 7F10 | 电信目录 | ||
EFADN缩位拨号 | 6F3A | AND | 电话簿 | 用于将电话记录存放在SIM卡中 |
EFFDN固定拨号 | 6F3B | FDN | 固定拨号 | 包括固定拨号(FDN)和/或补充业务控制字串(SSC),还包括相关网络/承载能力的识别符和扩展记录的识别符,以及有关的α识别符 |
EFSMS短消息 | 6F3C | SMS | 短消息 | 用于将短消息记录存放在SIM卡中 |
EFCCP能力配置参数 | 6F3D | CCP | 能力配置参数 | 包括所需要的网络和承载能力的参数,以及当采用一个缩位拨号号码,固定拨号号码,MSISDN、最后拨号号码、服务拨号号码或禁止拨号方式等,建立呼叫时相关的ME配置 |
EFMSISDN电话号码 | 6F40 | MSISDN | 移动基站国际综合业务网号 | 存放用户的手机号 |
EFSMSP短信息参数 | 6F42 | SMSP | 短消息业务参数 | 包括短信中心号码等信息 |
EFSMSS短信息状态 | 6F43 | SMSS | 短消息状态 | 这个标识是用来控制流量的 |
EFLND最后拨号 | 6F44 | LND | 最后拨叫号码 | 存储最后拨叫号码 |
EFExt1扩展文件1 | 6F4A | EXT1 | 扩展文件1 | 包括AND,MSISDN或LND的扩展数据 |
EFExt2扩展文件2 | 6F4B | EXT2 | 扩展文件2 | 包含FDN的扩展数据 |
5. 如何判断是否有SD卡?
通过如下方法:
Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)
如果返回true就是有sdcard,如果返回false则没有。
6. dvm的进程和Linux的进程, 应用程序的进程是否为同一个概念?
dvm指dalvik的虚拟机。每一个Android应用程序都拥有一个独立的Dalvik虚拟机实例,应用程序都在它自己的进程中运行。而每一个dvm都是在Linux 中的一个进程,所以说可以近似认为是同一个概念。
什么是android DVM:Dalvik是Google公司自己设计用于Android平台的Java虚拟机,每一个Dalvik 应用作为一个独立的Linux 进程执行。独立的进程可以防止在虚拟机崩溃的时候所有程序都被关闭。
Dalvik和Java虚拟机的区别
Dalvik主要是完成对象生命周期管理,堆栈管理,线程管理,安全和异常管理,以及垃圾回收等等重要功能。
Dalvik负责进程隔离和线程管理,每一个Android应用在底层都会对应一个独立的Dalvik虚拟机实例,其代码在虚拟机的解释下得以执行。
不同于Java虚拟机运行java字节码,Dalvik虚拟机运行的是其专有的文件格式Dex
dex文件格式可以减少整体文件尺寸,提高I/O操作的类查找速度。
odex是为了在运行过程中进一步提高性能,对dex文件的进一步优化。
所有的Android应用的线程都对应一个Linux线程,虚拟机因而可以更多的依赖操作系统的线程调度和管理机制
有一个特殊的虚拟机进程Zygote,他是虚拟机实例的孵化器。它在系统启动的时候就会产生,它会完成虚拟机的初始化,库的加载,预制类库和初始化的操作。如果系统需要一个新的虚拟机实例,它会迅速复制自身,以最快的数据提供给系统。对于一些只读的系统库,所有虚拟机实例都和Zygote共享一块内存区域。
7. Android程序与Java程序的区别?
Android程序用android sdk开发,java程序用javasdk开发。
Android SDK引用了大部分的Java SDK,少数部分被AndroidSDK抛弃,比如说界面部分,java.awt swing package除了java.awt.font被引用外,其他都被抛弃,在Android平台开发中不能使用。android sdk 添加工具jar httpclient , pull opengl
8. 启动应用后,改变系统语言,应用的语言会改变么?
这个一般是不会的,一般需要重启应用才能改变应用语言。但是对应应用来说如果做了国际化处理则支持如果没有处理那系统语言再更改也是无用的。
9. 请介绍下adb、ddms、aapt的作用
adb是Android Debug Bridge ,Android调试桥的意思,ddms是Dalvik Debug Monitor Service,dalvik调试监视服务。aapt即AndroidAsset Packaging Tool,在SDK的build-tools目录下。该工具可以查看,创建,更新ZIP格式的文档附件(zip, jar, apk)。也可将资源文件编译成二进制文件,尽管我们没有直接使用过该工具,但是开发工具会使用这个工具打包apk文件构成一个Android 应用程序。
Android 的主要调试工具是adb(Android debuging bridge),ddms是一个在adb基础上的一个图形化工具。adb,它是一个命令行工具。而ddms功能与adb相同,只是它有一个图形化界面。对不喜欢命今操作方式的人来说是一个不错的选择。
10. ddms 和traceview的区别
简单的说ddms是一个程序执行查看器,在里面可以看见线程和堆栈等信息,traceView是程序性能分析器。
11. TraceView的使用
TraceView简介
Traceview是Android平台特有的数据采集和分析工具,它主要用于分析Android中应用程序的hotspot(瓶颈)。Traceview本身只是一个数据分析工具,而数据的采集则需要使用Android SDK中的Debug类或者利用DDMS工具。二者的用法如下:
开发者在一些关键代码段开始前调用Android SDK中Debug类的startMethodTracing函数,并在关键代码段结束前调用stopMethodTracing函数。这两个函数运行过程中将采集运行时间内该应用所有线程(注意,只能是Java线程)的函数执行情况,并将采集数据保存到/mnt/sdcard/下的一个文件中。开发者然后需要利用SDK中的Traceview工具来分析这些数据。
借助Android SDK中的DDMS工具。DDMS可采集系统中某个正在运行的进程的函数调用信息。对开发者而言,此方法适用于没有目标应用源代码的情况。DDMS工具中Traceview的使用如下图所示。
点击上图中所示按钮即可以采集目标进程的数据。当停止采集时,DDMS会自动触发Traceview工具来浏览采集数据。
下面,我们通过一个示例程序向读者介绍Debug类以及Traceview的使用。
实例程序如下图所示:界面有4个按钮,对应四个方法。
点击不同的方法会进行不同的耗时操作。
public class MainActivity extends ActionBarActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void method1(View view) {
int result = jisuan();
System.out.println(result);
}
private int jisuan() {
for (int i = 0; i < 10000; i++) {
System.out.println(i);
}
return 1;
}
public void method2(View view) {
SystemClock.sleep(2000);
}
public void method3(View view) {
int sum = 0;
for (int i = 0; i < 1000; i++) {
sum += i;
}
System.out.println("sum=" + sum);
}
public void method4(View view) {
Toast.makeText(this, "" + new Date(), 0).show();
}
}
我们分别点击按钮一次,要求找出最耗时的方法。点击前通过DDMS 启动 Start Method Profiling按钮。
然后依次点击4个按钮,都执行后再次点击上图中红框中按钮,停止收集数据。
接下来我们开始对数据进行分析。
当我们停止收集数据的时候会出现如下分析图表。该图表分为2大部分,上面分不同的行,每一行代表一个线程的执行耗时情况。main线程对应行的的内容非常丰富,而其他线程在这段时间内干得工作则要少得多。图表的下半部分是具体的每个方法执行的时间情况。显示方法执行情况的前提是先选中某个线程。
我们主要是分析main线程。
上面方法指标参数所代表的意思如下:
列名 | 描述 |
---|---|
Name | 该线程运行过程中所调用的函数名 |
Incl Cpu Time | 某函数占用的CPU时间,包含内部调用其它函数的CPU时间 |
Excl Cpu Time | 某函数占用的CPU时间,但不含内部调用其它函数所占用的CPU时间 |
Incl Real Time | 某函数运行的真实时间(以毫秒为单位),内含调用其它函数所占用的真实时间 |
Excl Real Time | 某函数运行的真实时间(以毫秒为单位),不含调用其它函数所占用的真实时间 |
Call+Recur Calls/Total | 某函数被调用次数以及递归调用占总调用次数的百分比 |
Cpu Time/Call | 某函数调用CPU时间与调用次数的比。相当于该函数平均执行时间 |
Real Time/Call | 同CPU Time/Call类似,只不过统计单位换成了真实时间 |
我们为了找到最耗时的操作,那么可以通过点击Incl Cpu Time,让其按照时间的倒序排列。我点击后效果如下图:
通过分析发现:method1最耗时,耗时2338毫秒。
那么有了上面的信息我们可以进入我们的method1方法查看分析我们的代码了。