大学还没毕业,却很幸运地收到一家公司的offer,这是我努力去面试的结果,原以为我将会走在同学们的前面一点点,可是好景不长,收到公司的通知----我被炒了!这种心情真的...唉,还是不说了。又要开始准备面试了,既然要准备面试,顺带也整理一下面试内容吧!
Activity的生命周期
先上一张大众图片
Activity的生命周期有七个过程,onCreate、onStart、onRestart,onResume、onPause、onStop、onDestroy。这样说谁都会,但是你知道所以然吗?下面我解析一下,也是从网上查找出来的。
1、启动Activity:系统会调用onCreate方法,然后调用onStart方法,最后调用onResume,Activity进入运行状态。
2、当前Activity被其他Activity覆盖其上或锁屏:系统会调用onPause方法,暂停当前Activity的执行。
3、当前Activity由被覆盖状态回到前台或锁屏:系统会调用onResume方法,再次进入运行状态
4、当前Activity转到新的Activity界面或Home键回到主屏,自身退居后台:系统会先调用onPause方法,然后调用onStop方法,进入停滞状态。
5、用户后退回到此Activity:系统会先调用onRestart方法,然后调用onStart方法,最后调用onResume方法,再次进入运行状态
6、当前Activity处于被覆盖状态或者后台不可见状态,即第二步和第四步,系统内存不足,杀死当前Activity,而后用户退回当前Activity,再次调用onCreate方法,onStart方法、onResume,进入运行状态。
7、用户退出当前Activity:系统先调用onPause方法,然后调用onStop方法,最后调用onDestroy方法,结束当前Activity。
Fragment的生命周期
启动Fragment的时候,先onAttach、onCreate、onCreateView、onActivityCreated、onStart、onResume;
屏幕灭掉的时候,onPause,onSaveInstanceState、onStop
屏幕解锁的时候,先onStart,onResume
切换到其他Fragment,onPause,onStop、onDestroyView
切换回本身的Fragment,onCreateView,onActivityCreated、onStart、onResume
回到桌面、onPause、onSaveInstanceState、onStop
回到应用,onStart、 onResume
退出应用 ,onPause,onStop,onDestroyView, onDestroy, onDetach
ANR
ANR的定义:在Android上,如果你的应用有一段时间不够灵敏,系统会像用户显示一个对话框,这个对话框称作应用程序无响应(ANR:Application Not Responding)对话框,用户可以选择用程序继续运行,但是,他们在使用你的应用程序时,并不希望每次都要处理这个对话框。因此,在程序对相应性能的设计很重要,这样,系统不会显示ANR给用户。
不同组件发生ANR的时间不一样,主线程Activity是5s,BroadCaseReceive是10s。那么解决方案都有哪些呢,其实我觉得没有具体的解决方案,只是你编程的时候注意些,严谨一点,将所有的耗时操作都放在子线程里去操作。如果耗时操作确实要用户等待,那我觉得在显示界面上展示一个进度条是个不错的选择。
什么情况会导致Force Close ?如何避免?能否捕获导致其的异常?
导致出现Force Close(强行关闭)的原因有很多,比如NullPointExection(空指针)IndexOutOfBoundsException(角标越界),使用的类没有找到,使用的资源没有找到,或者调用Android api的时候使用顺序错误也有可能导致、
避免forceclose方案:首先是尽可能的保证程序不出现这些异常,如果有些异常实在不可避免而又不想让程序弹出forceclose弹窗,可以使用UncaughtExceptionHandler。当程序出现未捕获异常时会去调用UncaughtExctionHandler中的uncaughtException方法,我们要做的就是实现UncaughtExceptionHandler类,自行处理未捕获异常,代码请看处理forcelose问题。
横竖屏切换时候activity的生命周期
这个面试题网上到处都有,但是实际面试中好像没有遇到过。1、不设置Activity的android:configChanges时,切屏会重新调用各个生命周期,切横屏时会执行一次,切竖屏时会执行两次;2、设置Activity的android:configChanges="orientation"时,切屏还是会重新调用各个生命周期,切横、竖屏时只会执行一次;3、设置Activity的android:configChanges="orientation|keyboardHidden"时,切屏不会重新调用各个生命周期,只会执行onConfigurationChanged方法
Handler 、 Looper 、Message 有什么关系
这三者都与Android异步消息处理线程相关的概念。那什么是异步消息处理线程呢?异步消息处理线程启动后会进入一个无限循环体之中,没循环一次,从其内部的消息队列中取出一个消息,然后回调相应的消息处理函数,执行完成一个消息后则继续循环。若消息队列为空,线程则会阻塞等待。其实Looper负责的就是创建一个MessageQueue(消息队列),然后进入一个无限循环体不断从该MessageQueue中读取消息,而消息的创建者就是一个或多个Handler 。
对Android NDK的理解
Android NDK 是在SDK前面又加上了“原生”二字,即Native Development Kit,因此又被Google称为“NDK”。
还有些理解就是:1、NDK是系列工具的集合;2、NDK提供了一份稳定、功能有限的API头文件声明;3、使“Java + C”的开发方式正式终于转正,成为官方支持的开发方式;4、NDK将是Android平台支持C开发的开端
四大组件,五大存储、六大布局
Android的四大组件是activity,service、contentprovider、broadcastreceiver,这四个组件都需要在配置文件(AndroidManifest.xml)中声明,他们之间通过是用Intent进行通信。
activity通常就是一个单独的界面(窗口或屏幕),它是一种可以包含用户界面的组件,主要用于和用户进行交互
service
(1)service用于在后台完成用户指定的操作。service分为两种:
(a)started(启动):当应用程序组件(如activity)调用startService()方法启动服务时,服务处于started状态。
(b)bound(绑定):当应用程序组件调用bindService()方法绑定到服务时,服务处于bound状态。
(2)startService()与bindService()区别:
(a)started service(启动服务)是由其他组件调用startService()方法启动的,这导致服务的onStartCommand()方法被调用。当服务是started状态时,其生命周期与启动它的组件无关,并且可以在后台无限期运行,即使启动服务的组件已经被销毁。因此,服务需要在完成任务后调用stopSelf()方法停止,或者由其他组件调用stopService()方法停止。
(b)使用bindService()方法启用服务,调用者与服务绑定在了一起,调用者一旦退出,服务也就终止,大有“不求同时生,必须同时死”的特点。
(3)开发人员需要在应用程序配置文件中声明全部的service,使用标签。
(4)Service通常位于后台运行,它一般不需要与用户交互,因此Service组件没有图形用户界面。Service组件需要继承Service基类。Service组件通常用于为其他组件提供后台服务或监控其他组件的运行状态。
content provider
(1)android平台提供了Content Provider使一个应用程序的指定数据集提供给其他应用程序。其他应用可以通过ContentResolver类从该内容提供者中获取或存入数据。
(2)只有需要在多个应用程序间共享数据是才需要内容提供者。例如,通讯录数据被多个应用程序使用,且必须存储在一个内容提供者中。它的好处是统一数据访问方式。
(3)ContentProvider实现数据共享。ContentProvider用于保存和获取数据,并使其对所有应用程序可见。这是不同应用程序间共享数据的唯一方式,因为android没有提供所有应用共同访问的公共存储区。
(4)开发人员不会直接使用ContentProvider类的对象,大多数是通过ContentResolver对象实现对ContentProvider的操作。
(5)ContentProvider使用URI来唯一标识其数据集,这里的URI以content://作为前缀,表示该数据由ContentProvider来管理。
broadcast receiver
(1)你的应用可以使用它对外部事件进行过滤,只对感兴趣的外部事件(如当电话呼入时,或者数据网络可用时)进行接收并做出响应。广播接收器没有用户界面。然而,它们可以启动一个activity或serice来响应它们收到的信息,或者用NotificationManager来通知用户。通知可以用很多种方式来吸引用户的注意力,例如闪动背灯、震动、播放声音等。一般来说是在状态栏上放一个持久的图标,用户可以打开它并获取消息。
(2)广播接收者的注册有两种方法,分别是程序动态注册(非常驻型,广播跟随程序的生命周期)和AndroidManifest文件中进行静态注册(常驻型,当应用程序关闭后,如果有信息广播来,程序也会被系统调用自动运行。)。
(3)动态注册广播接收器特点是当用来注册的Activity关掉后,广播也就失效了。静态注册无需担忧广播接收器是否被关闭,只要设备是开启状态,广播接收器也是打开着的。也就是说哪怕app本身未启动,该app订阅的广播在触发时也会对它起作用
五中存储方式有SharedPreferences、文件存储、SQLite方式、内容提供器(Content provider)和网络存储。SharedPreferences只能保存在当前应用并且被当前应用使用。文件存储是用Android提供的openFileInput和openFileOutput方法读取设备上的文件。SQLite是Android所带的一个标准的数据库,它支持SQL语句。ContentProvider两个程序之间对于数据进交换。外界的程序通过ContentResolver接口可以访问ContentProvider提供的数据,在Activity当中通过getContentResolver()可以得到当前应用的ContentResolver实例。
LinearLayout(线性布局)、TableLayout(表格布局)、FragmeLayout(帧布局)、RelativeLayout(相对布局)、GridLayout(网络布局)、AbsoluteLayout(绝对布局)。虽然Android上有这些布局,但是说实在的,我用最多的就是线性布局和相对布局,其他的几乎没有用过。
Android中的动画有哪几类?
两种,一种是Tween动画,还有一种是Frame动画。Tween动画,这种实现方式可以使视图组件移动、放大、缩小以及产生透明度的变化,Tween动画在Android中分为4类,它们分别是:AlphaAnimation(透明度动画)、TranslateAnimation(平移动画)、ScaleAnimation(缩放动画)、RotateAnimation(旋转动画)。都继承自android.view.Animation类,它们都是表示从一个状态A向状态B变化的一个过程,所以英文名字叫Tween动画、中文名叫:“补间动画”、“中间动画”;另一种Frame动画,传统的动画方法,通过顺序的播放排列好的图片来实现,类似电影。
socktet、tcp/ip、http
TCP/IP协议是一个协议集合,TCP/IP协议按照层次分为以下四层:应用层、传输层、网络层、数据链路层。http是超文本传输协议,是互联网上应用最广泛的以一种网络协议,所有www文件都遵循这个标准。socktet的中文名是套接字,它是网络上的两个程序通过一个双向的通信连接实现数据的交换,这个连接的一端称为一个socktet。
MVC
MVC是Model View Controller,即模型-视图-控制器,是一种软件框架模式。它是用一种业务逻辑、数据与界面显示分离的方法来组织代码,将众多的业务逻辑聚集到一个部件里面,在需要改进和个性化定制界面及用户交互的同时,不需要重新编写业务逻辑,达到减少编码的时间。同时它还提高了应用系统的可维护性,可扩展性、可移植性和组件的可复用性。(为了达到编码的最高境界,那就是:低藕合,高复用,易测试,好维护。)这里有位大神写的非常好,附上链接mvp模式是你的救命稻草吗?
MVP
理解Activity,View,Window三者关系
都是主要用于显示并与用户交互的。view主要是用于绘制我们想要的结果,是一个最基本的ui组件;window简单来说是一个窗口,它的大小取决于屏幕的大小,但不是绝对的,如对话框等。可以将window理解为一个容器,里面“盛放”这很多view,这view是以树形结构组织起来的。activity相当于一个界面,可以直接在其里面处理事件。
四种LaunchMode及其使用场景
standard模式,这是默认模式,每次激活activity时都会创建Activity实力,并放入任务栈中,这是大都数Activity都使用的模式。
singleTop 模式,如果任务的栈顶正好存放在该Activity的实例,就重用该实例( 会调用实例的 onNewIntent() )否则就会创建新的实例并放入栈顶,即使栈中已经存在该Activity的实例,只要不在栈顶,都会创建新的实例。使用场景如新闻类或者阅读类App的内容页面。
singleTask 模式,如果在栈中已经有该Activity的实例,就重用该实例(会调用实例的 onNewIntent() )。重用时,会让该实例回到栈顶,因此在它上面的实例将会被移出栈。如果栈中不存在该实例,将会创建新的实例放入栈中。使用场景如浏览器的主界面。不管从多少个应用启动浏览器,只会启动主界面一次,其余情况都会走onNewIntent,并且会清空主界面上面的其他页面
singleInstance 模式,在一个新栈中创建该Activity的实例,并让多个应用共享该栈中的该Activity实例。一旦该模式的Activity实例已经存在于某个栈中,任何应用再激活该Activity时都会重用该栈中的实例( 会调用实例的 onNewIntent() )。其效果相当于多个应用共享一个应用,不管谁激活该 Activity 都会进入同一个应用中。使用场景如闹铃提醒,将闹铃提醒与闹铃设置分离。singleInstance不要用于中间页面,如果用于中间页面,跳转会有问题,比如:A -> B (singleInstance) -> C,完全退出后,在此启动,首先打开的是B。
Touch事件传递机制
public boolean dispatchTouchEvent(MotionEventev); //用来分派eventpublic boolean onInterceptTouchEvent(MotionEventev);//用来拦截eventpublic boolean onTouchEvent(MotionEventev);//用来处理event
其中Activity和View控件(TextView)拥有分派和处理事件方法,View容器(LinearLayout)具有分派,拦截,处理事件方法。这里也有个比喻:领导都会把任务向下分派,一旦下面的人把事情做不好,就不会再把后续的任务交给下面的人来做了,只能自己亲自做,如果自己也做不了,就只能告诉上级不能完成任务,上级又会重复他的过程。另外,领导都有权利拦截任务,对下级隐瞒该任务,而直接自己去做,如果做不成,也只能向上级报告不能完成任务。
跨进程通讯的几种方式
1、访问其他应用的Activity,如调用系统通话应用2、ContentProvider,即访问系统相册3、广播,如显示系统时间4、AIDL服务。
什么是AIDL呢?
关于Context,这里有篇很好的文章Context
关于Intent
Intent是一个传递消息的对象,可以为Intent制定action来启动其他应用,它是Android四大组件通信的桥梁,比如启动Activity,启动Service等等。Intent有两种类,一种是显式:通过指定具体类名启动一个组件。显式Intent一般用于同一应用程序内,因为您可以确定地知道要启动的组件名。另外,Android 5.0以后规定必须显式启动Service。
一种是隐式:当希望启动具备某种特性的组件时,可以使用隐式Intent,隐式Intent无需指定类名,通常用于启动其他应用程序的组件,比如您打算启动一个地图定位的activity。
Activity意外退出时,如何进行数据保存和恢复?
onSaveInstanceState方法,创建一个Bundle类型参数,吧数据存储在这个Bundle对象中,这样即使Activity意外退出的时候或者被系统摧毁,当重新启动这个Activity而调用onCreate方法是,上述Bundle对象会作为参数转递给onCreate方法,开发者可以从Bundle对象中取出保存的数据,利用这些数据将Activity恢复到被摧毁之前的状态。
什么是OOM?如何避免OOM?
oom,想必大多数人都遇到这样的情况,它的概念是内存溢出,内存占有量超过了java虚拟机分配的最大内存。比如创建或解析Bitmap,分配特大的数组等。避免oom:1、避免对activity的超过生命周期的引用(尽量使用application代替activity)2、在展示高分辨率图片时,先将图片进行压缩到与空间大小相近。3、及时释放不使用的Bitmap,动态回收内存,方法:bitmap.recycle()4、对适配器视图进行优化处理,避免过多加载数据和对象的生成
异步方式
常见的实现异步方式有:AsyncTask、Thread+Handler
常见的耗时操作有哪些:网络请求,数据库操作,复杂的运算等
子线程更新ui的基本方法有哪些:1、Thread + Handler的方式 2、Activity提供的一个简便的方式来更新UI runOnUiThread(Runnable r); 3、Handler里边也提供简便的更新UI的方式handler.post(Runnable r);
runOnUiThread为什么可以用来更新UI?该方法内部做了判断当前线程是否为UI线程的操作不是UI线程则将该action添加到mHandler所在的UI线程的消息队列中是UI线程,则直接执行。
什么情况下会导致内存泄露
内存泄漏的根本原因:长生命周期的对象持有短生命周期的对象,短生命周期就无法及时释放。I、静态集合类引起内存泄露主要是hashmap,Vector等,如果是静态集合 这些集合没有及时setnull的话,就会一直持有这些对象。II.remove 方法无法删除set集 Objects.hash(firstName, lastName);经过测试,hashcode修改后,就没有办法remove了。III. observer 我们在使用监听器的时候,往往是addxxxlistener,但是当我们不需要的时候,忘记removexxxlistener,就容易内存leak。广播没有unregisterrecevierIV.各种数据链接没有关闭,数据库contentprovider,io,sokect等。cursorV.内部类:java中的内部类(匿名内部类),会持有宿主类的强引用this。所以如果是new Thread这种,后台线程的操作,当线程没有执行结束时,activity不会被回收。Context的引用,当TextView 等等都会持有上下文的引用。如果有static drawable,就会导致该内存无法释放。VI.单例单例 是一个全局的静态对象,当持有某个复制的类A是,A无法被释放,内存leak。