-
调用PhoneWindow中的setContentView方法
-
创建ParentView: 作为ViewGroup的子类,实际是创建的DecorView(作为FramLayout的子类)
-
将指定的R.layout.xxx进行填充 通过布局填充器进行填充【其中的parent指的就是DecorView】
-
调用到ViewGroup
-
调用ViewGroup的removeAllView(),先将所有的view移除掉
添加新的view:addView()
3、Fragment 特点
-
Fragment可以作为Activity界面的一部分组成出现;
-
可以在一个Activity中同时出现多个Fragment,并且一个Fragment也可以在多个Activity中使用;
-
在Activity运行过程中,可以添加、移除或者替换Fragment;
-
Fragment可以响应自己的输入事件,并且有自己的生命周期,它们的生命周期会受宿主Activity的生命周期影响。
4、Handler、Thread和HandlerThread的差别?
-
http://blog.csdn.net/guolin_blog/article/details/9991569
-
http://droidyue.com/blog/2015/11/08/make-use-of-handlerthread/
-
从Android中Thread(java.lang.Thread -> java.lang.Object)描述可以看出,Android的Thread没有对Java的Thread做任何封装,但是Android提供了一个继承自Thread的类HandlerThread(android.os.HandlerThread -> java.lang.Thread),这个类对Java的Thread做了很多便利Android系统的封装。
-
android.os.Handler可以通过Looper对象实例化,并运行于另外的线程中,Android提供了让Handler运行于其它线程的线程实现,也就是HandlerThread。HandlerThread对象start后可以获得其Looper对象,并且使用这个Looper对象实例Handler。
5、Launch mode应用场景
-
Standard,创建一个新的Activity。
-
SingleTop,栈顶不是该类型的Activity,创建一个新的Activity。否则,onNewIntent。
-
SingleTask,回退栈中没有该类型的Activity,创建Activity,否则,onNewIntent+ClearTop。
注意:
-
设置了"singleTask"启动模式的Activity,它在启动的时候,会先在系统中查找属性值affinity等于它的属性值taskAffinity的Task存在; 如果存在这样的Task,它就会在这个Task中启动,否则就会在新的任务栈中启动。因此, 如果我们想要设置了"singleTask"启动模式的Activity在新的任务中启动,就要为它设置一个独立的taskAffinity属性值。
-
如果设置了"singleTask"启动模式的Activity不是在新的任务中启动时,它会在已有的任务中查看是否已经存在相应的Activity实例, 如果存在,就会把位于这个Activity实例上面的Activity全部结束掉,即最终这个Activity 实例会位于任务的Stack顶端中。
-
在一个任务栈中只有一个”singleTask”启动模式的Activity存在。他的上面可以有其他的Activity。这点与singleInstance是有区别的。
singleInstance,回退栈中,只有这一个Activity,没有其他Activity。
-
SingleTop适合接收通知启动的内容显示页面。
-
例如,某个新闻客户端的新闻内容页面,如果收到10个新闻推送,每次都打开一个新闻内容页面是很烦人的。
-
singleTask适合作为程序入口点。
-
例如浏览器的主界面。不管从多少个应用启动浏览器,只会启动主界面一次,其余情况都会走onNewIntent,并且会清空主界面上面的其他页面。
-
singleInstance应用场景:
-
闹铃的响铃界面。 你以前设置了一个闹铃:上午6点。在上午5点58分,你启动了闹铃设置界面,并按 Home 键回桌面;在上午5点59分时,你在微信和朋友聊天;在6点时,闹铃响了,并且弹出了一个对话框形式的 Activity(名为 AlarmAlertActivity) 提示你到6点了(这个 Activity 就是以 SingleInstance 加载模式打开的),你按返回键,回到的是微信的聊天界面,这是因为 AlarmAlertActivity 所在的 Task 的栈只有他一个元素, 因此退出之后这个 Task 的栈空了。如果是以 SingleTask 打开 AlarmAlertActivity,那么当闹铃响了的时候,按返回键应该进入闹铃设置界面。
6、Android事件分发机制
- https://www.jianshu.com/p/38015afcdb58
7、view绘制流程
- https://www.jianshu.com/p/bb7977990baa
8、post和postDelay
9、线程同步
-
http://www.itzhai.com/java-based-notebook-thread-synchronization-problem-solving-synchronization-problems-synchronized-block-synchronized-methods.html#read-more
[收集的Android面试题,有时间看看~1、 Android dvm的进程和Linux的进程, 应用程序的进程是否为同一个概念DVM指Dalvik的虚拟机。每一个Android应用程序都在它自己的进程中
-
http://www.juwends.com/tech/android/android-inter-thread-comm.html
10、单例模式
public class Singleton {
private volatile static Singleton mSingleton;
private Singleton () {
}
public static Singleton getInstance () {
if (mSingleton == null ){
synchronized (Singleton.class){
if (mSingleton == null )
mSingleton = new Singleton();
}
}
return mSingleton;
}
}
11、什么情况导致内存泄漏
a、资源对象没关闭造成的内存泄漏
描述: 资源性对象比如(Cursor,File文件等)往往都用了一些缓冲,我们在不使用的时候,应该及时关闭它们,以便它们的缓冲及时回收内存。它们的缓冲不仅存在于 java虚拟机内,还存在于java虚拟机外。如果我们仅仅是把它的引用设置为null,而不关闭它们,往往会造成内存泄漏。因为有些资源性对象,比如 SQLiteCursor(在析构函数finalize(),如果我们没有关闭它,它自己会调close()关闭),如果我们没有关闭它,系统在回收它时也会关闭它,但是这样的效率太低了。因此对于资源性对象在不使用的时候,应该调用它的close()函数,将其关闭掉,然后才置为null.在我们的程序退出时一定要确保我们的资源性对象已经关闭。 程序中经常会进行查询数据库的操作,但是经常会有使用完毕Cursor后没有关闭的情况。如果我们的查询结果集比较小,对内存的消耗不容易被发现,只有在常时间大量操作的情况下才会复现内存问题,这样就会给以后的测试和问题排查带来困难和风险。
b、构造Adapter时,没有使用缓存的convertView
以构造ListView的BaseAdapter为例,在BaseAdapter中提供了方法: public View getView(int position, ViewconvertView, ViewGroup parent) 来向ListView提供每一个item所需要的view对象。初始时ListView会从BaseAdapter中根据当前的屏幕布局实例化一定数量的 view对象,同时ListView会将这些view对象缓存起来。当向上滚动ListView时,原先位于最上面的list item的view对象会被回收,然后被用来构造新出现的最下面的list item。这个构造过程就是由getView()方法完成的,getView()的第二个形参View convertView就是被缓存起来的list item的view对象(初始化时缓存中没有view对象则convertView是null)。由此可以看出,如果我们不去使用 convertView,而是每次都在getView()中重新实例化一个View对象的话,即浪费资源也浪费时间,也会使得内存占用越来越大。 ListView回收list item的view对象的过程可以查看: android.widget.AbsListView.java --> voidaddScrapView(View scrap) 方法。 示例代码:
public View getView ( int position, ViewconvertView, ViewGroup parent) {
View view = new Xxx(...);
... ...
return view;
}
修正示例代码:
public View getView ( int position, ViewconvertView, ViewGroup parent ) {
View view = null ;
if (convertView != null ) {
view = convertView;
populate(view, getItem(position));
...
} else {
view = new Xxx(...);
...
}
return view;
}
c、Bitmap对象不在使用时调用recycle()释放内存
有时我们会手工的操作Bitmap对象,如果一个Bitmap对象比较占内存,当它不在被使用的时候,可以调用Bitmap.recycle()方法回收此对象的像素所占用的内存,但这不是必须的,视情况而定。
d、试着使用关于application的context来替代和activity相关的context
这是一个很隐晦的内存泄漏的情况。有一种简单的方法来避免context相关的内存泄漏。最显著地一个是避免context逃出他自己的范围之外。使用Application context。这个context的生存周期和你的应用的生存周期一样长,而不是取决于activity的生存周期。如果你想保持一个长期生存的对象,并且这个对象需要一个context,记得使用application对象。你可以通过调用 Context.getApplicationContext() or Activity.getApplication()来获得。更多的请看这篇文章如何避免 Android内存泄漏。
e、注册没反注册造成的内存泄漏
一些Android程序可能引用我们的Anroid程序的对象(比如注册机制)。即使我们的Android程序已经结束了,但是别的引用程序仍然还有对我们的Android程序的某个对象的引用,泄漏的内存依然不能被垃圾回收。调用registerReceiver后未调用unregisterReceiver。 比如:假设我们希望在锁屏界面(LockScreen)中,监听系统中的电话服务以获取一些信息(如信号强度等),则可以在LockScreen中定义一个 PhoneStateListener的对象,同时将它注册到TelephonyManager服务中。对于LockScreen对象,当需要显示锁屏界面的时候就会创建一个LockScreen对象,而当锁屏界面消失的时候LockScreen对象就会被释放掉。 但是如果在释放 LockScreen对象的时候忘记取消我们之前注册的PhoneStateListener对象,则会导致LockScreen无法被垃圾回收。如果不断的使锁屏界面显示和消失,则最终会由于大量的LockScreen对象没有办法被回收而引起OutOfMemory,使得system_process 进程挂掉。 虽然有些系统程序,它本身好像是可以自动取消注册的(当然不及时),但是我们还是应该在我们的程序中明确的取消注册,程序结束时应该把所有的注册都取消掉。
f、集合中对象没清理造成的内存泄漏
我们通常把一些对象的引用加入到了集合中,当我们不需要该对象时,并没有把它的引用从集合中清理掉,这样这个集合就会越来越大。如果这个集合是static的话,那情况就更严重了
#####12、ANR定位和如何避免?
1.如果开发机器上出现问题,我们可以通过查看/data/anr/traces.txt即可,最新的ANR信息在最开始部分。
2.主线程被IO操作(从4.0之后网络IO不允许在主线程中)阻塞。
3.主线程中存在耗时的计算
4.主线程中错误的操作,比如Thread.wait或者Thread.sleep等 Android系统会监控程序的响应状况,一旦出现下面两种情况,则弹出ANR对话框
5.应用在5秒内未响应用户的输入事件(如按键或者触摸)
6.BroadcastReceiver未在10秒内完成相关的处理
7.Service在特定的时间内无法处理完成 20秒
避免
1.使用AsyncTask处理耗时IO操作。
2.使用Thread或者HandlerThread时,调用Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND)设置优先级,否则仍然会降低程序响应,因为默认Thread的优先级和主线程相同。
3.使用Handler处理工作线程结果,而不是使用Thread.wait()或者Thread.sleep()来阻塞主线程。
4.Activity的onCreate和onResume回调中尽量避免耗时的代码
5.BroadcastReceiver中onReceive代码也要尽量减少耗时,建议使用IntentService处理。
####13、什么情况导致OOM以及如何避免?
http://blog.csdn.net/yangxuehui1990/article/details/44994763
http://blog.csdn.net/ljx19900116/article/details/50037627
####14、Android Service与Activity之间通信的几种方式?
通过Binder对象
通过Broadcast(广播)的形式
####15、如何保证service在后台尽量不被kill
onStartCommand方法,返回START_STICKY
1.START_STICKY 在运行onStartCommand后service进程被kill后,那将保留在开始状态,但是不保留那些传入的intent。不久后service就会再次尝试重新创建,因为保留在开始状态,在创建 service后将保证调用onstartCommand。如果没有传递任何开始命令给service,那将获取到null的intent。
2.START_NOT_STICKY 在运行onStartCommand后service进程被kill后,并且没有新的intent传递给它。Service将移出开始状态,并且直到新的明显的方法(startService)调用才重新创建。因为如果没有传递任何未决定的intent那么service是不会启动,也就是期间onstartCommand不会接收到任何null的intent。
3.START_REDELIVER_INTENT 在运行onStartCommand后service进程被kill后,系统将会再次启动service,并传入最后一个intent给onstartCommand。直到调用stopSelf(int)才停止传递intent。如果在被kill后还有未处理好的intent,那被kill后服务还是会自动启动。因此onstartCommand不会接收到任何null的intent。
提升service优先级
在AndroidManifest.xml文件中对于intent-filter可以通过android:priority="1000"这个属性设置最高优先级,1000是最高值,如果数字越小则优先级越低,同时适用于广播。
提升service进程优先级
Android中的进程是托管的,当系统进程空间紧张的时候,会依照优先级自动进行进程的回收。Android将进程分为6个等级,它们按优先级顺序由高到低依次是:
前台进程( FOREGROUND_APP)
可视进程(VISIBLE_APP )
次要服务进程(SECONDARY_SERVER )
后台进程 (HIDDEN_APP)
内容供应节点(CONTENT_PROVIDER)
空进程(EMPTY_APP)
当service运行在低内存的环境时,将会kill掉一些存在的进程。因此进程的优先级将会很重要,可以使用startForeground 将service放到前台状态。这样在低内存时被kill的几率会低一些。
onDestroy方法里重启service
service+broadcast方式,就是当service走ondestory的时候,发送一个自定义的广播,当收到广播的时候,重新启动service;
Application加上Persistent属性
监听系统广播判断Service状态
####16、RequestLayout,onLayout,onDraw,DrawChild区别与联系
1.requestLayout()方法 :会导致调用measure()过程 和 layout()过程 。说明:只是对View树重新布局layout过程包括measure()和layout()过程,不会调用draw()过程,但不会重新绘制 任何视图包括该调用者本身。
2.onLayout()方法(如果该View是ViewGroup对象,需要实现该方法,对每个子视图进行布局)
3.调用onDraw()方法绘制视图本身(每个View都需要重载该方法,ViewGroup不需要实现该方法)
4.drawChild()去重新回调每个子视图的draw()方法
####17、invalidate()和postInvalidate() 的区别及使用
http://blog.csdn.net/mars2639/article/details/6650876
####18、LinearLayout对比RelativeLayout
RelativeLayout会让子View调用2次onMeasure,LinearLayout 在有weight时,也会调用子View2次onMeasure
RelativeLayout的子View如果高度和RelativeLayout不同,则会引发效率问题,当子View很复杂时,这个问题会更加严重。如果可以,尽量使用padding代替margin。
在不影响层级深度的情况下,使用LinearLayout和FrameLayout而不是RelativeLayout。