Android常见面试题学习第一天(原创)

1. 内存泄漏

在android程序开发中,当一个对象已经不需要再使用了,本该被回收时,而另外一个正在使用的对象持有它的引用从而导致它不能被回收,这就导致本该被回收的对象不能被回收而停留在堆内存中,内存泄漏就产生了。比如资源内关闭、Handler、线程都可能出现。比如Handler或者线程在Activity退出时候还在不断处理消息,而线程或者Handler又持有Activity的引用,所以导致Activity无法被回收

2. Activity四种启动模式

Activity启动方式有四种,分别是:
standard
singleTop
singleTask
singleInstance
可以根据实际的需求为Activity设置对应的启动模式,从而可以避免创建大量重复的Activity等问题。
设置Activity的启动模式,只需要在AndroidManifest.xml里对应的<activity>标签设置Android:launchMode属性,例如:

<activity  

    android:name=".A1"  

    android:launchMode="standard" />  

standard

默认模式,可以不用写配置。在这个模式下,都会默认创建一个新的实例。因此,在这种模式下,可以有多个相同的实例,也允许多个相同Activity叠加。
例如:
若我有一个Activity名为A1, 上面有一个按钮可跳转到A1。那么如果我点击按钮,便会新启一个Activity A1叠在刚才的A1之上,再点击,又会再新启一个在它之上……
点back键会依照栈顺序依次退出。

singleTop
可以有多个实例,但是不允许多个相同Activity叠加。即,如果Activity在栈顶的时候,启动相同的Activity,不会创建新的实例,而会调用其onNewIntent方法。
例如:
若我有两个Activity名为B1,B2,两个Activity内容功能完全相同,都有两个按钮可以跳到B1或者B2,唯一不同的是B1为standard,B2为singleTop。
若我意图打开的顺序为B1->B2->B2,则实际打开的顺序为B1->B2(后一次意图打开B2,实际只调用了前一个的onNewIntent方法)
若我意图打开的顺序为B1->B2->B1->B2,则实际打开的顺序与意图的一致,为B1->B2->B1->B2。

singleTask
只有一个实例。在同一个应用程序中启动他的时候,若Activity不存在,则会在当前task创建一个新的实例,若存在,则会把task中在其之上的其它Activity destory掉并调用它的onNewIntent方法。
如果是在别的应用程序中启动它,则会新建一个task,并在该task中启动这个Activity,singleTask允许别的Activity与其在一个task中共存,也就是说,如果我在这个singleTask的实例中再打开新的Activity,这个新的Activity还是会在singleTask的实例的task中。
例如:
若我的应用程序中有三个Activity,C1,C2,C3,三个Activity可互相启动,其中C2为singleTask模式,那么,无论我在这个程序中如何点击启动,如:C1->C2->C3->C2->C3->C1-C2,C1,C3可能存在多个实例,但是C2只会存在一个,并且这三个Activity都在同一个task里面。

但是C1->C2->C3->C2->C3->C1-C2,这样的操作过程实际应该是如下这样的,因为singleTask会把task中在其之上的其它Activity destory掉。

操作:C1->C2 C1->C2->C3 C1->C2->C3->C2 C1->C2->C3->C2->C3->C1 C1->C2->C3->C2->C3->C1-C2

实际:C1->C2 C1->C2->C3 C1->C2 C1->C2->C3->C1 C1->C2

若是别的应用程序打开C2,则会新启一个task。

如别的应用Other中有一个activity,taskId为200,从它打开C2,则C2的taskIdI不会为200,例如C2的taskId为201,那么再从C2打开C1、C3,则C2、C3的taskId仍为201。

注意:如果此时你点击home,然后再打开Other,发现这时显示的肯定会是Other应用中的内容,而不会是我们应用中的C1 C2 C3中的其中一个。

singleInstance
只有一个实例,并且这个实例独立运行在一个task中,这个task只有这个实例,不允许有别的Activity存在。
例如:
程序有三个ActivityD1,D2,D3,三个Activity可互相启动,其中D2为singleInstance模式。那么程序从D1开始运行,假设D1的taskId为200,那么从D1启动D2时,D2会新启动一个task,即D2与D1不在一个task中运行。假设D2的taskId为201,再从D2启动D3时,D3的taskId为200,也就是说它被压到了D1启动的任务栈中。
若是在别的应用程序打开D2,假设Other的taskId为200,打开D2,D2会新建一个task运行,假设它的taskId为201,那么如果这时再从D2启动D1或者D3,则又会再创建一个task,因此,若操作步骤为other->D2->D1,这过程就涉及到了3个task了。

3. Handler消息机制

http://www.cnblogs.com/JczmDeveloper/p/4403129.html 
handler我理解为电话,子线程要通知主线程修改UI,或是线程之间传递信息可以通过handler来传递

4. java异常机制

Throwable
Throwable类是所有异常或错误的超类,它有两个子类:Error和Exception,分别表示错误和异常。其中异常Exception分为运行时异常(RuntimeException)和非运行时异常,也称之为不检查异常(Unchecked Exception)和检查异常(Checked Exception)。

Error
一般是指java虚拟机相关的问题,如系统崩溃、虚拟机出错误、动态链接失败等,这种错误无法恢复或不可能捕获,将导致应用程序中断,通常应用程序无法处理这些错误,因此应用程序不应该捕获Error对象,也无须在其throws子句中声明该方法抛出任何Error或其子类。

