以下是某家金融证券类公司的Android笔试题,及自己整理的答案,如有错误请诸位看官指正,小生在此先行谢过。
基础篇:
1、请描述下Activity的生命周期,说明下出现的条件和顺序。
按照顺序分别是:onCreate(),onStart(),onRestart(),onResume(),onPause(),onStop(),onDestory();
完整生命周期:一个activity从出现到消失,对应的周期方法是从onCreate()到onDestory();
可见生命周期:当activity处于用户可见状态,将多次执行从onStart()到onStop();
前景生命周期:当activity可以与用户交互时,将多次执行从onResume()到onPause();
2、如果后台的Activity被系统回收了,如何在被回收之前保存当前状态。
调用onSaveInstanceState() 方法保存数据:
@Override
protected void onSaveInstanceState(Bundle outState) {
// TODO Auto-generated method stub
super.onSaveInstanceState(outState);
String statetext=tView1.getText().toString();
outState.putString("state", statetext);
}
在onCreate()中恢复保存的数据:
if(savedInstanceState!=null){
String statetextString=savedInstanceState.getString("state");
}
3、如何将activity设置成窗口化。
第一种方法,在styles.xml文件中,可以新建如下的类似Dialog的style。
<style name=“Theme.FloatActivity” parent=“android:style/Theme.Dialog”> </style>。然后在AndroidManifest.xml中在需要显示为窗口的Activity中添加如下属性: android: theme=“@style/Theme.FloatActivity”即可。
第二种方法,也可以直接添加对应需要展示为Dialog style的Activity的android: theme属性为android: theme=“@ android: style/Theme.Dialog”
4、如何退出activity?如何安全退出已调用多个activity的application?
对于单一的activity,直接finish()即可,或者可以使用killProcess()和System.exit();
对于多个activity,可以定义一个list<activity>,实现创建的时候将activity缓存在list中,销毁的时候从list中移除,按退出按钮,则遍历整个List将Activity一一销毁;
5、请介绍下Android的数据存储方式。
1)SharePreference:采用XML格式将数据存储到设备中,只能在同一包名内使用;
2)文件存储:存储文件到 /data/data/包名/files 内存里面,默认是私有的访问权限;
3)SQLite数据库:Android自带的轻量级嵌入式数据库,支持SQL语句;
4)ContentProvider:主要用于应用程序之间的数据交换;
5)网络存储:通过网络上的存储空间上传下载数据;
6、请介绍下ContentProvider时如何实现数据共享。
ContentProvider是以Uri的形式对外提供数据,ContenrResolver是根据Uri来访问数据。
步骤:
1)定义自己的ContentProvider类,继承系统的ContentProvider类
2)在Mainifest.xml文件中注册ContentProvider,注册时需要绑定一个URL
<manifest .... >
<application android:icon="@drawable/icon" android:label="@string/app_name">
<provider android:name=".PersonContentProvider"
android:authorities="com.faith.providers.personprovider" />
</application>
</manifest>
(注:authorities就相当于为该ContentProvider指定URL)
3)其他程序调用ContentReslover的insert(),delete(),update(),query()进行增删改查。
7、请介绍下Android的五种常用的布局。
FrameLayout(帧布局):从屏幕左上角开始布局,叠加显示
LinearLayout(线性布局):可分为垂直、水平布局
AbsoluteLayout(绝对布局):用X,Y坐标制定元素位置
RelativeLatout(相对布局):以一个元素为参照物,来定位布局方式
TableLayout(表格布局):行和列的表格布局
8、如何启动service,如何停用service。
1)调用Context.startService()方法启动服务,在服务为创建时系统会先调用onCreate()方法,接着调用onStart()方法。调用Context.stopService方法结束服务,服务结束时会调用onDestroy()方法;
2)调用Context.bindService()法启动服务,在服务为创建时系统会先调用onCreate()方法,接着调用onBind()方法,这个时候调用者与服务绑定在一起了,当调用者退出时系统会调用服务的onUnbind()-->onDestroy()方法。解除绑定可调用unvindService()方法,调用该方法也会导致系统调用服务的onUnbind()-->onDestroy()方法;
9、注册广播的有几种方式,有何优缺点?请谈谈Android引入广播机制的用意。
1)静态注册,只要是设备开启状态,广播接受器就是打开着的,无需担心接收器是否被关闭;
2)动态注册,广播跟随程序的生命周期,优先级高于静态注册;
引入广播机制的用意:
a:从MVC的角度考虑(应用程序内)
b:程序间互通消息(例如在自己的应用程序内监听系统来电)
c:效率上(参考UDP的广播协议在局域网的方便性)
d:设计模式上(反转控制的一种应用,类似监听者模式)
10、请设计一段断点续传的代码,说明关键几点即可。
在本地下载过程中要使用数据库实时存储到底存储到文件的哪个位置了,这样点击开始继续传递时,才能通过HTTP的GET请求中的setRequestProperty()方法可以告诉服务器,数据从哪里开始,到哪里结束。同时在本地的文件写入时,RandomAccessFile的seek()方法也支持在文件中的任意位置进行写入操作。同时通过广播将子线程的进度告诉Activity的ProcessBar。
11、关于Android应用程序自动更新方式,请阐述一种合理的方式。
1)获取服务器版本,对比当前版本,判断是否需要更新程序;
2)弹出是否下载新版本对话框,点击下载
3)在通知栏显示下载进度
4)下载完成后,调用系统安装软件服务,安装软件
12、Intent的几种有关activity启动方式有哪些,说明下每种方式的含义。
Activity有如下两种启动模式:
1)通过AndroidMainifest.xml给Activity 指定启动模式
2)通过intent中设置标志位为Activity 指定启动模式
常用的Activity 的Flags有:
FLAG_ACTIVITY_NEW_TASK :为 Activity 指定 “singleTask” 启动模式
FLAG_ACTIVITY_SINGLE_TOP :为 Activity 指定 “singleTop” 启动模式
FLAG_ACTIVITY_CLEAR_TOP:具有此标志位的 Activity ,当它启动时,在同一个任务栈中所有位于它上面的 Activity 都要出栈。这个模式一般需要和 FLAG_ACTIVITY_NEW_TASK 配合使用。singleTask 启动模式默认具有此标志位的效果。
FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS:
具有这个标记的 Activity 不会出现在历史 Activity 的列表中,它等同于在 XML 中指定 Activity 的属性 android:excludeFromRecents="true" 。
13、说说你对自定义控件的想法,介绍下你做过的某些自定义控件。
随着UI越来越绚丽,Android自带控件已无法满足产品的脑洞了,这时候就需要我们自己来实现满足项目需求的控件。常用的自定义控件有如下几种:
1)基于原声控件的扩展(如:实现可滚动字体的TextView)
2)基于组合控件的扩展(如:可以图文混排的LinearLayout)
3)自定义View(如:波浪加载动画)
自定义View的绘制主要有三种方法onMeasure(),onLayout(),onDraw();
14、你如何评价Android系统,有何优缺点。
优点:
开源性,市场占有率大;
无缝结合Google应用
缺点:
安全与隐私
运行商可定制系统
缺乏标准配置
15、请解释下在单线程模型中Message、Handler、Message Queue、Looper之间的关系。
简单的说,Handler获取当前线程中的 looper对象,looper 用来从存放 Message 的 MessageQueue中取出 Message,再有 Handler 进行 Message 的分发和处理.
Message Queue(消息队列): 用来存放通过 Handler 发布的消息, 通常附属于某一个创建它的线程,可以通过 Looper.myQueue()得到当前线程的消息队列
Handler:可以发布或者处理一个消息或者操作一个 Runnable,通过 Handler发布消息, 消息将只会发送到与它关联的消息队列,然也只能处理该消息队列中的消息
Looper:是 Handler 和消息队列之间通讯桥梁,程序组件首先通过 Handler 把消息传递给 Looper,Looper 把消息放入队列。Looper 也把消息队列里的消息广播给所有的 Handler,Handler接受到消息后调用 handleMessage进行处理
Message:消息的类型,在 Handler 类中的 handleMessage 方法中得到单个的消息进行处理
在单线程模型下, 为了线程通信问题, Android 设计了一个 Message Queue(消息队列), 线程间可以通过该 Message Queue 并结合 Handler 和 Looper 组件进行信息交换。
16、Android 中线程与线程,进程与进程之间如何通信。
一个Android程序开始运行时,会单独启动一个process,这个process呈现的是单线程模型,即mianthread,所有的任务都在一个线程中运行。所以mainthread所调用的每一个函数耗时越短越好,对于比较耗时的工作应该交给子线程去做,以避免主线程阻塞。Android提供了Handler和Looper来满足线程之间的通信。
Android的IPC(进程间通信)机制是为了让activity和service之间可以随时进行交互,所以该机制只适用于activity和service之间的通信。 要实现跨进程通信,需要借助AIDL(Android Interface Definition Language)。Android中的跨进程服务其实是采用C/S的架构,因而AIDL的目的就是实现通信接口。简单来说就是通过定义 AIDL 接口文件来定义 IPC 接口。Servier 端实现 IPC接口,Client 端调用 IPC接口本地代理。
17、 AIDL的全称是什么?如何工作?
AIDL 全称 Android Interface Definition Language(Android 接口描述语言)是一种接口描述语言 ; 编译器可以通过 aidl文件生成一段代码,通过预先定义的接口达到两个进程内部通信进程跨界对象访问的目的。
AIDL的IPC的机制和COM 或 CORBA 类似,是基于接口的,但它是轻量级的。它使用代理类在客户端和实现层间传递值。
如果要使用 AIDL, 需要完成2件事情 :
- 引入AIDL的相关类;
- 调用aidl产生的 class;(理论上 , 参数可以传递基本数据类型和String, 还有就是Bundle的派生类 )
进阶篇
1、请阐述之前使用过的网络通信框架,包含了调用方式,封装数据对象,传输,返回数据解析,以及全局的一场捕获和处理。
这一题不知道具体怎么回答,就简单列出一个OKhttp的GET请求代码:
OkHttpClient okHttpClient=new OkHttpClient();
Request request=new Request.Builder()
.url("http://www.baidu.com")
.build();
Call call=okHttpClient.newCall(request);
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
}
@Override
public void onResponse(Call call, Response response) throws IOException {
Log.d(LOG,"body"+response.body().toString());
}
});
2、有4个Activity A、B、C、D在当前应用的页面栈中,请描述如何保证在互相随意跳转,打开的是原来的界面,并且4个activity都不会被回收或者重新打开一个新的对象。
这个问题也不知道怎么回答才好,先简单列一下Android的四种启动模式,再做分析吧。
1)standard:标准模式,也就是Android默认的启动方式。在该模式下没启动一个activity就会重新创建一个新的实例,不管这个实例在任务中是否存在。
2)singleTop:栈顶复用模式。假如A启动B,就会判断A所在的栈顶是否是B实例,如果是则直接引用这个栈顶实例,如果不是则重新创建的B实例加载到栈顶。
3)singleTask:站内复用模式。如果要启动的activity不存在,则创建新的的实例并加载到栈顶;如果位于栈中,则销毁上面的实例,使该实例位于栈顶;如果已位于栈顶,则与singleTop模式相同。
4)singleInstance:单例模式。这个是 singleTask 模式的加强版,它除了具有 singleTask 模式的所有特性外,它还有一点独特的特性,那就是此模式的 Activity 只能单独地位于一个任务栈,不与其他 Activity 共存于同一个任务栈。
经过上面的描述,可以看出满足题中条件只能使用singleTop,即栈顶复用模式,具体方法就是通过AndroidMenifest 给 Activity 指定启动模式:
<activity android:name=".SecondActivity"
android:launchMode="singleTask"></activity>
3、描述下ANR错误,哪些情况会发生ANR错误,如何避免?
Application Not Responding 程序无响应,出现下列情况,会显示ANR框:
1)输入事件的响应时间超过5秒
2)BroadcastReceiver在10秒内没有执行完毕
造成以上两点的原因有很多,比如在主线程中进行耗时操作,如网络请求、IO等。避免方法就是不要在主线程中做耗时操作,而是采用handler+message的方式放在子线程中去实现。
4、如何理解application?你的项目中,application用来管理哪些数据?
Application是单例模式的类,android系统为每个应用程序创建一个Application类的对象且只创建一个。
启动Application时,系统会创建一个PID,即进程ID,所有的Activity都会在此进程上运行。
Application创建的时候初始化全局变量,同一个应用的所有Activity都可以取到这些全局变量的值
Application对象的生命周期是整个程序中最长的,它的生命周期就等于这个程序的生命周期
Application全局的单例的,所以在不同的Activity,Service中获得的对象都是同一个对象。
应用场景:
在Android中,可以通过继承Application类来实现应用程序级的全局变量,这种全局变量方法相对静态类更有保障,直到应用的所有Activity全部被destory掉之后才会被释放掉。
5、说说activity的affinity属性及其应用场景。
每个Activity都有taskAffinity属性,这个属性指出了它希望进入的Task。如果一个Activity没有显式的指明该Activity的taskAffinity,那么它的这个属性就等于Application指明的taskAffinity,如果Application也没有指明,那么该taskAffinity的值就等于包名。而Task也有自己的affinity属性,它的值等于它的根Activity的taskAffinity的值。
6、如何理解DVM的进程和Linux的进程
Dvm的进程是dalivk虚拟机进程,每个Android程序都运行在自己的进程里面,每个android程序系统都会给他分配一个单独的liunx uid(user id),每个dvm都是Linux里面的一个进程.所以说这两个进程是一个进程.
7、描述下JNI的编译和工作原理,你的项目中使用过JNI吗?
编译过程:
1)下载和配置NDK
2)新建项目MyJniDemo,然后再新建一个类JniUtils,在其内部声明native方法
3)将JNI的内容通过TextView显示在UI上
4)执行Build->Make Project,生成的.class文件目录
5)根据生成的class文件,利用javah生成对应的 .h头文件
6)在main目录下新建一个名为jni的目录,讲刚才的.h文件剪切过来,然后新建一个jniutils.c文件
7)在app module目录下的build.gradle中设置库文件名
8)在JniUtils类中添加静态初始化load代码
原理:
在JNI中,本地函数是通过一个独立的.c或.cpp文件来实现的(C++为JNI提供的界面会更简洁一些)。当JVM调用该函数时,它传递了一个JNIEnv指针、一个jobject指针和通过Java方法定义的Java参数
8、你理解的Android安全性可以分为哪几块?分别说说你的的一些安全解决方案,也可以单独举出一个场景来说明,如“登录”,“支付”流程。
1)数据传输过程遭劫持 解决:数据加密
2)APP反编译 解决:应用程序签名,混淆打包,应用加固
3)手机ROOT,进程被劫持 解决:应用权限控制
4)本地数据存储的安全性 解决:数据存储加密
9、如APP运行所需内存较大,在一些低端手机上经常会无法正常工作。请给出定位、解决内存问题的方案思路,可以结合你曾经解决过的场景说明。
本应该被回收的对象没有被GC回收,这些无用的对象会占用大量内存,这就是我们常说的内存泄漏。下面说一下怎么避免内存泄漏:
1)Application Context代替Activity Context
2)使用静态内部类和弱引用
3)资源对象必须关闭
4)注销监听器
5)不要加载过大的图片
6)对批量加载进行缓存设计