Android面试题整理(中)

1.如何将一个Activity设置成窗口的样式。

在AndroidManifest.xml中定义Activity的地方一句话android:theme="@android:style/Theme.Dialog"或android:theme="@android:style/Theme.Translucent"就变成半透明

2.如何退出Activity?如何安全退出已调用多个Activity的Application?

1、抛异常强制退出:

该方法通过抛异常,使程序ForceClose。

验证可以,但是,需要解决的问题是,如何使程序结束掉,而不弹出ForceClose的窗口。

2、记录打开的Activity:

每打开一个Activity,就记录下来。在需要退出时,关闭每一个Activity即可。

3、发送特定广播:

在需要结束应用时,发送一个特定的广播,每个Activity收到广播后,关闭即可。

4、递归退出

在打开新的Activity时使用startActivityForResult,然后自己加标志,在onActivityResult中处理,递归关闭。

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

onSaveInstanceState()

当你的程序中某一个ActivityA在运行时,主动或被动地运行另一个新的ActivityB,这个时候A会执行onSaveInstanceState()。B完成以后又会来找A,这个时候就有两种情况:一是A被回收,二是A没有被回收,被回收的A就要重新调用onCreate()方法,不同于直接启动的是这回onCreate()里是带上了参数savedInstanceState;而没被收回的就直接执行onResume(),跳过onCreate()了。

4.在android中,请简述jni的调用过程。

1)安装和下载Cygwin,下载AndroidNDK

2)在ndk项目中JNI接口的设计

3)使用C/C++实现本地方法

4)JNI生成动态链接库.so文件

5)将动态链接库复制到java工程,在java工程中调用,运行java工程即可

5.简述Android应用程序结构是哪些?

Android应用程序结构是:

LinuxKernel(Linux内核)、Libraries(系统运行库或者是c/c++核心库)、Application

Framework(开发框架包)、Applications(核心应用程序)

6.Service的生命周期

1.Service常用生命周期回调方法如下:

onCreate()该方法在服务被创建时调用,该方法只会被调用一次,无论调用多少次startService()或bindService()方法,

服务也只被创建一次。onDestroy()该方法在服务被终止时调用。

2.Context.startService()启动Service有关的生命周期方法

onStart()只有采用Context.startService()方法启动服务时才会回调该方法。该方法在服务开始运行时被调用。

多次调用startService()方法尽管不会多次创建服务,但onStart()方法会被多次调用。

3.Context.bindService()启动Service有关的生命周期方法

onBind()只有采用Context.bindService()方法启动服务时才会回调该方法。该方法在调用者与服务绑定时被调用,

当调用者与服务已经绑定,多次调用Context.bindService()方法并不会导致该方法被多次调用。

onUnbind()只有采用Context.bindService()方法启动服务时才会回调该方法。该方法在调用者与服务解除绑定时被调用。

备注:

1.采用startService()启动服务

Intentintent=newIntent(DemoActivity.this,DemoService.class);

startService(intent);

2.Context.bindService()启动

Intentintent=newIntent(DemoActivity.this,DemoService.class);

bindService(intent,conn,Context.BIND_AUTO_CREATE);

//unbindService(conn);//解除绑定

7.注册广播有几种方式,这些方式有何优缺点?请谈谈Android引入广播机制的用意。

Android广播机制(两种注册方法)

在android下,要想接受广播信息,那么这个广播接收器就得我们自己来实现了,我们可以继承BroadcastReceiver,就可以有一个广播接受器了。有个接受器还不够,我们还得重写BroadcastReceiver里面的onReceiver方法,当来广播的时候我们要干什么,这就要我们自己来实现,不过我们可以搞一个信息防火墙。具体的代码:

publicclassSmsBroadCastReceiverextendsBroadcastReceiver{

@Override

publicvoidonReceive(Contextcontext,Intentintent){

Bundlebundle=intent.getExtras();

Object[]object=(Object[])bundle.get("pdus");

SmsMessagesms[]=newSmsMessage[object.length];

sms[0]=SmsMessage.createFromPdu((byte[])object);

Toast.makeText(context,"来自"+sms.getDisplayOriginatingAddress()+"的消息是:"+sms.getDisplayMessageBody(),Toast.LENGTH_SHORT).show();

}

//终止广播,在这里我们可以稍微处理,根据用户输入的号码可以实现短信防火墙。

abortBroadcast();

}

}

当实现了广播接收器,还要设置广播接收器接收广播信息的类型,这里是信息:

android.provider.Telephony.SMS_RECEIVED

我们就可以把广播接收器注册到系统里面,可以让系统知道我们有个广播接收器。这里有两种,一种是代码动态注册:

//生成广播处理

smsBroadCastReceiver=newSmsBroadCastReceiver();

//实例化过滤器并设置要过滤的广播

IntentFilterintentFilter=

newIntentFilter("android.provider.Telephony.SMS_RECEIVED");

//注册广播

BroadCastReceiverActivity.this.registerReceiver(smsBroadCastReceiver,intentFilter)

一种是在AndroidManifest.xml中配置广播

package="spl.broadCastReceiver"

android:versionCode="1"

android:versionname="1.0">

android:label="@string/app_name">

两种注册类型的区别是:

1)第一种不是常驻型广播,也就是说广播跟随程序的生命周期。

2)第二种是常驻型,也就是说当应用程序关闭后,如果有信息广播来,程序也会被系统调用自动运行。

8.AIDL的全称是什么?如何工作?能处理哪些类型的数据?

AIDL的英文全称是AndroidInterfaceDefineLanguage

当A进程要去调用B进程中的service时,并实现通信,我们通常都是通过AIDL来操作

A工程:

首先我们在net.blogjava.mobile.aidlservice包中创建一个RemoteService.aidl文件,在里面我们自定义一个接口,含有方法get。ADT插件会在gen目录下自动生成一个RemoteService.java文件,该类中含有一个名为RemoteService.stub的内部类,该内部类中含有aidl文件接口的get方法。

说明一:aidl文件的位置不固定,可以任意

然后定义自己的MyService类,在MyService类中自定义一个内部类去继承RemoteService.stub这个内部类,实现get方法。在onBind方法中返回这个内部类的对象,系统会自动将这个对象封装成IBinder对象,传递给他的调用者。

其次需要在AndroidManifest.xml文件中配置MyService类,代码如下:

为什么要指定调用AIDL服务的ID,就是要告诉外界MyService这个类能够被别的进程访问,只要别的进程知道这个ID,正是有了这个ID,B工程才能找到A工程实现通信。

说明:AIDL并不需要权限

B工程:

首先我们要将A工程中生成的RemoteService.java文件拷贝到B工程中,在bindService方法中绑定aidl服务

绑定AIDL服务就是将RemoteService的ID作为intent的action参数。

说明:如果我们单独将RemoteService.aidl文件放在一个包里,那个在我们将gen目录下的该包拷贝到B工程中。如果我们将RemoteService.aidl文件和我们的其他类存放在一起,那么我们在B工程中就要建立相应的包,以保证RmoteService.java文件的报名正确,我们不能修改RemoteService.java文件

 bindService(newInten("net.blogjava.mobile.aidlservice.RemoteService"),serviceConnection,Context.BIND_AUTO_CREATE);

ServiceConnection的onServiceConnected(ComponentNamename,IBinderservice)方法中的service参数就是A工程中MyService类中继承了RemoteService.stub类的内部类的对象。

9.请解释下在单线程模型中Message、Handler、MessageQueue、Looper之间的关系。

Handler简介:

一个Handler允许你发送和处理Message和Runable对象,这些对象和一个线程的MessageQueue相关联。每一个线程实例和一个单独的线程以及该线程的MessageQueue相关联。当你创建一个新的Handler时,它就和创建它的线程绑定在一起了。这里,线程我们也可以理解为线程的MessageQueue。从这一点上来看,Handler把Message和Runable对象传递给MessageQueue,而且在这些对象离开MessageQueue时,Handler负责执行他们。

Handler有两个主要的用途:(1)确定在将来的某个时间点执行一个或者一些Message和Runnable对象。(2)在其他线程(不是Handler绑定线程)中排入一些要执行的动作。

SchedulingMessage,即(1),可以通过以下方法完成:

post(Runnable):Runnable在handler绑定的线程上执行,也就是说不创建新线程。

postAtTime(Runnable,long):

postDelayed(Runnable,long):

sendEmptyMessage(int):

sendMessage(Message):

sendMessageAtTime(Message,long):

sendMessageDelayed(Message,long):

post这个动作让你把Runnable对象排入MessageQueue,MessageQueue受到这些消息的时候执行他们,当然以一定的排序。sendMessage这个动作允许你把Message对象排成队列,这些Message对象包含一些信息,Handler的hanlerMessage(Message)会处理这些Message.当然,handlerMessage(Message)必须由Handler的子类来重写。这是编程人员需要作的事。

当posting或者sending到一个Hanler时,你可以有三种行为:当MessageQueue准备好就处理,定义一个延迟时间,定义一个精确的时间去处理。后两者允许你实现timeout,tick,和基于时间的行为。