可查异常和不可查异常
通常,Java的异常(包括Exception和Error)分为可查的异常(checked exceptions)和不可查的异常(unchecked exceptions)。
可查异常(编译器要求必须处置的异常):正确的程序在运行中,很容易出现的、情理可容的异常状况。可查异常虽然是异常状况,但在一定程度上它的发生是可以预计的,而且一旦发生这种异常状况,就必须采取某种方式进行处理。

除了RuntimeException及其子类以外,其他的Exception类及其子类都属于可查异常。这种异常的特点是Java编译器会检查它,也就是说,当程序中可能出现这类异常,要么用try-catch语句捕获它,要么用throws子句声明抛出它,否则编译不会通过。

不可查异常(编译器不要求强制处置的异常):包括运行时异常(RuntimeException与其子类)和错误(Error)。

如果使用throw在方法体中抛出可查异常,则需要在方法头部声明方法可能抛出的异常类型。程序会在throw语句后立即终止,它后面的语句执行不到,然后在包含它的所有try块中(可能在上层调用函数中)从里向外寻找含有与其匹配的catch子句的try块。

运行时异常和非运行时异常

(1)运行时异常都是RuntimeException类及其子类异常,如NullPointerException、IndexOutOfBoundsException等,这些异常是不检查异常,程序中可以选择捕获处理,也可以不处理。这些异常一般是由程序逻辑错误引起的,程序应该从逻辑角度尽可能避免这类异常的发生。

当出现RuntimeException的时候,我们可以不处理。当出现这样的异常时,总是由虚拟机接管。比如:我们从来没有人去处理过NullPointerException异常,它就是运行时异常,并且这种异常还是最常见的异常之一。

出现运行时异常后,如果没有捕获处理这个异常(即没有catch),系统会把异常一直往上层抛,一直到最上层,如果是多线程就由Thread.run()抛出,如果是单线程就被main()抛出。抛出之后,如果是线程,这个线程也就退出了。如果是主程序抛出的异常,那么这整个程序也就退出了。运行时异常是Exception的子类,也有一般异常的特点,是可以被catch块处理的。只不过往往我们不对他处理罢了。也就是说,你如果不对运行时异常进行处理,那么出现运行时异常之后,要么是线程中止,要么是主程序终止。

如果不想终止,则必须捕获所有的运行时异常,决不让这个处理线程退出。队列里面出现异常数据了,正常的处理应该是把异常数据舍弃,然后记录日志。不应该由于异常数据而影响下面对正常数据的处理。

(2)非运行时异常是RuntimeException以外的异常,类型上都属于Exception类及其子类。如IOException、SQLException等以及用户自定义的Exception异常。对于这种异常,JAVA编译器强制要求我们必需对出现的这些异常进行catch并处理,否则程序就不能编译通过。所以,面对这种异常不管我们是否愿意,只能自己去写一大堆catch块去处理可能的异常。

5. 简述Activity的生命周期

1、Activity可见并获得焦点

当Activity启动的时候,首先调用onCreate()、onStart(),onResume()方法,此时Activity对用户来说,是可见的状态

2、Activity可见但没获得焦点

当Activity从可见状态变为被Dialog遮挡的状态的时候,会调用onPause()方法,此时的Activity对用户可见,但是不能获得焦点

3、Activity不可见

当Activity从可见状态变为被其他的Activity完全覆盖或者是点击Home进入后台的时候,会依次调用onPause()//onStop()方法,如果在这个期间,系统内存不足,导致Activity被回收的话,还会调用onDestory()方法

4、Activity可见、没获得焦点状态 –> Activity可见、获得焦点状态

当Activity从被Dialog遮挡的状态恢复的时候,会调用onResume()方法,从而恢复可以点击的状态

5、Activity不可见、没获得焦点状态 –> Activity可见、获得焦点状态

当Activity从被其他Activity遮挡或者是进入后台状态后恢复,若没有被系统回收,会依次调用onRestart()、onStart()、onResume()方法,恢复到可以与用户进行交互的状态

6、Activity不可见状态–> Activity被回收 –> Activity可见、获得焦点状态

当Activity从被其他Activity遮挡或者进入后台,而且被系统回收的时候,此时恢复Activity,相当于重新打开一个Activity,既调用onCreate()、onStart()//onResume()方法,从而恢复到可与用户进行交互的状态(期间可调用onRestoreInstanceState(),进行界面恢复)。

7、Activity可见、获得焦点状态 –> Activity可见、没获得焦点状态 或 不可见状态

在onPause()方法执行后,系统会停止一些消耗CPU 的操作,因为这个时候程序的优先级降低,很有可能被系统收回,所以我们应该在这个方法里做数据持久化处理。保存的数据可在onResume() 里读出来,帮用户恢复到之前的状态。

8、Activity结束

在onDestroy()执行后,activity生命周期就结束了,可用 isFinishing()方法来判断。如果此时有 Progress Dialog显示,我们应该在onDestroy()里cancel 掉,否则线程结束的时候,调用Dialog 的cancel 方法会抛异常。

6. 请简单说下对广播接收者有哪些了解

广播接收者(BroadcastReceiver)用于接收广播Intent,广播Intent的发送是通过调用Context.sendBroadcast()、Context.sendOrderedBroadcast()来实现的。通常一个广播Intent可以被订阅了此Intent的多个广播接收者所接收,这个特性跟JMS中的Topic消息接收者类似。要实现一个广播接收者方法如下:
第一步:继承BroadcastReceiver,并重写onReceive()方法。

