Android面试基础知识总结。
Activity
生命周期
- 启动Activity:onCreate->onStart->onResume
- 锁屏或被其它Activity覆盖:onPause->onStop
- 解锁或由被覆盖状态再回到前台:onRestart->onStart->onResume
- 跳转到其它Activity或按Home进入后台:onPause->onStop
- 退回到此Activity:onRestart->onStart->onResume
- 退出此Activity:onPause->onStop->onDestory
- 对话框弹出不会执行任何生命周期(注:对话框如果是Activity(Theme为Dialog),还是会执行生命周期的)
- 从A跳转到B:A-onPause->B-(onCreate->onStart->onResume)-A-onStop
- 从B返回到A:B-onPause->A-(onRestart->onStart->onResume)-B-(onStop->onDestroy)
onWindowFocusChanged方法
- 窗口焦点改变时被调用
- 在onResume之后获得焦点,onPause之后失去焦点
onSaveInstanceState方法
- 用于保存Activity的状态存储一些临时数据
- Activity被覆盖或进入后台,由于系统资源不足被kill会被调用
- 用户改变屏幕方向会被调用
- 跳转到其它Activity或按Home进入后台会被调用
- 会在onStop之前被调用,和onPause的顺序不固定的
onRestoreInstanceState(Bundle savedInstanceState)方法
- 用于恢复保存的临时数据,此方法的Bundle参数也会传递到onCreate方法中,你也可以在onCreate(Bundle savedInstanceState)方法中恢复数据
- 由于系统资源不足被kill之后又回到此Activity会被调用
- 用户改变屏幕方向重建Activity时会被调用
- 会在onStart之后被调用
问题:内存不足时,怎么保持Activity的一些状态,在哪个方法里面做具体操作?
在onSaveInstanceState方法中保存Activity的状态,在onRestoreInstanceState或onCreate方法中恢复Activity的状态
屏幕方向
- 竖屏:在AndroidManifest.xml中对指定的Activity设置android:screenOrientation=”portrait”或在onCreate方法中调用
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
- 横屏:在AndroidManifest.xml中对指定的Activity设置android:screenOrientation=”landscape”或在onCreate方法中调用
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
默认情况下,切换屏幕方向时Activity会销毁、重建
- onPause->onStop->onDestroy->onCreate->onStart->onResume
配置为android:configChanges=”orientation|screenSize”时
- 只会调用onConfigurationChanged方法
- 注意当配置screenOrientation属性后,此属性无效。
启动模式
- standard 标准模式(activity默认的): 每次调用startActivity, 都会把activity给创建.
- singleTop 单一顶部模式: 每次调用startActivity, 需要判断当前的activity是否已经被创建过并且查看任务栈的顶部是否是当前的 activity, 如果是, 调用onNewIntent方法, 如果不是, 就创建一个新的activity实例.
应用场景: 非法程序员, 写的流氓程序, 一直在弹出某个页面. - singleTask 单一任务栈模式: 如果任务栈中已经存在当前activity, 再去调用startActivity, 会调用当前任务栈的onNewIntent方法. 同时 , 会把所有以上的activity都给清除出栈.
应用场景: 如果一个界面显示的资源非常大, 只需要初始化一次实例. - singleInstance 单一实例模式: activity会在一个新的任务栈中实例化, 并且其他的activity不会创建在新的任务栈中. 始终在整个系统中 会被初始化一次.
应用场景: 在整个系统中, 只需要初始化一次的页面.
同一个程序不同的Activity如何放在不同的任务栈中?
- 需要为不同的activity设置不同的affinity属性,启动activity的Intent需要包含FLAG_ACTIVITY_NEW_TASK标记。
如何将一个Activity设置成窗口的样式
- 给Activity设置主题为android:theme=”@android:style/Theme.Dialog”
如何退出Activity?如何安全退出已调用多个Activity的Application?
- 退出Activity直接finish即可。
- 抛异常强制退出,该方法通过抛异常,使程序Force Close。验证可以,但是,需要解决的问题是,如何使程序结束掉,而不弹出Force Close的窗口。
- 记录打开的Activity:每打开一个Activity,就记录下来。在需要退出时,关闭每一个Activity即可。
- 发送特定广播:在需要结束应用时,发送一个特定的广播,每个Activity收到广播后,关闭即可。
- 递归退出:在打开新的Activity时使用startActivityForResult,然后自己加标志,在onActivityResult中处理,递归关闭。
Fragment生命周期
onAttach->onCreate->onCreateView->onActivityCreated->onStart->onResume->onPause->onStop->onDestroyView->onDestroy->onDetach
Broadcast、Content Provider 和 AIDL的区别和联系
这3种都可以实现跨进程的通信,那么从效率,适用范围,安全性等方面来比较的话他们3者之间有什么区别?
Broadcast:用于发送和接收广播!实现信息的发送和接收!
AIDL:用于不同程序间服务的相互调用!实现了一个程序为另一个程序服务的功能!
Content Provider:用于将程序的数据库人为地暴露出来!实现一个程序可以对另个程序的数据库进行相对用的操作!
Broadcast,既然是广播,那么它的优点是:注册了这个广播接收器的应用都能够收到广播,范围广。
缺点是:速度慢点,而且必须在一定时间内把事情处理完(onReceive执行必须在几秒之内),否则的话系统给出ANR。
AIDL,是进程间通信用的,类似一种协议吧。优点是:速度快(系统底层直接是共享内存),性能稳,效率高,一般进程间通信就用它。
Content Provider,因为只是把自己的数据库暴露出去,其他程序都可以来获取数据,数据本身不是实时的,不像前两者,只是起个数据供应作用。一般是某个成熟的应用来暴露自己的数据用的。 你要是为了进程间通信,还是别用这个了,这个又不是实时数据。
参考链接:http://blog.csdn.net/woaieillen/article/details/8185531
Handler机制
- andriod提供了Handler 和 Looper 来满足线程间的通信。Handler先进先出原则。Looper类用来管理特定线程内对象之间的消息交换(MessageExchange)。
- Looper: 一个线程可以产生一个Looper对象,由它来管理此线程里的MessageQueue(消息队列)。
- Handler: 你可以构造Handler对象来与Looper沟通,以便push新消息到MessageQueue里;或者接收Looper从Message Queue取出)所送来的消息。
- Message Queue(消息队列):用来存放线程放入的消息。
- 线程:UIthread 通常就是main thread,而Android启动程序时会替它建立一个MessageQueue。
ListView卡顿原因
- Adapter的getView方法里面convertView没有使用setTag和getTag方式;
- 在getView方法里面ViewHolder初始化后的赋值或者是多个控件的显示状态和背景的显示没有优化好,抑或是里面含有复杂的计算和耗时操作;
- 在getView方法里面 inflate的row 嵌套太深(布局过于复杂)或者是布局里面有大图片或者背景所致;
- Adapter多余或者不合理的notifySetDataChanged;
- listview 被多层嵌套,多次的onMessure导致卡顿,如果多层嵌套无法避免,建议把listview的高和宽设置为fill_parent. 如果是代码继承的listview,那么也请你别忘记为你的继承类添加上LayoutPrams,注意高和宽都是fill_parent的;
数据存储,数据持久化的方式有哪些
- SharedPreference
- 数据库SQLite
- 文件
- ContentProvider内容提供者,如联系人
- 网络
进程优先级
- 前台进程
- 可视进程
- 服务进程
- 后台进程
- 空进程
JVM 和Dalvik虚拟机的区别
- JVM:
.java -> javac -> .class -> jar -> .jar
架构: 堆和栈的架构. - DVM:
.java -> javac -> .class -> dx.bat -> .dex
架构: 寄存器(cpu上的一块高速缓存)
Android中px,sp,dip,dp的区别与联系,将60px转换为相应屏幕的dp,并填入下表
ldpi | mdpi | tvdpi | hdpi | xhdpi | xxhdpi | xxxhdpi |
---|---|---|---|---|---|---|
80 | 60 | 45 | 40 | 30 | 20 | 15 |
px = dip * density / 160
ldpi = 60px/0.75 = 80dp
mdpi = 60px/1 = 60dp
hdpi = 60px/1.5 = 40dp
xhdpi = 60px/2.0 = 30dp
xxhdpi = 60px/3.0 = 20dp
xxxhdpi = 60px/4.0 = 15dp
PPI = Pixels per inch,每英寸上的像素数,即 “像素密度”
xxxhdpi: 4.0
xxhdpi: 3.0 (10801920) ppi=480
xhdpi: 2.0 (7201280) ppi=320
hdpi: 1.5 (480800) ppi=240
mdpi: 1.0 (baseline)(320480) ppi=160
ldpi: 0.75 (240*320) ppi=120
tvdpi:ppi=213
dip: device independent pixels(设备独立像素). 不同设备有不同的显示效果,这个和设备硬件有关,一般我们为了支持WVGA、HVGA和QVGA 推荐使用这个,不依赖像素。
dp: dip是一样的
px: pixels(像素).
pt: point,是一个标准的长度单位,1pt=1/72英寸,用于印刷业,非常简单易用;
sp: scaled pixels(放大像素). 主要用于字体显示best for textsize。
in(英寸):长度单位。
mm(毫米):长度单位。
据px = dip * density / 160,则当屏幕密度为160时,px = dip
根据 google 的建议,TextView 的字号最好使用 sp 做单位,而且查看TextView的源码可知Android默认使用sp作为字号单位。将dip作为其他元素的单位。
参考链接:http://www.jb51.net/article/38506.htm
http://www.cnblogs.com/bluestorm/p/3640786.html
简述Android应用程序的组成
- Activites 应用程序的表示层。
应用程序的每个界面都将是Activity类的扩展。Acitvities用视图(View)构成GUI来显示信息、响应用户操作。就桌面开发而言,一个活动(Activity)相当于一个窗体(Form)。 - Services 应用程序中的隐形工作者。
Service组件在后台运行,更新你的数据源和可见的Activities,触发通知(Notification)。在应用程序的Activities不激活或不可见时,用于执行依然需要继续的长期处理。 - Content Providers 可共享的数据存储。
Content Providers用于管理和共享应用程序数据库。是跨应用程序边界数据共享的优先方式。 - Intents 一个应用程序间(inter-application)的消息传递框架。
使用Intents你可以在系统范围内广播消息或者对一个目标Activity或Service发送消息,来表示你要执行一个动作。 - Widgets 可以添加到主屏幕界面(home screen)的可视应用程序组件。
作为Broadcase Receiver的特殊变种,widgets让你可以为用户创建可嵌入到主屏幕界面的动态的、交互的应用程序组件。
Android中的动画有哪些,区别是什么
两种,一种是Tween动画、还有一种是Frame动画。Tween动画,这种实现方式可以使视图组件移动、放大、缩小以及产生透明度的变化;另一种Frame动画,传统的动画方法,通过顺序的播放排列好的图片来实现,类似电影。
简述静默安装的原理,如何在无需root权限的情况下实现静默安装?
- 伪装成系统应用,这就要给app打上系统应用的签名,但是这些签名在小米等手机上是没用的。
- 通过把应用放在system/app的目录下也可以实现。
假如com.google.gson 包中的类不允许混淆,并且项目中所有的Bean不允许混淆,但是由于项目是由多人开发,并不确定Bean所在的包,只知道Bean实现了序列化,请手动配置项目的混淆规则
1 2 | -keep class com.google.gson.** { *; }
-keep class * implements java.io.Serializable {*;}
|
手动编写gradle脚本,将libs\arm64-v8a目录下的so库及libs\gson-2.5.jar配置到项目依赖中
指定JNI文件夹为libs
1 2 3 4 5 | sourceSets{ main{ jniLibs.srcDir(['libs']) } } |
添加gson依赖
1
| compile files('libs/gson-2.5.jar')
|
Android事件传递及处理机制
- dispatchTouchEvent()事件分发
- onInterceptTouchEvent()事件拦截
- onTouchEvent()
首先由父控件接收到事件进行分发,调用拦截,返回true进行消费调用onTouchEvent,返回false则将事件传递给子控件,若子控件为ViewGroup则继续传递,最终为View时,事件无法向下传递调用onTouchEvent返回true消费,返回false,回传事件,父控件的onTouchEvent返回true消费,返回false事件丢失
无子类的View没有onInterceptTouchEvent()事件拦截方法
子线程中更新UI的方法
- 第一种:Handler+Message
-
第二种:
1 2 3 4 5 6
new Handler(context.getMainLooper()).post( new Runnable(){ public void run(){ //更新UI } });
-
第三种
1 2 3 4 5 6 7
((Activity)context)runOnUiThread( new Runnable(){ public void run(){ //更新UI } } );
postInvalidate与invalidate有什么区别?
- 都用于刷新界面
- postInvalidate()用在子线程
- invalidate()用在主线程
notifyDataSetChanged和notifyDataSetInvalidated的区别
- notifyDataSetInvalidated(),会重绘整个控件(还原到初始状态)
- notifyDataSetChanged(),重绘当前可见区域
请介绍下Android中常用的五种布局
- FrameLayout(框架布局)
- LinearLayout (线性布局)
- AbsoluteLayout(绝对布局)
- RelativeLayout(相对布局)
- TableLayout(表格布局)
Serializable和Parcelable的区别
- 都能实现序列化且可用于Intent间的数据传递
- Serializable是Java中的序列化接口,使用简单但开销大,序列化和反序列化过程需要大量I/O操作。
- Parcelable更适合Android平台,使用麻烦但效率高,主要用在内存序列化上。
文件和数据库哪个效率高
- 数据量大时使用数据库效率高
- 数据量小时使用文件效率高