当你的应用创建一个新的进程时,主线程(也就是UI线程)自带一个MessageQueue,这个MessageQueue管理顶层的应用对象(像activities,broadcastreceivers等)和主线程创建的窗体。你可以创建自己的线程,并通过一个Handler和主线程进行通信。这和之前一样,通过post和sendmessage来完成,差别在于在哪一个线程中执行这么方法。在恰当的时候,给定的Runnable和Message将在Handler的MessageQueue中被Scheduled。

Message简介:

Message类就是定义了一个信息,这个信息中包含一个描述符和任意的数据对象,这个信息被用来传递给Handler.Message对象提供额外的两个int域和一个Object域,这可以让你在大多数情况下不用作分配的动作。

尽管Message的构造函数是public的,但是获取Message实例的最好方法是调用Message.obtain(),或者Handler.obtainMessage()方法,这些方法会从回收对象池中获取一个。

MessageQueue简介:

这是一个包含message列表的底层类。Looper负责分发这些message。Messages并不是直接加到一个MessageQueue中,而是通过MessageQueue.IdleHandler关联到Looper。

你可以通过Looper.myQueue()从当前线程中获取MessageQueue。

Looper简介:

Looper类被用来执行一个线程中的message循环。默认情况,没有一个消息循环关联到线程。在线程中调用prepare()创建一个Looper,然后用loop()来处理messages,直到循环终止。

大多数和messageloop的交互是通过Handler。

下面是一个典型的带有Looper的线程实现。

classLooperThreadextendsThread{

publicHandlermHandler;

publicvoidrun(){

Looper.prepare();

mHandler=newHandler(){

publicvoidhandleMessage(Messagemsg){

//processincomingmessageshere

}

};

Looper.loop();

}

}

10.什么是ANR如何避免它?

ANR:ApplicationNotResponding,五秒

在Android中,活动管理器和窗口管理器这两个系统服务负责监视应用程序的响应。当出现下列情况时,Android就会显示ANR对话框了:

对输入事件(如按键、触摸屏事件)的响应超过5秒

意向接受器(intentReceiver)超过10秒钟仍未执行完毕

Android应用程序完全运行在一个独立的线程中(例如main)。这就意味着,任何在主线程中运行的,需要消耗大量时间的操作都会引发ANR。因为此时,你的应用程序已经没有机会去响应输入事件和意向广播(Intentbroadcast)。

因此,任何运行在主线程中的方法,都要尽可能的只做少量的工作。特别是活动生命周期中的重要方法如onCreate()和onResume()等更应如此。潜在的比较耗时的操作,如访问网络和数据库;或者是开销很大的计算,比如改变位图的大小,需要在一个单独的子线程中完成(或者是使用异步请求,如数据库操作)。但这并不意味着你的主线程需要进入阻塞状态已等待子线程结束--也不需要调用Therad.wait()或者Thread.sleep()方法。取而代之的是,主线程为子线程提供一个句柄(Handler),让子线程在即将结束的时候调用它(xing:可以参看Snake的例子,这种方法与以前我们所接触的有所不同)。使用这种方法涉及你的应用程序,能够保证你的程序对输入保持良好的响应,从而避免因为输入事件超过5秒钟不被处理而产生的ANR。这种实践需要应用到所有显示用户界面的线程,因为他们都面临着同样的超时问题。

11.什么情况会导致ForceClose?如何避免?能否捕获导致其的异常?

一般像空指针啊,可以看起logcat,然后对应到程序中来解决错误

12.解释一下activity、intentintentfilter、service、Broadcase、BroadcaseReceiver

一个activity呈现了一个用户可以操作的可视化用户界面

一个service不包含可见的用户界面,而是在后台无限地运行

可以连接到一个正在运行的服务中,连接后,可以通过服务中暴露出来的借口与其进行通信

一个broadcastreceiver是一个接收广播消息并作出回应的component,broadcastreceiver没有界面

intent:contentprovider在接收到ContentResolver的请求时被激活。

activity,service和broadcastreceiver是被称为intents的异步消息激活的。

一个intent是一个Intent对象,它保存了消息的内容。对于activity和service来说,它指定了请求的操作名称和待操作数据的URI

Intent对象可以显式的指定一个目标component。如果这样的话,android会找到这个component(基于manifest文件中的声明)并激活它。但如果一个目标不是显式指定的,android必须找到响应intent的最佳component。

它是通过将Intent对象和目标的intentfilter相比较来完成这一工作的。一个component的intentfilter告诉android该component能处理的intent。intentfilter也是在manifest文件中声明的。

相关推荐