public class IncomingSMSReceiver extends BroadcastReceiver {

     @Override public void onReceive(Context context, Intent intent) {

     }

 }

第二步:订阅指定的广播Intent,订阅方法有两种:

第一种:使用代码进行订阅

IntentFilter filter = new IntentFilter("android.provider.Telephony.SMS_RECEIVED");

IncomingSMSReceiver receiver = new IncomingSMSReceiver();

registerReceiver(receiver, filter);

第二种:在AndroidManifest.xml文件中的节点里进行订阅:

 <receiver android:name=".IncomingSMSReceiver">

      <intent-filter>    

     </action></intent-filter>

 </receiver>

广播类型
广播分为两种不同的类型:“普通广播(Normal broadcasts)”和“有序广播(Ordered broadcasts)”。普通广播是完全异步的,可以在同一时刻(逻辑上)被所有接收者接收到,消息传递的效率比较高,但缺点是:接收者不能将处理结果传递给下一个接收者,并且无法终止广播Intent的传播;然而有序广播是按照接收者声明的优先级别,被接收者依次接收广播。如:A的级别高于B,B的级别高于C,那么,广播先传给A,再传给B,最后传给C 。优先级别声明在intent-filter元素的android:priority属性中,数越大优先级别越高,取值范围:-1000到1000,优先级别也可以调用IntentFilter对象的setPriority()进行设置 。有序广播的接收者可以终止广播Intent的传播,广播Intent的传播一旦终止,后面的接收者就无法接收到广播。另外,有序广播的接收者可以将数据传递给下一个接收者,如:A得到广播后,可以往它的结果对象中存入数据,当广播传给B时,B可以从A的结果对象集合中得到A存入的数据。

Context.sendBroadcast() 发送的是普通广播,所有订阅者都有机会获得并进行处理。

Context.sendOrderedBroadcast() 发送的是有序广播,系统会根据接收者声明的优先级别按顺序逐个执行接收者,前面的接收者有权终止广播

BroadcastReceiver.abortBroadcast(),如果广播被前面的接收者终止,后面的接收者就再也无法获取到广播。对于有序广播,前面的接收者可以将数据通过setResultExtras(Bundle)方法存放进结果对象,然后传给下一个接收者,下一个接收者通过代码:Bundle bundle = getResultExtras(true))可以获取上一个接收者存入在结果对象中的数据。

系统收到短信,发出的广播属于有序广播。如果想阻止用户收到短信,可以通过设置优先级,让你们自定义的接收者先获取到广播,然后终止广播,这样用户就接收不到短信了。

广播接收者的响应

在Android中,每次广播消息到来时都会创建BroadcastReceiver实例并执行onReceive() 方法,onReceive() 方法执行完后,BroadcastReceiver 的实例就会被销毁。当onReceive() 方法在10秒内没有执行完毕,Android会认为该程序无响应。所以在BroadcastReceiver里不能做一些比较耗时的操作,否侧会弹出ANR(Application No Response)的对话框。如果需要完成一项比较耗时的工作,应该通过发送Intent给Service,由Service来完成。这里不能使用子线程来解决,因为BroadcastReceiver的生命周期很短,子线程可能还没有结束BroadcastReceiver就先结束了。BroadcastReceiver一旦结束,此时BroadcastReceiver的所在进程很容易在系统需要内存时被优先杀死,因为它属于空进程(没有任何活动组件的进程)。如果它的宿主进程被杀死,那么正在工作的子线程也会被杀死。所以采用子线程来解决是不可靠的。

public class IncomingSMSReceiver extends BroadcastReceiver {

     @Override

    public void onReceive(Context context, Intent intent) {

             //发送Intent启动服务,由服务来完成比较耗时的操作

            Intent service = new Intent(context, XxxService.class);

             context.startService(service);

     }

 }

常用广播Intent

除了短信到来广播Intent,Android还有很多广播Intent,如:开机启动、电池电量变化、时间已经改变等广播Intent。

接收开机启动广播Intent,在AndroidManifest.xml文件中的节点里订阅此Intent:

<receiver android:name=".IncomingSMSReceiver">

     <intent-filter>

     </action></intent-filter>

 </receiver>

并且要进行权限声明:

<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"></uses-permission>

接收电池电量变化广播Intent ,在AndroidManifest.xml文件中的节点里订阅此Intent:

<receiver android:name=".IncomingSMSReceiver">

     <intent-filter>

     </action></intent-filter>

 </receiver>

广播接收者的生命周期及使用注意事项

1、广播接收者的生命周期是非常短暂的,在接收到广播的时候创建,onReceive()方法结束之后销毁

2、广播接收者中不要做一些耗时的工作,否则会弹出Application No Response错误对话框,耗时的较长的工作最好放在服务中完成

3、最好也不要在广播接收者中创建子线程做耗时的工作,因为广播接收者被销毁后进程就成为了空进程,很容易被系统杀掉

7. view如何刷新?简述什么是双缓冲

android中实现view的刷新有两个方法,一个是invalidate(),另一个是postInvalidate(),其中前者是在UI线程自身中使用,而后者在非UI线程中使用。也可以使用Handler的sendMessage方法

出现屏幕闪烁是图形编程的一个常见问题。当进行复杂的绘制操作时会导致呈现的图像闪烁或具有其他不可接受的外观。双缓冲的使用解决这些问题。双缓冲使用内存缓冲区来解决由多重绘制操作造成的闪烁问题。当使用双缓冲时,首先在内存缓冲区里完成所有绘制操作,而不是在屏幕上直接进行绘图。当所有绘制操作完成后,把内存缓冲区完成的图像直接复制到屏幕。因为在屏幕上只执行一个图形操作,所以消除了由复杂绘制操作造成的图像闪烁问题。

在android中实现双缓冲,可以使用一个后台画布backcanvas,先把所有绘制操作都在这上面进行。等图画好了,然后在把backcanvas拷贝到

与屏幕关联的canvas上去。

8. NDK是什么

NDK 是一些列工具的集合,NDK 提供了一系列的工具,帮助开发者迅速的开发 C/C++的动态库,并能自动将so 和java 应用打成apk 包。

NDK 集成了交叉编译器,并提供了相应的mk 文件和隔离 cpu、平台等的差异,开发人员只需简单的修改mk 文件就可以创建出 so。

NDK可以为我们生成了C/C++的动态链接库,JNI是java和C/C++沟通的接口,两者与android没有半毛钱关系,只因为安卓是java程序语言开发,然后通过JNI又能与C/C++沟通,所以我们可以使用NDK+JNI来实现“Java+C”的开发方式。

9. 如何将SQLite数据库(xxx.db文件)与apk文件一起发布

可以将xxx.db文件复制到Eclipse Android工程中的res raw目录中。所有在res raw目录中的文件不会被压缩,这样可以直接提取该目录中的文件。可以将xxx.db文件复制到res raw目录中。

10. java中如何引用本地语言

可以用JNI(java native interface java 本地接口)接口

10. ANR是什么?怎样避免和解决ANR

ANR->Application Not Responding

也就是在规定的时间内,没有响应。

三种类型:

1). KeyDispatchTimeout(5 seconds) --主要类型按键或触摸事件在特定时间内无响应

2). BroadcastTimeout(10 seconds) --BroadcastReceiver在特定时间内无法处理完成

3). ServiceTimeout(20 seconds) --小概率类型 Service在特定的时间内无法处理完成

为什么会超时:事件没有机会处理& 事件处理超时

怎么避免ANR

ANR的关键

是处理超时,所以应该避免在UI线程,BroadcastReceiver 还有service主线程中,处理复杂的逻辑和计算

而交给work thread操作。

1)避免在activity里面做耗时操作,oncreate & onresume

2)避免在onReceiver里面做过多操作

3)避免在Intent Receiver里启动一个Activity,因为它会创建一个新的画面,并从当前用户正在运行的程序上抢夺焦点。

4)尽量使用handler来处理UI thread & workthread的交互。

11. Android屏幕适配

屏幕适配的方式:xxxdpi,wrap_content,match_parent. 获取屏幕大小,做处理。

dp来适配屏幕,sp来确定字体大小

drawable-xxdpi, values-1280*1920等 这些就是资源的适配。

wrap_content,match_parent, 这些是view的自适应

weight,这是权重的适配。

12. activity怎么和service绑定

怎么在activity中启动自己对应的service:

1、activity能进行绑定得益于Serviece的接口。为了支持Service的绑定,实现onBind方法。

2、Service和Activity的连接可以用ServiceConnection来实现。需要实现一个新的ServiceConnection,重现onServiceConnected和OnServiceDisconnected方法,一旦连接建立,就能得到Service实例的引用。

3、执行绑定,调用bindService方法,传入一个选择了要绑定的Service的Intent(显示或隐式)和一个你实现了的ServiceConnection的实例

13. 什么是service,service生命周期,启动方式

 

14. Intent传递数据时,可以传递哪些类型数据

intent间传送数据一般有两种常用的方法: 1、extra 2、data。
extra可以用Intent.putExtra放入数据。新启动的Activity可用Intent.getExtras取出Bundle,然后用Bundles.getLong,getInt,getBoolean,getString等函数来取放进去的值。
Data则是传输url。url可以是指我们熟悉的http,ftp等网络地址,也可以指content来指向ContentProvider提供的资源。Intent.setData可以放入数据,Intent.getData可以取出数据。

15. 说一说activity,intent,service是什么关系

一个Activity通常是一个单独的屏幕,每一个Activity都被实现为一个单独的类,这些类都是从Activity基类中继承而来的。Activity类会显示由视图控件组成的用户接口,并对视图控件的事件做出响应。
Intent的调用是用来进行屏幕之间的切换。Intent描述应用想要做什么。Intent数据结构中两个最重要的部分是动作和动作对应的数据,一个动作对应一个动作数据。
Service是运行在后台的代码,不能与用户交互,可以运行在自己的进程里,也可以运行在其他应用程序进程的上下文里。需要一个Activity或者其他Context对象来调用。
Activity跳转Activity,Activity启动Service,Service打开Activity都需要Intent表明意图,以及传递参数,Intent是这些组件间信号传递的承载着

16. 描述一下BroadcastReceiver

Broadcast Receiver用于接收并处理广播通知(broadcast announcements)。多数的广播是系统发起的,如地域变换、电量不足、来电短信等。程序也可以播放一个广播。程序可以有任意数量的broadcast receivers来响应它觉得重要的通知。Broadcast receiver可以通过多种方式通知用户: 启动activity、使用NotificationManager、开启背景灯、振动设备、播放声音等,最典型的是在状态栏显示一个图标,这样用户就可以点它打开看通知内容。通常我们的某个应用或系统本身在某些事件(电池电量不足、来电短信)来临时会广播一个Intent出去,我们利用注册一个broadcast
receiver来监听这些Intent并获取Intent中的数据。

