牛客网—Android工程师能力评估测试
编写Aidl文件时,需要注意下面几点:
bindService是异步调用和Service进行绑定,如果绑定成功,则会调用ServiceConnection的onServiceConnected当调用bindService方法后就会回调Activity的onServiceConnected,在这个方法中会向Activity中传递一个IBinder的实例,Activity需要保存这个实例。
Android官方文档中对于onBinder()方法的解释:if you don’t want to allow binding, you should return null.(如果你不希望你的服务被绑定,那么你应该返回null)。测试确实如此,如果onBinder()方法返回Null那么onServiceConnected将不会被调用
进程按重要性分类,第一类进程最重要,通常最后被销毁
或者可以说:只要主线程正在做事,那么即为前台进程。
Toast只能设置为2s和3,5s,其它的值都无效,API文档虽然写了三个,但是在Framework里做了重定义,限定了2s和3,5s这两个值,对应
Toast.LENGTH_SHORT和Toast.LENGTH_LONG。实现方式在NotificationManagerService.java的scheduleTimeoutLocked()这个函数里。
总的来说:Toast只能使用short和long两种时长,传进去自定义数字实际不起作用,想要更丰富的提示推荐使用Dialog。
都可以
Intent可以传递哪些类型的数据:
ps:CharSequence接口的实现类有CharBuffer、String、StringBuffer、StringBuilder这个四个类。
上下文菜单(通过在某元素上长按,来呼出菜单)
选项菜单(通过按手机上的菜单按钮,来呼出菜单)
重写onCreateContextMenu用以创建上下文菜单
重写onCreateItemSelected用以响应上下文菜单
重写onCreateOptionsMenu用来创建选项菜单
重写onOptionsItemSelected用以响应选项菜单
当每次Menu显示时,回调用方法onPrepareOptionMenu,也可以在菜单每次被调用时,对菜单中的项重新生成,通过重载onPrepareOptionsMenu来实现,由于每次调用时都要重新生成,对于那些不经常变化的菜单,效率就会比较低。
总的来说:Android中有三种菜单
Android使用getWriteableDatabase()和getReadableDatabase()方法都可以获取一个用于操作数据库的SQLiteDatabase实例。
(getReadableDatabase()方法中会调用getWriteableDatabase()方法)
getReadableDatabase()并不是以只读方式打开数据库,而是先执行getWriteableDatabase(),失败的情况下才以只读方式打开数据库。但getWriteableDatabase()方法以读写方式打开数据库,一旦数据库的磁盘空间满了,数据库就只能读而不能写,getWriteableDatabase()打开数据库就会出错,getReadableDatabase()方法先以读写方式打开数据库,倘若使用如果数据库的磁盘空间满了,就会打开失败。当打开失败后会继续尝试以只读方式打开数据库。
Google宣称其虚拟机Dalvik支持JNI编程方式,也就是第三方应用完全可以通过JNI调用自己的C动态库,即在Android上,“Java+c”的编程方式是一直都可以实现的,NDK是Android支持C的开端说法是不正确的。
NDK是一系列工具的集合,NDK提供了一系列的工具,帮助开发者迅速的开发C/C++的动态库,并能自动将So和Java应用打成APK包。
NDK集成了交叉编译器,并提供了响应的mk文件和隔离cpu,平台等的差异,开发人员只需要简单的修改mk文件就可以创建出so
解析:
A:设置Activity的android:screenOrientation=”portrait”属性时,无法切换横竖屏,因此不但不会重新调用各个生命周期方法,而且onConfigurationChanged()方法也不会执行
B:未设置Activity的android:configChanges属性,API上说“the activity will be restarted if any of these configuration changes happen in the system”,即如果配置有改变,就会重启activity
C:launchMode设置为singletask时,通过Intent启动一个Activity,如果系统已经存在一个实例,系统就会将请求发送到这个实例上,但这个时候,系统就不会再调用通常情况下我们处理请求数据的onCreate()方法,而是调用onNewIntent方法
D:用户正在操作某个Activity,这是如果其它应用程序需要内存,此时的Activity是Foreground process,应该按照Empty process,Back process,Service process,Visible process顺序kill,最后才是前台进程。
简单说:如果设置了android:configChanges=”oritation|screenSize”,并在activtiy中复写onConfigurationChanged方法,就不会重新走生命周期,而是执行复写方法中的方法
launchMode为singleTask的时候,通过Intent启动一个Activity,如果系统已经存在一个实例,系统就会将请求发送到这个实例上,但这个时候,系统就不会再调用通常情况下我们处理请求数据的onCreate方法,而是调用OnNewIntent方法。
AD:产生ANR,程序没有响应,有可能程序会再次响应
BC:程序抛出异常,会强制退出
FC(Force close)原因:
1.Error:OOM,StackOverFlowError
2.RuntimeException
A:Message提供了消息池,有静态方法Obtain从消息池中取对象
B:Thread默认不提供资源池,除非使用线程池ThreadPool管理
C:AsyncTask是线程池改造的,池里默认提供(核数+1)个线程进行开发操作,最大支持(核数*2+1)个线程,超过后会丢弃其它任务
D:每个Looper创建时创建一个消息队列和线程对象,也不是资源池
解析:IntentService是继承Service的,那么它包含了Service的全部特性,当然也包含Service的生命周期,那么与service不同的是,IntentService在执行onCreate操作的时候,内部开启一个线程,去执行你的耗时操作。
IntentService其实就是一个Service的实现类,启动方式都是startService。
补充一下:style和theme本质上就是同一个东西,xml格式完全相同,只是我用在activity上我叫他theme,我用在View上我就叫他style,唯一的区别就是style里头控制的各个属性了,某些属性是只有针对Activity才能生效的(例如你View有标题栏嘛有状态栏嘛有导航栏嘛?但是反过来Activity内部却是有一个继承自View的Decorview)。所以style可以作用在activity上,但是theme却不能反过来作用在view上
theme是被final标记的,不能被继承。而且,xml文件中的parent不属于继承。说一下xml文件的解析规则,遇到parent就去parent里面解析,逐个递归,最后解析自己,相同的元素会被后面解析出来的覆盖掉,这也说明了D选项。
使用SimpleAdapter作为适配器时,支持三种类型的View,而且是按照如下顺序进行匹配:
CompoundButton声明如下:
‘public abstract class CompoundButton extends Button implements checkable’
可见他是实现了Checkable接口的按钮,因此也在入选范围
根据SimpleAdapter的源码可知,使用SimpleAdapter作为适配器会按照如下顺序判断View:
如果以上三种类型都不是,就会抛出IllegalStateExeception
Android专项练习
B:只能在UI线程操作UI组件
C:采用队列
D:只能属于创建它的线程
解析:在Android开发中,经常会用到线程和Timer,如果没有主动关闭它们,当程序结束时,线程并没有被销毁,而是一直在后台运行着,当我们重新启动应用时,又会重新启动一个线程,周而复始,你启动应用次数越多,开启的线程数就越多,你的机器就会变得越慢。还会导致意识不到的错误。
1.线程的销毁
Handler是线程与Activity通信的桥梁,利用handler接收到任务线程,放到任务队列里派对执行
例如:
//调用该任务线程的run() 方法执行任务线程。
Handler updateBarHandler =new handler();
handler.post(Runnable Thread);
//移除handler里的任务线程,调用线程的stop()方法,销毁线程。
handler.removecallbacks(Runnable Thread);
一个简单的例子如下:
import Android.app.Activity;
import Android.os.Bundle;
import Android.os.Handler;
import Android.util.Log;
public class HandlerThread extends Activity {
private static final String TAG = "HandlerThread";
private Handler mHandler = new Handler();
private Runnable mRunnable = new Runnable() {
public void run() {
//为了方便 查看,我们用Log打印出来
Log.e(TAG, Thread.currentThread().getName() + "Thread run");
}
};
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
//通过Handler启动线程
mHandler.post(mRunnable);
}
@Override
protected void onDestroy() {
//将线程销毁掉
mHandler.removeCallbacks(mRunnable);
super.onDestroy();
}
}
2.Timer的销毁
默认情况下,只要一个程序的timer线程在运行,那么这个程序就会保持运行。当然,你可以通过以下四种方式终止一个timer线程:
B:onStart()和onStop()方法之间的Activity是可见的,但是并不是可交互或者用户输入信息时侯的回调,只有onResume()之后,用户才可以交互操作Activity。
C:如果是正常回退,这个要看Activity Stack栈顶第二个Activity的状态,可能是onPaused(),如果是onPaused(),则直接回到onResume(),如果是onStop()则需要onRestart()->onStart()->onResume();如果Activity因为Config改变(横竖屏切换),则会重新创建一个Activity或者设置了android:config,则另当别论
解析:由于Broadcast Receiver本质上是一种监听器,所以创建Broadcast Receiver的方法也非常简单,只需要创建一个BroadcastReceiver的子类然后重写onReceiver(Context context,Intent intent)方法就行
Broadcast Receiver的生命周期,从对象调用它开始,到onReceiver()方法完成之后结束。另外,每次广播被接收后会重新创建Broadcast Receiver对象,并在onReceiver方法中执行完就销毁,如果Broadcast Receiver的onReceiver方法中不能再10秒内执行完成,Android会出现ANR,所以不要在onReceiver方法中执行耗时的操作
如果需要在Broadcast Receiver中执行耗时操作,可以通过Intent启动Service来完成,但是不能绑定Service。
Android专项练习
解析:Android系统用的就是Linux的内核,DVM可以理解成在Linux上跑的程序,每个应用程序运行时,都会启动一个DVM实例,也就是一个Linux的进程,因此DVM进程和Linux进程实际上是一回事
Android的动画分为三种:
解析:
1.前台进程:
用户当前操作所必需的进程,如果一个进程满足一下任一条件,即视为前台进程:
通常,在任意给定时间前台进程都为数不多。只有在内存不足以支持它们同时继续运行这一万不得已的情况下,系统才会终止它们。此时,设备往往已达到内存分页状态,因此需要终止一些前台进程来确保用户界面正常响应。
2.可见进程:
没有任何前台组件,但仍会影响用户在屏幕上所见内容的进程。如果一个进程满足以下任一条件,即可视为可见进程:
可见进程被视为是及其重要的进程,除非为了维持所有前台进程同时运行而必须终止,否则系统不会终止这些进程。
3.服务进程:
正在运行已使用startService()方法启动的服务且不属于上述两个更高类别进程的进程。尽管服务进程与用户所见内容没有直接关联,但是它们通常在执行一些用户关心的操作(例如:在后台播放音乐或从网络下载数据)。因此,除非内存不足以维持所有前台进程和可见进程同时运行,否则系统会让服务进程保持运行状态。
4.后台进程:
包含目前对用户不可见的Activity进程(已调用Activity的onStop()方法)。这些进程对用户体验没有直接影响,系统可能随时终止它们,以回收内存供前台进程,可见进程,或服务进程使用。通常会有很多后台进程在运行,因此它们会保存在LRU(最近最少使用)列表中,以确保包含用户最近查看的Activity的进程最后一个被终止。如果某个Activity正确实现了生命周期方法,并保存了其当前状态,则终止其进程不会对用户体验产生明显影响,因为当用户导航回该Activity时,Activity会恢复其所有可见状态。有关保存和恢复状态的信息,请看Activity文档。
5.空进程:
不含任何活动应用组件的进程。保留这种进程的唯一目的是用作缓存,以缩短下次在其中运行组件所需要的启动时间。为使总体系统资源在进程缓存和底层内核缓存之间保持平衡,系统往往会终止这些进程。
解析:
这道题A和B有争议!我认为是A,答案为B。
启动B的时候立马回调result方法,当launchMode为singleTask或singleInstance时候都这样。只要被启动的activity设置为singleInstance则startActivityForResult不起效。
不同task之间,不能传递数据。
解析:Android2.2以后的备份服务功能允许用户备份应用数据到云存储中,即当应用执行了工厂服务或转换到一个新的平台上时,如果备份的应用需要重新安装,系统就自动恢复原先备份的数据并重新安装。
解析:
Android提供了Handler和Looper来满足线程间的通信。Handler先进先出原则。Looper类用来管理特定线程内对象之间的消息交换(MessageExchange)
Looper:一个线程可以产生一个Looper对象,由它来管理此线程里的MessageQueue(消息队列)
Handler:你可以构造Handler对象来与Looper沟通,以便Push新消息到MessageQueue里;或者接收Looper从Message Queue所送来的消息
Message Queue(消息队列):用来存放线程放入的消息
线程:UIThread 通常就是main thread,而Android启动程序时会替他建立一个MessageQueue。
解析:
Android中实现序列化有两个选择:
实现Serializable接口非常简单,声明一下就可以;而实现Parcelable接口稍微复杂一些,但效率更高,推荐用这种方法提高性能。
注:Android中Intent传递对象有两种方法:
当然这些Object是有一定条件的,前者实现了Serializable接口,而后者实现了Parcelable接口。
Serializable本身就是Java特有的序列化接口。而Parcelable是Android才有的,之所以Android还要弄出Parcelable而不直接用Serializable,就是因为Parcelable更加高效,但比起Serializable在写法上要复杂一些。
解析:
获取屏幕密度 :getScreen
获取设备屏幕大小:getDisplay
获取屏幕属性,从而取得屏幕的高度和宽度:getMetrics
获取window对象:getWindows
DVM指dalivk的虚拟机。每个Android应用程序都在它自己的进程中运行,都拥有一个独立额度Dalvik虚拟机实例。而每一个DVM都是在Linux中的一个进程,所以说可以认为是同一概念
Dalvik是Google公司自己设计用于Android平台的Java虚拟机,每一个Dalvik应用作为一个独立的Linux进程执行。独立的进程可以防止在虚拟机奔溃的时候所有程序都被关闭。
Dalvik和Java运行环境的区别:
解析:
Android中界面部分也采用了当前比较流行的MVC框架,在Android中:
解析:
如果从用户角度来说,是不能编辑的。
解析:
Broadcast Receiver本质上是一种监听器,所以创建Broadcast Receiver的方法也非常简单,只需要创建一个Broadcast Receiver的子类然后重写onReceiver(Context context,Intent intent)方法即可
Broadcast Receiver的生命周期,从对象调用它开始,到onReceiver方法执行完成之后结束,另外,每次广播被接收后会重新创建Broadcast Receiver对象,并在onReceiver()方法中执行完就销毁,如果Broadcast Receiver的onReceiver方法中不能在10s内执行完成,Android就会出现ANR异常,所以不要在Broadcast Receiver的onReceiver方法中执行耗时操作。
如果要在Broadcast Receiver中执行耗时操作,可以通过Intent启动Service来完成,但不能绑定Sercvice。
解析:编写aidl文件时,需要注意以下几点:
AIDL Android Interface Definition Language,即Android接口定义语言
Android使用AIDL提供公开服务接口,使得不同进程间可以相互通信
解析:
A:Message提供了消息池,有静态方法Obtain从消息池中取对象
B:Thread默认不提供资源池,除非使用线程池Thread Pool管理
C:AsyncThread是线程池改造的,池里默认提供(核数+1)个线程进行并发操作,最大支持(核数*2+1)个线程,超过后会丢弃其它任务
D:Looper,每个Looper创建时创建一个消息队列和线程对象,也不是资源池。