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*。
    对应的数据关系如下表:
java类型 本地c类型 说明 boolean jboolean 无符号,8位 byte jbyte 无符号,8位 char jchar 无符号,16位 short jshort 有符号,16位 int jint 有符号,32位 long jlong 有符号,64位 float jfloat 32位 double jdouble 64位 void void N/A

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);        }    }
原创粉丝点击