17. 请介绍下ContentProvider是如何共享数据的

一个程序可以通过实现一个Content provider的抽象接口将自己的数据完全暴露出去,而且Content provider是以类似数据库中的表的方式将自己的数据暴露。Content provider存储和检索数据,通过它可以让所有的应用程序访问到,这也是应用程序之间唯一共享数据的方法。
要想使应用程序的数据公开化,可通过2种方法:创建一个数据自己的Content Provider或者将你的数据添加到一个已经存在的Content Provider中,前提是有相同数据类型并且有写入Content Provider的权限,Android提供了Content Resolverr,外界的程序可以通过Content Resolver接口访问Content Provider提供的数据

18. 请介绍下android数据存储方式

1、使用Shared Preferences存储数据,用来存储key-value,pairs格式的数据,它是一个轻量级的键值存储机制,只可以存储基本数据类型。
2、使用文件存储数据,通过FileInputStream和FileOutputStream对文件进行操作。在Android中,文件是一个应用程序私有的,一个应用程序无法读写其他应用程序的文件。
3、使用SQLite数据库存储数据,Android提供的一个标准数据库,支持SQL语句。
4、使用Content Provider存储数据,是所有应用程序之间数据存储和检索的一个桥梁,它的作用就是使得各个应用程序之间实现数据共享。它是一个特殊的存储数据的类型,它提供了一套标准的接口用来获取数据,操作数据。系统也提供了音频、视频、图像和个人信息等几个常用的Content Provider。如果你想公开自己的私有数据,可以创建自己的Content Provider类,或者当你对这些数据拥有控制写入的权限时,将这些数据添加到Content Provider中实现共享。外部访问通过Content Resolver去访问并操作这些被暴露的数据。
5、使用网络存储数据

19. UI中padding和margin有什么区别

Padding是控件的内容相对控件的边缘的边距,而Margin是控件边缘相对于其他控件的边距

20. AsyncTask使用在那些场景?他的缺陷是什么?如何解决?

AsyncTask 运用的场景就是我们需要进行一些耗时的操作,耗时操作完成后更新主线程,或者在操作过程中对主线程的UI进行更新。
缺陷:AsyncTask中维护着一个长度为128的线程池,同时可以执行5个工作线程,还有一个缓冲队列,当线程池中已有128个线程,缓冲队列已满时,如果此时向线程提交任务,将会抛出RejectedExecutionException。
解决:由一个控制线程来处理AsyncTask的调用判断线程池是否满了,如果满了则线程睡眠否则请求AsyncTask继续处理。

21. 启动一个程序,可以从桌面点击图标进入,也可以从另一个程序中跳转过去,二者有什么区别?

是因为启动程序(主界面也是一个app),发现了在这个程序中存在一个设置为<category android:name="android.intent.category.LAUNCHER" />的activity,
所以这个launcher会把icon提出来,放在主界面上。当用户点击icon的时候,发出一个Intent:
Intent intent = mActivity.getPackageManager().getLaunchIntentForPackage(packageName);
mActivity.startActivity(intent);
跳过去可以跳到任意允许的页面,如一个程序可以下载,那么真正下载的页面可能不是首页(也有可能是首页),这时还是构造一个Intent,startActivity
这个intent中的action可能有多种view,download都有可能。系统会根据第三方程序向系统注册的功能,为你的Intent选择可以打开的程序或者页面。所以唯一的一点
不同的是从icon的点击启动的intent的action是相对单一的,从程序中跳转或者启动可能样式更多一些。本质是相同的。

22. Android 中的动画有哪几类,它们的特点和区别是什么

(1)视图动画,或者说补间动画。只是视觉上的一个效果,实际view属性没有变化,性能好,但是支持方式少。
(2)属性动画,通过变化属性来达到动画的效果,性能略差,支持点击等事件。android 3.0
(3)帧动画,通过drawable一帧帧画出来。
(4)Gif动画,原理同上,canvas画出来。

23. 如果后台的Activity由于某原因被系统回收了,如何在被系统回收之前保存当前状态?

重写onSaveInstanceState()方法,在此方法中保存需要保存的数据,该方法将会在activity被回收之前调用。通过重写onRestoreInstanceState()方法可以从中提取保存好的数据

24. 如何将一个Activity设置成窗口的样式?

<activity>中配置:android :theme=“@android:style/Theme.Dialog"

25. 如何打开res aw目录中的数据库文件?

在Android中不能直接打开res aw目录中的数据库文件,而需要在程序第一次启动时将该文件复制到手机内存或SD卡的某个目录中,然后再打开该数据库文件。
复制的基本方法是使用getResources().openRawResource方法获得res aw目录中资源的 InputStream对象,然后将该InputStream对象中的数据写入其他的目录中相应文件中。在Android SDK中可以使用SQLiteDatabase.openOrCreateDatabase方法来打开任意目录中的SQLite数据库文件。

26. Android中View,SurfaceView和GLSurfaceView绘图的区别

http://blog.csdn.net/doom20082004/article/details/53860153

27. Service的生命周期,两种启动方法,有什么区别

