您的位置:首页 > 移动开发 > Android开发

android一些容易被忽略的问题

2012-08-25 21:02 316 查看
面试归来,把面试过程中被问到没回答上来、或者说回答的不好的问题列出来。

1.    注册广播有几种方式,这些方式有何优缺点?(重点是不同方式的比较没答上来)

实现BroadcastReceiver,并设置广播接收器接收广播信息的类型(过滤器)。然后我们就可以把广播接收器注册到系统里面,可以让系统知道我们有个广播接收器。

这里有两种,一种是代码动态注册:
//生成广播处理  
smsBroadCastReceiver = newSmsBroadCastReceiver();   
//实例化过滤器并设置要过滤的广播  
IntentFilter intentFilter = newIntentFilter("android.provider.Telephony.SMS_RECEIVED"); 
//注册广播   
BroadCastReceiverActivity.this.registerReceiver(smsBroadCastReceiver,intentFilter);  

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

<!--广播注册-->  

       <receiver android:name=".SmsBroadCastReceiver">  

            <intent-filterandroid:priority="20">  

                <actionandroid:name="android.provider.Telephony.SMS_RECEIVED"/>  

            </intent-filter>  

       </receiver>

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

两种注册类型的区别是:

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

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

2.    service的生命周期(一直关注activity的生命周期,service的生命周期也会被问到,要熟)

相对于activity,service的回调方法之一onCreate(),onStart(),onDestroy().Service不能自己启动,必须通过context对象调用startService()或bindService()方法启动。两种方法的生命周期不一样。

startService()启动service时,如果service没有启动,首先调用onCreate()方法,然后再调用onStart()方法。如果service已经启动,则直接调用onStart()方法。通过startService()启动的service可以通过context对象的stopService()方法关闭,也可以通过service自身调用stopSelf()或者stopSelfResult()来关闭。关闭之前调用onDestroy()方法。

bindService()功能是,使当前的context对象通过一个serviceConnection的对象绑定到所指定的Service,若没有启动Service(),则首先调用service的onCreate()方法来初始化service,然后调用service的onBind()方法初始化绑定。如果绑定service的context对象已经被销毁时,被绑定的service也会调用onUnbind()方法和onDestroy()方法并停止运行。一个绑定了服务的context对象通过unBindService()方法取消对服务的绑定。取消时,service会调用unBind()方法,若service通过bindService()来启动的,还会调用onDestroy()方法。

3.    bindService()和startService()区别,怎么用

见问题2

4. android中的内存泄漏问题

可以参考:http://blog.csdn.net/huaciom/article/details/6247402等等等等

Android(Java)中常见的容易引起内存泄漏的不良代码 

(一) 查询数据库没有关闭游标 

(二) 构造Adapter时,没有使用缓存的 convertView 

(三) Bitmap对象不在使用时调用recycle()释放内存 

(四) 释放对象的引用 

(五) 其他 

5.ANR

ANR:Application NotResponding,五秒 。(注意下时间)

6.activity的启动方式有哪些、区别?

http://www.cnblogs.com/halzhang/archive/2011/01/05/1926771.html

http://www.itivy.com/android/archive/2011/6/18/four-load-modes-for-android-activity.html

http://blog.csdn.net/pcwings/article/details/5895197

standard(默认方式)、singleTop、singleTask、singleInstance。

看了也不是太明白,所以自己写了一个例子试了一下,对这四种启动模式有了更多了解。

(1)standard:不多说、好理解

(2)singleTask:例子构造如下

例子中共5个Acitivity:TestActivity1、TestActivity2,……TestActivity5.设置启动模式分别为:standard,singleTop,singleTask,standard,standard。

当压栈顺序为TestActivity1、TestActivity2、TestActivity3、TestActivity4、TestActivity5、TestActivity3。

当按返回键时,直接返回了TestActivity2、TestActivity1

(3)singleInstance:例子构造如下

例子中共5个Acitivity:TestActivity1、TestActivity2,……TestActivity5.设置启动模式分别为:standard,singleTop,singleInstance,standard,standard。

当压栈顺序为TestActivity1、TestActivity2、TestActivity3、TestActivity4、TestActivity5、TestActivity3。

按返回键时,出栈顺序为:TestActivity5、TestActivity4、TestActivity2、TestActivity1.

(4)singleTop:例子构造如下
例子中共5个Acitivity:TestActivity1、TestActivity2.设置启动模式分别为:standard,singleTop。

当压栈顺序为TestActivity1、TestActivity2、TestActivity2、TestActivity2。

按返回键时,出栈顺序为TestActivity1。

