当前位置: 代码迷 >> Android >> Android面试题拾掇(中)
  详细解决方案

Android面试题拾掇(中)

热度:82   发布时间:2016-05-01 20:47:06.0
Android面试题整理(中)
   


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

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

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

1、抛异常强制退出:
该方法通过抛异常,使程序ForceClose。
验证可以,但是,需要解决的问题是,如何使程序结束掉,而不弹出Force Close的窗口。
2、记录打开的Activity:
每打开一个Activity,就记录下来。在需要退出时,关闭每一个Activity即可。
3、发送特定广播:
在需要结束应用时,发送一个特定的广播,每个Activity收到广播后,关闭即可。
4、递归退出
在打开新的Activity时使用startActivityForResult,然后自己加标志,在onActivityResult中处理,递归关闭。

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

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

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

    1)安装和下载Cygwin,下载 Android NDK
  2)在ndk项目中JNI接口的设计
  3)使用C/C++实现本地方法
  4)JNI生成动态链接库.so文件
  5)将动态链接库复制到java工程,在java工程中调用,运行java工程即可

5. 简述Android应用程序结构是哪些?
    
    Android应用程序结构是:
  Linux Kernel(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()启动服务
  Intent intent =new Intent(DemoActivity.this, DemoService.class);
  startService(intent);

  2.Context.bindService()启动
  Intent intent =new Intent(DemoActivity.this, DemoService.class);
  bindService(intent, conn, Context.BIND_AUTO_CREATE);
  //unbindService(conn);//解除绑定

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

    Android广播机制(两种注册方法)
  在android下,要想接受广播信息,那么这个广播接收器就得我们自己来实现了,我们可以继承BroadcastReceiver,就可以有一个广播接受器了。有个接受器还不够,我们还得重写BroadcastReceiver里面的onReceiver方法,当来广播的时候我们要干什么,这就要我们自己来实现,不过我们可以搞一个信息防火墙。具体的代码:
  public class SmsBroadCastReceiverextends BroadcastReceiver{
       @Override
       public void onReceive(Context context, Intent intent){
            Bundle bundle = intent.getExtras();
            Object[] object = (Object[])bundle.get("pdus");
            SmsMessage sms[]=new SmsMessage[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 = new SmsBroadCastReceiver();
  
    //实例化过滤器并设置要过滤的广播
  IntentFilter intentFilter = 
                   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的英文全称是Android Interface Define Language
  当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(ComponentName name, 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绑定线程)中排入一些要执行的动作。
  Scheduling Message,即(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,broadcast receivers等)和主线程创建的窗体。你可以创建自己的线程,并通过一个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,直到循环终止。
  大多数和message loop的交互是通过Handler。
  下面是一个典型的带有Looper的线程实现。
  class LooperThread extends Thread {
        public Handler mHandler;
        public void run() {
          Looper.prepare();
          mHandler = new Handler() {
               public voidhandleMessage(Message msg) {
                   // process incomingmessages here
               }
         };
         Looper.loop();
         }
  }

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

  ANR:Application NotResponding,五秒
  在Android中,活动管理器和窗口管理器这两个系统服务负责监视应用程序的响应。当出现下列情况时,Android就会显示ANR对话框了:
  对输入事件(如按键、触摸屏事件)的响应超过5秒
  意向接受器(intentReceiver)超过10秒钟仍未执行完毕
  Android应用程序完全运行在一个独立的线程中(例如main)。这就意味着,任何在主线程中运行的,需要消耗大量时间的操作都会引发ANR。因为此时,你的应用程序已经没有机会去响应输入事件和意向广播(Intentbroadcast)。
  因此,任何运行在主线程中的方法,都要尽可能的只做少量的工作。特别是活动生命周期中的重要方法如onCreate()和 onResume()等更应如此。潜在的比较耗时的操作,如访问网络和数据库;或者是开销很大的计算,比如改变位图的大小,需要在一个单独的子线程中完成(或者是使用异步请求,如数据库操作)。但这并不意味着你的主线程需要进入阻塞状态已等待子线程结束 -- 也不需要调用Therad.wait()或者Thread.sleep()方法。取而代之的是,主线程为子线程提供一个句柄(Handler),让子线程在即将结束的时候调用它(xing:可以参看Snake的例子,这种方法与以前我们所接触的有所不同)。使用这种方法涉及你的应用程序,能够保证你的程序对输入保持良好的响应,从而避免因为输入事件超过5秒钟不被处理而产生的ANR。这种实践需要应用到所有显示用户界面的线程,因为他们都面临着同样的超时问题。


11.什么情况会导致Force Close ?如何避免?能否捕获导致其的异常?
  
   一般像空指针啊,可以看起logcat,然后对应到程序中 来解决错误

12. 解释一下activity、intent intent filter、service、Broadcase、BroadcaseReceiver

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

  一个service不包含可见的用户界面,而是在后台无限地运行
  可以连接到一个正在运行的服务中,连接后,可以通过服务中暴露出来的借口与其进行通信

  一个broadcast receiver是一个接收广播消息并作出回应的component,broadcastreceiver没有界面
  intent:content provider在接收到ContentResolver的请求时被激活。
  activity, service和broadcast receiver是被称为intents的异步消息激活的。

  一个intent是一个Intent对象,它保存了消息的内容。对于activity和service来说,它指定了请求的操作名称和待操作数据的URI
  Intent对象可以显式的指定一个目标component。如果这样的话,android会找到这个component(基于manifest文件中的声明)并激活它。但如果一个目标不是显式指定的,android必须找到响应intent的最佳component。
  它是通过将Intent对象和目标的intent filter相比较来完成这一工作的。一个component的intent filter告诉android该component能处理的intent。intent filter也是在manifest文件中声明的。
  相关解决方案