Service有两种使用方法:
1>以调用Context.startService()启动,而以调用Context.stopService()结束
2>以调用Context.bindService()方法建立,以调用Context.unbindService()关闭
service重要的生命周期方法
当用户调用startService ()或bindService()时,Service第一次被实例化的时候系统会调用,整个生命周期只调用1次这个方法,通常用于初始化设置。注意:多次调用startService()或bindService()方法不会多次触发onCreate()方法
通过startService()方法启动的服务
初始化结束后系统会调用该方法,用于处理传递给startService()的Intent对象。如音乐服务会打开Intent 来探明将要播放哪首音乐,并开始播放。注意:多次调用startService()方法会多次触发onStart()方法

void onStart(Intent intent)
通过bindService ()方法启动的服务

初始化结束后系统会调用该方法,用来绑定传递给bindService 的Intent 的对象。注意:多次调用bindService()时,如果该服务已启动则不会再触发此方法
IBinder onBind(Intent intent)

28. ContentProvider使用方法

为存储和获取数据提供统一的接口。可以在不同的应用程序之间共享数据。android已经为常见的一些数据提供了默认的ContentProvider,比如联系人、短信、图片信息、通话记录等等;
ContentProvider使用表的形式来组织数据,无论数据的来源是什么,ContentProvider都会认为是一种表,然后把数据组织成表格;
提供的方法:增删改查获取回调;
每个ContentProvider都有一个公共的URI,这个URI用于表示这个ContentProvider所提供的数据。Android所提供的ContentProvider都存放在android.provider包当中。

29. JSON 和 XML 优缺点的比较

(1) 在可读性方面,JSON和XML的数据可读性基本相同。JSON和XML的可读性可谓不相上下,一边是建议的语法,一边是规范的标签形式,很难分出胜负。
(2) 在可扩展性方面,XML天生有很好的扩展性,JSON当然也有,没有什么是XML能扩展,JSON不能的。
(3) 在编码难度方面,XML有丰富的编码工具,比如Dom4j、JDom等,JSON也有json.org提供的工具,但是JSON的编码明显比XML容易许多,即使不借助工具也能写出JSON的代码,可是要写好XML就不太容易了。
(4) 在解码难度方面,XML的解析得考虑子节点父节点,让人头昏眼花,而JSON的解析难度几乎为0。这一点XML输的真是没话说。
(5) 在流行度方面,XML已经被业界广泛的使用,而JSON才刚刚开始,但是在Ajax这个特定的领域,未来的发展一定是XML让位于JSON。到时Ajax应该变成Ajaj(Asynchronous JavaScript and JSON)了。
(6) JSON和XML同样拥有丰富的解析手段。
(7) JSON相对于XML来讲,数据的体积小。
(8) JSON与javascript的交互更加方便。
(9) JSON对数据的描述性比XML较差。
(10) JSON的速度要远远快于XML。

  1. 怎样退出App
    在onCreate() 中将Activity 实例 放到 线性容器中, 退出时不停地((Activity)list.gert(i)).finsh();
    Android经典完美退出方法,使用单例模式创建一个Activity管理对象,该对象中有一个Activity容器(具体实现自己处理,使用LinkedList等)专门负责存储新开启的每一个Activity,并且容易理解、易于操作,非常不错!
    AppUtils类(储存每一个Activity,并实现关闭所有Activity的操作)

31. Android内存优化

使用SparseArray,SparseBooleanArray代替HaspMap:HaspMap是内存低效的,因为每一个Map就需要一个Entry,每个元素将多占8byte内存(多了next和hash两个成员变量)
使用IntentService代替Service:Service默认在UI线程中执行,而IntentService的onHandleIntent()方法在后台执行。Service如果没有手动Stop会一直存在,而IntentService在执行完后会自动退出
尽量避免使用Enum:因为枚举相对于静态常量来说需要2倍甚至更多的内存
使用混淆器移除不必要的代码
不要因为一两个特性使用大体积库
需要频繁修改的字符串使用StringBuilder和StringBuffer代替
对于常量请使用static final:减少类生成时,初始化方法调用时对常量的存储
对象在不用的时候最好设置为null

32. 什么情况下会导致内存泄漏

(1)静态集合类引起内存泄漏:主要是HashMap,Vector等,如果这些静态集合类位set null会一直持有这些对象
(2)Observer未移除监听:当我们是有监听器时,往往是addxxxListener,却总是忘记在不需要的时候removexxxListener这样就容易导致内存泄漏。广播未调用unregisterrecevier方法
(3)各种数据连接未关闭:ContentProvider、IO、socket、Cursor等
(4)内部类:Java中的内部类会持有宿主类的this

33. 广播的注册方式

静态注册:在AndroidManifest.xml中注册,Android不能自动销毁广播接收器,即程序关闭时,还会继续接收广播,消耗资源大
动态注册:在代码中调用registerReceiver方法注册,需要手动调用unregisterReceiver方法注销,否则将会内存泄漏

34. 如何防止Service被杀死

(1)在startCommand方法中修改flags的值为START_STICKY或START_READELIVER_INTENT
(2)在onDestory方法中重启Service
(3)创建一个广播,在onReceiver中启动Service

35. Service有两种启动方式,启动方式不同,生命周期也不同

- startService:onCreate()-onStartCommand()-onDestory() 
- bindService:onCreate()-onBind()-onUnBind()-onDestory()

36. TCP与UDP的区别

TCP:TCP是基于连接的协议,也就是说,在正式首发数据之前,必须和对方建立可靠的连接\
UDP:UDP是面向非连接的协议,它不予对方建立连接,而是直接把数据包发送过去\
差别:

  • TCP面向连接,传输可靠,应用于传输大量数据,数度慢
    UDP面向非连接,传输不可靠,应用于传输少量数据,速度快

37. StringBuffer与StringBuilder的区别

StringBuilder:字符串变量,线程非安全的,适用于单线程操作字符串缓冲区下操作大量字符串,执行速度大于StringBuffer
StringBuffer:字符串变量,线程安全的,适用于多线程操作字符串缓冲区下操作大量字符串,执行速度慢于StringBuilfer

38. 什么是Context

Context字面意思为上下文,也可以叫做场景,是用户与操作系统交互的一个过程,比如打电话,场景包括显示的界面,以及隐藏在背后的数据

39. 有没有用过自定义View?

(1)有用过,一般指定View都需要进行这几个步骤,首先可以自定义一些自己的属性,在res/values/attrs.xml里面定义,然后在layout中使用,在View中通过context.obtainStyledAttributes(attrs,R.styleable.自定义属性的名字)进行获取。
(2)然后在测量onMeasure,一般通过他的三个模式(EXACTLY,AT_MODE,,UNSPECIFIED)进行测量,调用setMeasuredDimension进行传入设置的值。
接着如果是ViewGroupt 的话我们还需要设置下子View的位置,一般是通过requestLayout去触发onLayout的方法的。
(3)最后在onDraw里面通过Canvas的一些方法进行绘制。
(4)如果需要进行触摸事件的话,一般需要有实现onTouchEvent事件,注意,如果需要多点触摸,需要实现ACTION_POINTER_DOWN和ACTION_POINTER_UP进行处理。
http://blog.csdn.net/lmj623565791/article/details/24252901/

40. layout_weight怎么理解?

layout_weight的尺寸分配一般是先满足设置尺寸的分配然后剩下的尺寸在进行比例分配的。如果一个view需要设置1:2的比例显示,可以在LinearLayout中设置weightSum进行设置总的比例,然后在设置子View的比例。

41. layout_gravity和gravity的区别?

layout_gravity是根据父布局设置位置的,而gravity是根据自身内容设置位置。

42. 只能在UI线程里面更新界面吗?

不一定,之所以子线程不能更新界面,是因为Android在线程的方法里面采用checkThread进行判断是否是主线程,而这个方法是在ViewRootImpl中的,这个类是在onResume里面才生成的,因此,如果这个时候子线程在onCreate方法里面生成更新UI,而且没有做阻塞,就是耗时多的操作,还是可以更新UI的。

43. Android子线程更新UI的方式有几种?

一般情况下,我们都采用Handler的方式进行更新UI,当然,代码层的实现有不同的方法,比如可以使用Handler的post方法进行更新UI,或者用Handler的sendMessage方法进行更新UI,或者通过View的post方法进行更新,还有一个是runOnUIThread也是可以进行更新的。但这些本质上还是通过Handler进行子线程的更新。

44. 你知道HandlerThread是什么吗?

HandlerThread是Android官方给我们提供好的一套子线程的Handler,也就是异步处理机制,它是为了避免线程切换导致空指针异常的错误。

45. Activity的缓存方法是怎么样的?

可以在onSaveInstanceState中将要保存的数据保存起来,可以通过Bundle进行临时保存,然后在onCreate中的Bundle中取出来进行恢复,这样就可以避免Activity被销毁的时候数据的清空。因为onSaveInstanceState在Activity销毁之前必然会调用,所以可以在这里做缓存操作。记住,这个是系统未经你同意的时候就销毁的时候才会的。

46. 为什么在Service中创建子线程而不是Activity中?

因为假如在Activity中创建子线程的话,当Activity销毁的时候,这个时候重新再调用该Activity就会重新走新的生命周期,这个时候就无法再重新获取到刚才的子线程,而且如果在一个Activity中创建子线程,另一个Activity也无法操作该子线程,但是Service就不一样,所有的Activity都可以和Service关联,即使是Activity被销毁了,只要再重新建立联系就好了,所以,一般后台任务都是通过Service去控制的。

47. SQLite的基础操作

首先需要创建库和表,并且需要继承SQLiteOpenHelper类,然后在这个表里面实现增删改查的方法,可以用Android官方封装好的方法进行,也可以调用SQL语句进行操作。调用SQLiteDatabase中的execSQL方法操作SQL语句。

48. 如何判断应用被强制杀死?

可以在Application中定义一个static常量,赋值为-1,然后在欢迎页面修改值为0,如果被强杀,Application被重新初始化,这个时候如果父Activity判断该常量是多少。

49. Asset和res目录的区别?

Asset不会在R文件里面生成一个ID,所以它不能直接用R文件来调用,这就说明要读取Asset目录下的文件需要指定文件的目录,可以通过AssetManager类来访问。res会自动在R文件里面生成id,直接可以用R.的方式进行访问资源。

50. Android怎么优化启动速度?

因为Android启动应用程序一般分为两种,一种是冷启动,就是要启动的应用程序没有后台进程的启动,这个时候需要重新分配一个进程给他,所以这个时候会先初始化Application类,再创建和初始化MainAcitvity 类,最后显示到界面上,还有一种是热启动,就是后台还有该应用的进程,比如说按下的home键或者返回键,虽然表面上退出了,但是在任务栈里面仍然还存在的,这个时候就不需要再初始化Application类了,只要重新初始化MainActivity了。因为大多数应用的启动都是冷启动(用户习惯将应用程序在任务栈中删除),所以这个时候可以采取这几个步骤,比如尽量不在Application的构造器,attachBaseContext方法和onCreaete方法中做过多的耗时操作,将一些数据预取放在异步线程中,可以采Callback的方式。优化MainActivity,尽量不要在MainActivity的onCreate,onStart和onResume等方法里面做过多的耗时操作。