7. 
   handler机制的原理 (描述清楚)

主要要搞清楚message的生命周期,在一个完整过程中是怎样一步一步传递的
看了这一篇,感觉比较清晰了:http://gundumw100.iteye.com/blog/858233

下面从初始化过程、消息发送过程和消息接收过程简单归纳一下:

(1)初始化过程:主线程创建的时候,自动创建Looper(非主线程不会自动创建Looper),创建looper的时候会自动创建一个由他来管理的MessageQueue;

(2)消息的发送过程:handler通过obtainMessage()方法获取一个Message对象,封装好消息内容后,通过sendMessage()方法将消息发送给Looper,Looper收到后,将其放入MessageQueue;

(3)消息的接收过程:Looper发现MessageQueue中有Message时,就将其广播出去,handler
对象收到该消息后,调用相应的handler 对象的handleMessage()方法对其进行处理。 

8.android中解析XML文件的方式,区别?

有SAX和DOM两种方式。

DOM
是用与平台和语言无关的方式表示 XML 文档的官方 W3C 标准。DOM 是以层次结构组织的节点或信息片断的集合。这个层次结构允许开发人员在树中寻找特定信息。分析该结构通常需要加载整个文档和构造层次结构,然后才能做任何工作。由于它是基于信息层次的,因而
DOM 被认为是基于树或基于对象的。DOM 以及广义的基于树的处理具有几个优点。
首先,由于树在内存中是持久的,因此可以修改它以便应用程序能对数据和结构作出更改。它还可以在任何时候在树中上下导航,而不是像 SAX 那样是一次性的处理。DOM 使用起来也要简单得多。
另一方面,对于特别大的文档,解析和加载整个文档可能很慢且很耗资源,因此使用其他手段来处理这样的数据会更好。

 SAX处理的优点非常类似于流媒体的优点。分析能够立即开始,而不是等待所有的数据被处理。而且,由于应用程序只是在读取数据时检查数据,因此不需要将数据存储在内存中。这对于大型文档来说是个巨大的优点。事实上,应用程序甚至不必解析整个文档;它可以在某个条件得到满足时停止解析。一般来说,SAX还比它的替代者DOM快许多。

DOM采用建立树形结构的方式访问XML文档,而SAX采用时间模型方式。

 DOM解析器把XML文档转化为一个包含其内容的树,并可以对树进行遍历。用DOM解析模型的优点是编程容易,开发人员只需要调用建树的指令,然后利用navigation APIs访问所需的树节点来完成任务。可以很容易的添加和修改树中的元素。然而由于使用DOM解析器的时候需要处理整个XML文档,所以对性能和内存的要求比较高,尤其是遇到很大的XML文件的时候。由于它的遍历能力,DOM解析器常用于XML文档需要频繁的改变的服务中。

  SAX解析器采用了基于事件的模型,它在解析XML文档的时候可以触发一系列的事件,当发现给定的tag的时候,它可以激活一个回调方法,告诉该方法制定的标签已经找到。SAX对内存的要求通常会比较低,因为它让开发人员自己来决定所要处理的tag。特别是当开发人员只需要处理文档中所包含的部分数据时,SAX这种扩展能力得到了更好的体现。但用SAX解析器的时候编码工作会比较困难,而且很难同时访问同一个文档中的多处不同数据。

9
Activity生命周期中,哪些阶段是可见、哪些阶段可获得焦点

当Activity运行到onStart()/onRestart()时,用户就可以再屏幕上看到这个Activity。相反,运行到inStop()时,这个Activity从屏幕上消失。在此期间,虽然Activity可见,但有时并不拥有焦点。

在onStop方法中,我们应该暂停或结束动画、线程、定时器、服务这些用了更新界面的字眼,因为当Activity变为不可见后,更新这个东西没有意义。正确方法时当UI变得可见之后,调用onStart()或onRestart()方法继续活重启Activity这些资源。

onStart()和onStop()也被用于注册、取消注册BroadcastReceiver。

Activity从onResume()到onPause()的过程称为活跃Activity的生命周期,这期间Activity可见并且可以获得用户输入的焦点。

10横竖屏切换时候activity的生命周期

1)、新建一个Activity,并把各个生命周期打印出来

2)、运行Activity,得到如下信息

onCreate-->

onStart-->

onResume-->

3)、按crtl+f12切换成横屏时

onSaveInstanceState-->

onPause-->

onStop-->

onDestroy-->

onCreate-->

onStart-->

onRestoreInstanceState-->

onResume-->

4)、再按crtl+f12切换成竖屏时,发现打印了两次相同的log

onSaveInstanceState-->

onPause-->

