android面试题总结(一)
来源:互联网 发布:小甲鱼c语言教程 编辑:程序博客网 时间:2024/06/17 18:30
1、详说一下Android的系统架构,包括层与层之间的调用,binder,jni,底层文件读写函数
- 应用程序层 —java的应用层
- 应用程序框架层 –应用软件架构 封装好的api
- 运行库 –C或C++的函数库部分
linux内核层 –硬件驱动,网络电源,系统安全等等
android系统中,用JAVA写界面程序,调用jni中间中间库提供的接口,去操作某一个驱动点,实现read,weiter,iocttl等操作。
jni是java原生接口,java可以通过jni调用c,c++的库,由于java是运行在jvm上的,所以可以做到跨平台性,但是jni调用了原生的代码,使得java程序丧失了平台型
2、生命周期方法中,系统在做什么和我们应该做什么
onCreate 在创建界面,做一些数据的初始工作 onStart 可见界面,但是不可交互 onResume 见界面,可交互(Activity栈系统通过栈的方式管理这些, Activity在最上面,一般是先进后出的原则) onPause 可见界面不可交互 (这一步系统会停止动画等消耗CPU的事情,这个时候你应该保存一些你的数据,因为这个时候你的程序优先级降低,很有可能被系统回收) onstop 变得不可见,被下一个Activity覆盖 onDestroy 这个是activity被干掉前的最后一个调用方法了,有可能是被finsh掉或者系统为了节省空间将它暂时干掉,可以用isFinshing()来判断它,如果你有一个Progress Dialog在线程中转动,请在onDestory方法中把它cancle掉,不然等线程结束的时候,调用Dialog的Cancle方法会抛异常的。
以上的生命周期变化而带来了很多的问题,比如你的程序在新的线程中跑,这时候中断了,你还要去维护这个线程,是暂停还是杀掉还是保存数据呢?这个时候的Activity随时可能被杀掉,所以线程中使用便变量和一些界面元素就得注意了,这样的话我们一般使用Android的消息机制来处理多线程和界面交互的问题
3、如何让一个Activity变成一个窗口
在AndroidManifest.xml中设置Activity的主题
<!-- 使得Activity对话框的形式弹出来 -->android :theme="@android:style/Theme.Dialog"android:theme="@android:style/Theme.Dialog" <!-- 变成半透明 -->android:theme="@android:style/Theme.Translucent"android:theme="@android:style/Theme.Translucent"
Android中的Mainifest文件的suoy元素属性的介绍都可以参考 android.R.styleable.
4、Service的使用场景和生命周期
1、Service不能与用户进行交互,不能自己启动,运行在后台
2、我们退出程序,Service进程并没有结束,它仍然运行在后台
使用场景
1、我们想要在后台播放音乐,就得用Service
2、应用数据是通过网络数据获取,不同时间段的数据是不同的
3、可以用Service在后台定时更新,而不用每次打开应用的时候去获取
Service生命周期
Service的生命周期比Activity简单
它只继承了onCreate,onStart,onDestory这三个方法
- 第一次启动Service的时候,调用onCreate()方法,onStart()方法
- 停止Service时候,执行onDestory()
- 如果Service启动,我们再次启动Service的时候,不会再执行onCreate()方法,而是直接执行onStart()方法
5、jni的书写步骤
- 声明native方法
- 编译java类
- 使用javah生成扩展名为.h的头文件
- 使用C或者C++实现本地方法
- 将C或者C++编写的文件生成动态链接库
这里以HelloWorld为例子
class HelloWorld{ //声明native方法,不能实现 public native void displayHelloWorld();/***加载静态库,参数"hello"是动态库的名字*可以理解为:我们displayHelloWorld()并没有实现,但是我们直接调用*了,所以必须在使用之前进行初始化,一般用static块进行加载*/static{System.loadLibirary("hello")}public static void main(String[] args){new HelloWorld().displayHelloWorld(); }}
6、jni调用考虑的问题
1、java和c是如何互通的
- 不能互通的原因是 数据类型 的问题
- 但是jni解决了这样的问题,例如C文件中的jstring数据类型是java传入的string对象,经过jni函数的转化就能成为c的chat*。
对应的数据关系如下表:
7、Android的动画有哪几类,它们的特点和区别是什么
1、Tween动画,使视图发生位置改变,分别是透明度,缩放,位移,放大
2、帧动画:给出一些图片,通过顺序播放排列好的图片进行shixina
3、属性动画:真正的改变属性
8、Handler机制的原理
Android提供了Handler和Looper来满足线程间的通信
1、Looper:一个线程产生一个Looper对象,用来管理线程间的MessageQueue(消息队列)
2、Handler:构造Handler对象与Looper进行沟通
3、MessageQueue 消息队列,用来存放线程放入的消息
4、线程:程序启动的时候会替线程创建一个MessageQueue。
9、Android中的存储方式
1、使用SharedPreference存储数据
2、文件存储数据
3、Sqlite数据库存储数据
4、使用ContentProvider存储数据
5、网络存储数据
Android中数据的存储都是私有的,应用程序之间都是无法访问的,除非通过ContentResolver来获取其他程序共享的数据
10、ContentProvider实现数据的共享
ContentProvider:为存储和获取数据提供统一的接口,可以在不同的应用程序之间共享数据。无论数据来源是什么,ContentProvider都会认为是一种表,然后把数据组织成表格
- 1、定义一个类继承ContentProvider
- 2、实现ContentProvider的所有方法,query,insert,update,delete等
- 3、在AndroidMinifest.xml文件中声明
11、Service的启用和关闭
1、通过调用Context.startService()启动,调用Context.stopService()结束, startService()可以传递参数给Service.
2、第二种方式可以通过bindService()启动,unbindService()结束
这种方法可以通过ServiceConnection访问Service
Service 在每一次开启和关闭的过程中,只有onStartCommand可以被多次调用,其他的其他onCreate,onBind,onUnbind,onDestory在一个生命周期中只能被调用一次。
12、注册广播的方式有几种,这些方式有什么优缺点
Android中,不同的进程之间传递信息要用的广播
- 方式1、Mainfest.xml中注册,这是一种比较推荐的方式
<receiver android:name = ".MyBroadcastReceiver" <intent-filter> <action android:name="com.zhuanghongji.broadcastreceiver.test" /> <intent-filter/><receiver/>
上面的两个android:name分别是广播名和广播动作名
如果要自己发送一个广播,在代码的地方
Intent i=new Intent("com.zhuanghongji.broadcastreceiver.test”)sendBroadcast(i)
这样的话,广播就发送过去了,下面就是接收了
新建一个类,继承至BroadcastReceiver,也可以创建一个BroadcastReceiver的实例,然后重新里面的onReceiver()方法,实现如下:
protected BroadcastReceiver mEvtReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); if (action.equals("com.zhuanghongji.broadcastreceiver.test")) { //Do something } }};
- 方式2,在代码中进行注册,但是需要手动在onDestory()注销
可以在代码中通过IntentFilter设置action,使用registerReceiver方法进行注册
IntentFilter filter = new IntentFilter();filter.addAction("com.zhuanghongji.broadcastreceiver.test");registerReceiver(mEvtReceiver, filter); // 这时注册了一个recevier ,名为mEvtReceiver,// 然后同样用上面的方法以重写onReceiver,// 最后在程序的onDestroy中要注销广播,实现如下:@Overridepublic void onDestroy() { super.onDestroy(); unregisterReceiver(mPlayerEvtReceiver);}
13、广播引入进制的用意
1、广泛用于应用程序之间通信的一种手段,类似于事件处理机制,不同的地方就是广播的处理是系统级别处理过程,而一般的事件处理是控件级别的。在这个过程中仍然离不开Intent对象
2、在Android中如果要发送一个广播就必须要使用到sendBroadcast(intent i)向系统发送对其感兴趣的广播接收器中
3、使用广播的时候必须要有一个intent对象必设置动作对象
4、每次接收广播的时候会重新生成一个接收广播的对象,在Broadcast中尽量不要处理太多的逻辑,复杂的逻辑一般交给Activity或者Service去处理
14、Broadcast的生命周期
一个广播在处理完成onReceive,那么系统将认定这个对象将不再是一个活动的对象,就会finish掉
15、单线程模型中Message,Handler,MessageQueue,Looper之间的关系
Message:Handler接收和处理的消息对象。
Handler:发送和处理消息。
MessageQueue:消息队列,以”先进先出”的方式管理Message。
Looper:读取MessageQueue的消息,然后把消息交给”发送该消息的Handler”进行处理。
16、AIDI如何工作?能处理哪些类型的数据
1、AIDL—android接口描述语言
- 编译器可以通过aidl文件生成一段代码,通过预先定义的接口达到两个进程内部的通信,进程间跨界对象访问的目的
- aidl的机制是基于接口的,是轻量级的。
2、使用aidl,需要完成2件事情
- 1、引入aidl的相关类
- 2、调用aidl产生的class
理论上,参数可以传递基本数据类型String,还有就是Bundle的派生类
3、具体实现步骤
- 1、创建aidl文件
这个文件里面定义了接口,该接口定义了可供客户端访问的方法和属性 - 2、编译aidl文件
用Ant的话,可能需要手动,使用Eclipse plugin的话,可以根据aidl文件自动产生java文件并编译,不需要人为接入 - 3、在java文件中,实现aidl接口
编译器会通过aidl接口,产生一个java接口。这个接口有一个名为stub的内部抽象类,它继承扩展了接口并实现了远程调用需要的几个方法。 - 4向客户端提供接口 ITaskBinder
如果写的是service,扩展该Service并重载 onBind () 方法来返回一个实现上述接口的类的实例。 - 5在服务器端回调客户端的函数
前提是当客户端获取的IBinder接口的时候,要去注册回调函数, 只有这样, 服务器端才知道该调用那些函数。
17、什么是ANR?如何避免它
1、什么是ANR?
程序无响应。
android应用程序完全运行在一个独立的线程中,任何在主线程中运行的,需要消耗大量时间的操作都会引发ANR,这个时候你的程序没有时间去响应输入的事件和意向广播
2、当你在下列的情况下,android就会显示anr对话框了
- 1、输入事件(按键、触摸事件)响应时间超过5秒
- 2、意向接收器(intentReceiver)超过10秒仍未执行完毕
3、如何避免它
主线程为子线程提供了handler,让子线程在即将结束的时候调用它与主线程通信
18、谈谈你对Intent的理解
一个Intent是一个intent的对象,它保存了消息的内容
1、对于activity和Service来说,它提供了请求的操作名和待操作数据的uri
2、Intent对象可以显示在一个指定的目标组件
这样的话,android会找到这个组件(基于Manifest),如果目标组件不是显示指定的,android就必须找到响应intent的那个组件。它是通过intent对象和目标的intent filiter相比较来完成这一个工作的。
19、Android中引入广播有什么用意
1、同一个应用中,方便了几大组件信息和数据的交互
2、在应用中,实现互相通信。(例如自己的应用程序内监听系统来电)
3、效率上更高,就相当于UDP的广播协议在局域网很方便
4、设计模式上类似于反转控制的一种应用,类似于监听者模式
20、DDMS和TranceView的区别
DDMS:一个程序的执行查看器,可以查看线程和堆栈情况
TranceView:程序性能分析器
21、Android中的ipc机制
ipc就是进程之间的通信
1、Activity和Service之间的通信
2、aidl接口文件来定义ipc接口
servier端实现IPC接口
Client端调用IPC接口本地代理
22、内存溢出和内存泄漏有什么区别
1、内存溢出:软件需要运行的内存,超出了它可用的最大内存
2、内存泄漏:对某一个内存空间进行使用,完成后没有释放,也就是GC管不到了
内存优化
内存溢出一般发生在图片的加载,我们可以使用图片的压缩和Lrucache缓存的目的来控制图片的加载
内存泄漏优化,一般在连接数据库,各种传感器,Service等耗费资源较大的对象进行及时关闭
23、AsyncTask一般运用在哪里,它的缺陷是什么,如何解决
一般运用在耗时的操作里面,耗时操作完成后又得更新主线程
缺陷是它只维护了一个长度为128的线程池,同时可以执行5个线程,还有一个缓冲队列,当这些东西都已满的时候,再次添加任务会抛异常
解决:由一个控制线程的方法来处理AsyncTask的调用,判断线程池是否满了,如果满了则线程睡眠,否则继续处理
24、横竖屏切换时候Activity的生命周期?
- 不设置Activity的android:configChanges时,切屏会重新调用各个生命周期,切横屏时会执行一次,切竖屏时会执行两次
- 设置Activity的android:configChanges=”orientation”时,切屏还是会重新调用各个生命周期,切横、竖屏时只会执行一次
- 设置Activityandroid:configChanges=”orientation|keyboardHidden”时,切屏不会重新调用各个生命周期,只会执行onConfigurationChanged方法
25、Intent传递的数据大小
40K
26、进程优先级
分别有5种优先级
- 1、前台进程
用户正在操作的进程,优先级最高,需要用户自己杀死 - 2、可见进程
这个进程不含有任何前台的组件,但是仍然可以被用户在屏幕上所见
比如说是Activity打开了一个对话框,此时的Activity在后台也是可以见到的 - 3、服务进程
进程中运行着一个Service,这个Service是通过startService()开启的,并且不属于上面两种较高优先级的情况 - 4、后台进程
此进程持有一个用户看不见的Activity,但是并没有调用onDestory(),此时可认为是一个后台进程
通常会有很多个后台进程存在,它们会被保存在一个LRU (least recently used)列表中,这样就可以确保用户最近使用的activity最后被销毁,即最先销毁时间最远的activity。 - 5、空进程
如果一个进程不包含任何活跃的应用组件,则认为是空进程。
例如:一个进程当中已经没有数据在运行了,但是内存当中还为这个应用驻留了一个进程空间。
保存这种进程的唯一理由是为了缓存的需要,为了加快下次要启动这个进程中的组件时的启动时间。系统为了平衡进程缓存和底层内核缓存的资源,经常会杀死空进程。
27、Service中新开线程和直接新开线程的区别
(1)若直接在Activity中新开一条线程来做耗时操作,当该Activity退出到桌面或其他情况时将成为一个后台进程。
(2)若在Service中新启动线程,则此时Android会依据进程中当前活跃组件重要程度,将其判断为服务进程,优先级比(1)高。
因为服务进程的优先级比后台进程的优先级高,所以对于一个需要启动一个长时间操作的activity来说,开启一个service比创建一个工作线程的方法更好,尤其是对于操作将很可能超出activity的持续时间时。
比如要上传一个图片文件,应该开启一个service来进行上传工作,这样在用户离开activity时工作仍在进行。使用service将会保证操作至少有服务进程的优先级。
28、尽可能保证Service不死常用技巧总结
- 1、在AndroidManifest.xml文件中对于intent-filter可以通过android:priority = “1000”这个属性设置最高优先级,1000是最高值,如果数字越小则优先级越低,同时实用于广播。
<service android:name="com.dbjtech.acbxt.waiqin.UploadService" android:enabled="true" > <intent-filter android:priority="1000" > <action android:name="com.dbjtech.myservice" /> </intent-filter> </service>
2、在onStartCommand里面调用 startForeground()方法把Service提升为前台进程级别,然后再onDestroy里面要记得调用stopForeground ()方法。
3、onStartCommand方法,返回START_STICKY。
手动返回START_STICKY,亲测当service因内存不足被kill,当内存又有的时候,service又被重新创建,比较不错,但是不能保证任何情况下都被重建,比如进程被干掉了….
public int onStartCommand(Intent intent, int flags, int startId) { flags = START_STICKY; return super.onStartCommand(intent, flags, startId); }
补充说明:onStartCommand()方法,返回的是一个int整形。
这个整形可以有以下四个取值:
1):START_STICKY:如果service进程被kill掉,保留service的状态为开始状态,但不保留递送的intent对象。随后系统会尝试重新创建service,由于服务状态为开始状态,所以创建服务后一定会调用onStartCommand(Intent,int,int)方法。如果在此期间没有任何启动命令被传递到service,那么参数Intent将为null。
2):START_NOT_STICKY:“非粘性的”。使用这个返回值时,如果在执行完onStartCommand后,服务被异常kill掉,系统不会自动重启该服务
3):START_REDELIVER_INTENT:重传Intent。使用这个返回值时,如果在执行完onStartCommand后,服务被异常kill掉,系统会自动重启该服务,并将Intent的值传入。
4):START_STICKY_COMPATIBILITY:START_STICKY的兼容版本,但不保证服务被kill后一定能重启。
- 4、在onDestroy方法里发广播重启service。
service +broadcast 方式,就是当service走ondestory的时候,发送一个自定义的广播,当收到广播的时候,重新启动service。(第三方应用或是在setting里-应用-强制停止时,APP进程就直接被干掉了,onDestroy方法都进不来,所以无法保证会执行)
<receiver android:name="com.dbjtech.acbxt.waiqin.BootReceiver" > <intent-filter> <action android:name="android.intent.action.BOOT_COMPLETED" /> <action android:name="android.intent.action.USER_PRESENT" /> <action android:name="com.dbjtech.waiqin.destroy" />//这个就是自定义的action </intent-filter> </receiver>
在onDestroy时:
@Override public void onDestroy() { stopForeground(true); Intent intent = newIntent("com.dbjtech.waiqin.destroy"); sendBroadcast(intent); super.onDestroy(); }
在BootReceiver里:
public class BootReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { if (intent.getAction().equals("com.dbjtech.waiqin.destroy")) { //TODO //在这里写重新启动service的相关操作 startUploadService(context); } }}
- 5、监听系统广播来判断Service的状态
通过系统的一些广播,比如:手机重启、界面唤醒、应用状态改变等等监听并捕获到,然后判断我们的Service是否还存活。
<receiver android:name="com.dbjtech.acbxt.waiqin.BootReceiver" > <intent-filter> <action android:name="android.intent.action.BOOT_COMPLETED" /> <action android:name="android.intent.action.USER_PRESENT" /> <action android:name="android.intent.action.PACKAGE_RESTARTED" /> <action android:name="com.dbjtech.waiqin.destroy" /> </intent-filter> </receiver>
BroadcastReceiver中:
@Override public void onReceive(Context context, Intent intent) { if (Intent.ACTION_BOOT_COMPLETED.equals(intent.getAction())) { System.out.println("手机开机了...."); startUploadService(context); } if (Intent.ACTION_USER_PRESENT.equals(intent.getAction())) { startUploadService(context); } }
- android面试题总结一:
- Android 面试题总结(一)
- android面试题总结(一)
- Android面试题总结(一)
- Android面试题总结(一)
- java android面试题分析总结《一》
- Android 面试题总结之View(一)
- Android 面试题总结之View(一)
- android 面试题一
- android面试题一
- Android面试题一
- Android面试题一
- android 面试题一
- Android 面试题一
- android 面试题一
- Android面试题(一)
- Android面试题一
- Android面试题(一)
- 如何在Ubuntu的服务器安装mongodb并开启远程连接
- 几种常用编程语言的编程思想和方法
- 基于opencv的人脸识别
- 其他
- mongodb主从用户权限管理
- android面试题总结(一)
- 【Openjudge】中缀表达式的值
- 集合类:单列集合--Collection
- 小猪的C语言快速入门系列(一)
- 甲骨文字理鼒爰武国平逻辑系统:卜占
- Java 堆栈内存分配
- Scanning errors (1): 1 Could not read pom.xml
- NDK层实现双进程守护
- SetRegistryKey的作用(转载)