51. Android怎么加快Activity的显示速度?

首先因为Activiy的显示是在这几个生命周期之间的,onCreate,onStart,和onResume,这个时候我们需要将我们需要初始化的数据分类,比如说我们将一些只需要初始化的一次的数据放到onCreate中,尽量不要在onCreate中做耗时的操作,然后将需要加载比较长时间的数据放到onResume中,可以利用handler的机制进行更新UI,或者放到AsyncTask逐个显示,然后可以设置一些动画进行显示,如果这个时候有许多数据都是一次显示的, 那么可以在onCreate里面进行标记,并且在onResume里面判断是否需要初始化,初始化完成以后就立刻false掉,这样就可以避免多次初始化了,也可以提升Activity的显示速度

52. 横竖屏切换时候activity的生命周期?

(1)不设置Activity的android:configChanges时,切屏会重新调用各个生命周期,切横屏时会执行一次,切竖屏时会执行两次。
(2)设置Activity的android:configChanges="orientation"时,切屏还是会重新调用各个生命周期,切横、竖屏时只会执行一次 。
(3)设置Activity的android:configChanges="orientation|keyboardHidden"时,切屏不会重新调用各个生命周期,只会执行onConfigurationChanged方法 。

53. 能说下Android应用的入口点吗?

真正的Android入口点是application的main,可以没有Activity但是必须有Application

54. Android引入广播机制的用意?

从MVC的角度考虑(应用程序内) 其实回答这个问题的时候还可以这样问,android为什么要有那4大组件,现在的移动开发模型基本上也是照搬的web那一套MVC架构,只不过是改了点嫁妆而已。android的四大组件本质上就是为了实现移动或者说嵌入式设备上的MVC架构,它们之间有时候是一种相互依存的关系,有时候又是一种补充关系,引入广播机制可以方便几大组件的信息和数据交互。   b:程序间互通消息(例如在自己的应用程序内监听系统来电)   c:效率上(参考UDP的广播协议在局域网的方便性)   d:设计模式上(反转控制的一种应用,类似监听者模式)

55. 成员方法和构造方法有什么区别?

成员方法必须有返回类型,即使是没有返回,也要写上void;构造函数没有返回类型,而且和类名一样。

56. 什么是栈?

栈是一种先进后出的线性表,只要符合先进后出的原则的线性表都是栈。至于采用的存储方式(实现方式)是顺序存储(顺序栈)还是链式存储(链式栈)是没有关系的。堆则是二叉树的一种,有最大堆最小堆,排序算法中有常用的堆排序。

57. ListView如何优化?

http://blog.csdn.net/s003603u/article/details/47261393

58. 计算机网络的七层模型?

(1)应用层 (Application)
网络服务与最终用户的一个接口。
协议
HTTP FTP TFTP SMTP SNMP DNS
(2)表示层(Presentation Layer)
数据的表示、安全、压缩。(在五层模型里面已经合并到了应用层)格式有,JPEG、ASCll、DECOIC、加密格式等
(3)会话层(Session Layer)
建立、管理、终止会话。(在五层模型里面已经合并到了应用层)对应主机进程,指本地主机与远程主机正在进行的会话
(4)传输层 (Transport)
定义传输数据的协议端口号,以及流控和差错效验。
(5)协议有
TCP UDP,数据包一旦离开网卡即进入网络传输层网络层 (Network):进行逻辑地址寻址,实现不同网络之间的路径选择。
协议有:ICMP IGMP IP(IPV4 IPV6) ARP RARP
(6)数据链路层 (Link)
建立逻辑连接、进行硬件地址寻址、差错校验等功能。(由底层网络定义协议)将比特组合成字节进而组合成帧,用MAC地址访问介质,错误发现但不能纠正。
(7)物理层(Physical Layer)
建立、维护、断开物理连接。(由底层网络定义协议)
TCP/IP 层级模型结构:
应用层之间的协议通过逐级调用传输层(Transport layer)、网络层(Network Layer)和物理数据链路层(Physical Data Link)而可以实现应用层的应用程序通信互联。

59. service生命周期?

这里要注意service有两种启动方式,startService()和bindService()

 

60. 如何理解Activity,View,Window三者之间的关系?

这个问题真的很不好回答。所以这里先来个算是比较恰当的比喻来形容下它们的关系吧。Activity像一个工匠(控制单元),Window像窗户(承载模型),View像窗花(显示视图)LayoutInflater像剪刀,Xml配置像窗花图纸。
1:Activity构造的时候会初始化一个Window,准确的说是PhoneWindow。
2:这个PhoneWindow有一个“ViewRoot”,这个“ViewRoot”是一个View或者说ViewGroup,是最初始的根视图。
3:“ViewRoot”通过addView方法来一个个的添加View。比如TextView,Button等
4:这些View的事件监听,是由WindowManagerService来接受消息,并且回调Activity函数。比如onClickListener,onKeyDown等。

posted @ 2019-05-31 19:26 故事爱人 阅读(...) 评论(...) 编辑 收藏