onStop-->

onDestroy-->

onCreate-->

onStart-->

onRestoreInstanceState-->

onResume-->

onSaveInstanceState-->

onPause-->

onStop-->

onDestroy-->

onCreate-->

onStart-->

onRestoreInstanceState-->

onResume-->

5)、修改AndroidManifest.xml,把该Activity添加 android:configChanges="orientation",执行步骤3

onSaveInstanceState-->

onPause-->

onStop-->

onDestroy-->

onCreate-->

onStart-->

onRestoreInstanceState-->

onResume-->

6)、再执行步骤4,发现不会再打印相同信息,但多打印了一行onConfigChanged

onSaveInstanceState-->

onPause-->

onStop-->

onDestroy-->

onCreate-->

onStart-->

onRestoreInstanceState-->

onResume-->

onConfigurationChanged-->

7)、把步骤5的android:configChanges="orientation" 改成 android:configChanges="orientation|keyboardHidden",执行步骤3,就只打印onConfigChanged

onConfigurationChanged-->

8)、执行步骤4

onConfigurationChanged-->

onConfigurationChanged-->

 总结:

1、不设置Activity的android:configChanges时,切屏会重新调用各个生命周期,切横屏时会执行一次,切竖屏时会执行两次

2、设置Activity的android:configChanges="orientation"时,切屏还是会重新调用各个生命周期,切横、竖屏时只会执行一次

3、设置Activity的android:configChanges="orientation|keyboardHidden"时,切屏不会重新调用各个生命周期,只会执行onConfigurationChanged方法

总结一下整个Activity的生命周期

补充一点,当前Activity产生事件弹出Toast和AlertDialog的时候Activity的生命周期不会有改变

Activity运行时按下HOME键(跟被完全覆盖是一样的):onSaveInstanceState --> onPause --> onStop       onRestart -->onStart--->onResume

Activity未被完全覆盖只是失去焦点:onPause--->onResume

11、Android中的进程线程

参考:http://blog.csdn.net/geniuseoe2012/article/details/7910715

当一个应用程序开始运行它的第一个组件时,Android会为它启动一个Linux进程,并在其中执行一个单一的线程。默认情况下,应用程序所有的组件均在这个进程的这个线程中运行。然而,你也可以安排组件在其他进程中运行,而且可以为任意进程衍生出其它线程。


Android中的进程

组件运行所在的进程由manifest文件所控制。组件元素——<activity>, <service>, <receiver>和<provider>——都有一个 process 属性来指定组件应当运行于哪个进程之内。这些属性可以设置为使每个组件运行于它自己的进程之内,或一些组件共享一个进程而其余的组件不这么做。它们也可以设置为令不同应用程序的组件在一个进程中运行——使应用程序的组成部分共享同一个Linux用户ID并赋以同样的权限。<application>元素也有一个process属性,以设定所有组件的默认值。

所有的组件实例都位于特定进程的主线程内,而对这些组件的系统调用也将由那个线程进行分发。一般不会为每个实例创建线程。因此,某些方法总是运行在进程的主线程内,这些方法包括诸如View.onKeyDown()这样报告用户动作以及生命周期通告的。这意味着组件在被系统调用的时候,不应该施行长时间的抑或阻塞的操作(诸如网络相关操作或是循环计算),因为这将阻塞同样位于这个进程的其它组件的运行。你应该如同下面线程部分所叙述的那样,为这些长时间操作衍生出一个单独的线程进行处理。

在可用内存不足而又有一个正在为用户进行服务的进程需要更多内存的时候,Android有时候可能会关闭一个进程。而在这个进程中运行着的应用程序也因此被销毁。当再次出现需要它们进行处理的工作的时候,会为这些组件重新创建进程。

在决定结束哪个进程的时候,Android会衡量它们对于用户的相对重要性。比如说,相对于一个仍有用户可见的activity的进程,它更有可能去关闭一个其activity已经不为用户所见的进程。也可以说,决定是否关闭一个进程主要依据在那个进程中运行的组件的状态。


Android中的线程

尽管你可以把你的应用程序限制于一个单独的进程中,有时,你仍然需要衍生出一个线程以处理后台任务。因为用户界面必须非常及时的对用户操作做出响应,所以,控管activity的线程不应用于处理一些诸如网络下载之类的耗时操作。所有不能在瞬间完成的任务都应安排到不同的线程中去。

线程在代码中是以标准JavaThread对象创建的。Android提供了很多便于管理线程的类:Looper用于在一个线程中运行一个消息循环,Handler用于处理消息,HandlerThread 用于使用一个消息循环启用一个线程。




内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: