二、组件
1、Activity----------1
分析篇:全面了解Activity
问题:Activity生命周期及流程图;
问题:介绍Activity的几种启动模式,并简单说说自己的理解或者使用场景;
1.standard:默认标准模式,每启动一个都会创建一个实例,
2.singleTop:栈顶复用,如果在栈顶就调用onNewIntent复用,从onResume()开始
3.singleTask:栈内复用,本栈内只要用该类型Activity就会调到栈顶复用,从onResume()开始
4.singleInstance:单例模式,除了3中特性,系统会单独给该Activity创建一个栈,
问题:Activity传递参数
问题:Activity中如何动态的添加Fragment
FragmentManager mFragmentManager = getSupportFragmentManager(); //获取支持包中的FragmentManager();
ExampleFragment mExampleFragment =newmExampleFragment(); //动态添加的Fragment
FragmentTransaction fragmentTransaction = mFragmentManager.beginTransaction(); //通过beginTransaction()获取fragmentTransaction
fragmentTransaction.add(R.id.new_panel, mExampleFragment); //向view中添加指定的Fragment
fragmentTransaction.commit(); //更新完成后不要忘记了commit()哦;
知识点:锁定屏与解锁屏幕只会调用onPause(),而不会调用onStop方法,开屏后则调用onResume()(经自己实际测试小米上会调用onStop);
问题:内存不足时系统会杀掉后台的Activity,若需要进行一些临时状态的保存,在哪个方法进行
Activity的 onSaveInstanceState() 和 onRestoreInstanceState()并不是生命周期方法,它们不同于 onCreate()、onPause()等生命周期方法,它们并不一定会被触发。当应用遇到意外情况(如:内存不足、用户直接按Home键)由系统销毁一个Activity,onSaveInstanceState() 会被调用。但是当用户主动去销毁一个Activity时,例如在应用中按返回键,onSaveInstanceState()就不会被调用。除非该activity是被用户主动销毁的,通常onSaveInstanceState()只适合用于保存一些临时性的状态,而onPause()适合用于数据的持久化保存。
问题:onSaveInstanceState()被执行的场景有哪些;
系统不知道你按下HOME后要运行多少其他的程序,自然也不知道activity A是否会被销毁,因此系统都会调用onSaveInstanceState(),让用户有机会保存某些非永久性的数据。以下几种情况的分析都遵循该原则
1.当用户按下HOME键时;2.长按HOME键,选择运行其他的程序时;3.锁屏时;4.从activity A中启动一个新的activity时;5.屏幕方向切换时。
问题:Activity场景记录及恢复的原理
问题:Activity缓存方法:
1.配置改变导致Activity被杀死,横屏变竖屏:在onStop之前会调用onSaveInstanceState()保存数据在重建Activity之后,会在onStart()之后调用onRestoreInstanceState(),并把保存下来的Bundle传给onCreate()和它会默认重建Activity当前的视图,我们可以在onCreate()中,回复自己的数据。
2.内存不足杀掉Activity,优先级分别是:前台可见,可见非前台,后台。
问题:同一个应用程序的不同Activity可以运行在不同的进程中么?如果可以,举例说明;
问题:Activity怎样加速启动
1、要显示的activity的onCreate()方法中不要进行耗时操作,减小主线程的阻塞时间。初始化的一次性操作可以放到onresume中。
2、前一个activity的onpause不要做耗时操作
3、优化布局文件, 如果我们的布局层次嵌套过多,那么view绘制的时间和findViewById的时间必然会变多。
4、使用多线程异步逐渐显示view
问题:怎样退出终止APP
问题:Activity切换动画
1、在android:theme 主题里设置android:windowAnimationStyle
2、使用overridePendingTransition函数
2、Service----------1
分析篇:Service全面总结
问题:Service的生命周期,两种启动方法,有什么区别:
1.context.startService() ->onCreate()- >onStart()->Service running-->(如果调用context.stopService() )->onDestroy() ->Service shut down
1.如果Service还没有运行,则调用onCreate()然后调用onStart();
2.如果Service已经运行,则只调用onStart(),所以一个Service的onStart方法可能会重复调用多次。
3.调用stopService的时候直接onDestroy,
4.如果是调用者自己直接退出而没有调用stopService的话,Service会一直在后台运行。该Service的调用者再启动起来后可以通过stopService关闭Service。
2.context.bindService()->onCreate()->onBind()->Service running-->onUnbind() -> onDestroy() ->Service stop
1.onBind将返回给客户端一个IBind接口实例,IBind允许客户端回调服务的方法,比如得到Service运行的状态或其他操作。
2.这个时候会把调用者和Service绑定在一起,Context退出了,Service就会调用onUnbind->onDestroy相应退出。
3.所以调用bindService的生命周期为:onCreate --> onBind(只一次,不可多次绑定) --> onUnbind --> onDestory。
问题:onStartCommand()的返回值是一个很奇怪的值START_STICKY,这是个什么呢?或者说这个方法的返回值是用来干嘛的呢?
事实上,它的返回值是用来指定系统对当前线程的行为的。它的返回值必须是以下常量之一:
START_NOT_STICKY : 如果系统在 onStartCommand() 返回后终止服务,则除非有挂起 Intent 要传递,否则系统不会重建服务。这是最安全的选项,可以避免在不必要时以及应用能够轻松重启所有未完成的作业时运行服务。
START_STICKY : 如果系统在 onStartCommand() 返回后终止服务,则会重建服务并调用 onStartCommand(),但绝对不会重新传递最后一个 Intent。相反,除非有挂起 Intent 要启动服务(在这种情况下,将传递这些 Intent ),否则系统会通过空 Intent 调用 onStartCommand()。这适用于不执行命令、但无限期运行并等待作业的媒体播放器(或类似服务)。
START_REDELIVER_INTENT : 如果系统在 onStartCommand() 返回后终止服务,则会重建服务,并通过传递给服务的最后一个 Intent 调用 onStartCommand()。任何挂起 Intent 均依次传递。这适用于主动执行应该立即恢复的作业(例如下载文件)的服务。
注意点:Android5.0后隐式启动service会报Service Intent must be explicit
问题:说下IntentService原理
IntentService已经做了这些事:
创建默认的工作线程,用于在应用的主线程外执行传递给 onStartCommand() 的所有 Intent
创建工作队列,用于将一个 Intent 逐一传递给 onHandleIntent() 实现,这样的话就永远不必担心多线程问题了
在处理完所有启动请求后停止服务,从此妈妈再也不用担心我忘记调用 stopSelf() 了
提供 onBind() 的默认实现(返回 null)
提供 onStartCommand() 的默认实现,可将 Intent 依次发送到工作队列和 onHandleIntent() 实现
问题:IntentService与Service的区别
IntentService是Service的子类,是一个异步的,会自动停止的服务,很好解决了传统的Service中处理完耗时操作忘记停止并销毁Service的问题
会创建独立的worker线程来处理所有的Intent请求;
会创建独立的worker线程来处理onHandleIntent()方法实现的代码,无需处理多线程问题;
所有请求处理完成后,IntentService会自动停止,无需调用stopSelf()方法停止Service;
为Service的onBind()提供默认实现,返回null;
为Service的onStartCommand提供默认实现,将请求Intent添加到队列中;
IntentService不会阻塞UI线程,而普通Serveice会导致ANR异常
Intentservice若未执行完成上一次的任务,将不会新开一个线程,是等待之前的任务完成后,再执行新的任务,等任务完成后再次调用stopSelf()
问题:如何保证一个后台服务不被杀死;比较省电的方式是什么
分析篇:保证service不被杀死
终极解决方案:Android应对进程被杀死--Service(二)
使用Jni,在 c端 fork进程,检测Service是否存活,若Service已被杀死,则进行重启Service.
至于检测方式,可以轮询获取子进程Pid,若为1, 则说明子进程被Init进程所领养,已经成为了孤儿进程.
但是这种方式比较消耗电量,并且由于不同手机系统定制的改变,当应用被强制停止时,父进程并不一定被真正杀死,因此在一些特定机型上是无法通过此方式进行判断.这里推荐使用liunx socket的方式进行类似心跳包的检测,并且当触发检测Service是否被杀死之前,需要判断应用是否已经被卸载,如果应用已经被卸载,则不再进行检测Service行为,直接调用exit(0)退出子进程,避免浪费系统资源和消耗电量.
注意: 目前在Android5.0系统上会把fork出来的进程放到一个进程组里, 当程序主进程挂掉后,也会把整个进程组杀掉,因此用fork的方式也无法在Android5.0及以上系统实现守护进程. 这个是系统层面的限制,当然也是为了优化整个的系统环境,守护进程给手机带来的体验并不好
1、利用service自己的机制.在onStartCommand中设置参数为START_STICKY,内存不足被杀死内存有的时候会重新创建,短时间5次限制。
2、设置Android:persistent="true"。
3、提升service优先级android:priority。
4、提升service进程优先级,可以绑定通知栏成为前台服务,在service中创建一个notification,startForeground;nDestory方法中需要通过stopForeground(true)来取消前台运行状态。
5、 android:process=”com.xxx.xxxservice”配置到单独的进程中
6、onDestroy方法里重启service。
7、监听系统广播判断Service状态,手机重启、界面唤醒、应用状态改变等等监听并捕获到,然后判断我们的Service是否还存活去启动。
8、双进程Service: 让2个进程互相保护**,其中一个Service被清理后,另外没被清理的进程可以立即重启进程
9、加上两个类似于守护进程的Service, 分别检查Service的运行状态,注册响应的广播,对其进行守护,一旦发现没有运行就将其启动.我利用的系统广播是Intent.ACTION_TIME_TICK,这个广播每分钟发送一次,我们可以每分钟检查一次Service的运行状态,如果已经被结束了,就重新启动Service。它的优点就是间隔时间短而且非常稳定, 而其他的广播并不能保证这一点,当然,在具体的应用中还是要根据需求使用, 结合其他广播来保证自己的service一定会被重启.
10、通过jni调用,在c层启动多进程 fork 机制创建 Native 进程监听主进程,为纯Linux进程生命周期不受android的控制,适用于5.0以下。
(要在 Native 进程中感知主进程是否存活有两种实现方式:
10.1、在 Native 进程中通过死循环或定时器,轮训判断主进程是否存活,档主进程不存活时进行拉活。该方案的很大缺点是不停的轮询执行判断逻辑,非常耗电。
10.2、在主进程中创建一个监控文件,并且在主进程中持有文件锁。在拉活进程启动后申请文件锁将会被堵塞,一旦可以成功获取到锁,说明主进程挂掉,即可进行拉活。由于 Android 中的应用都运行于虚拟机之上,Java层的文件锁与 Linux 层的文件锁是不同的,要实现该功能需要封装 Linux 层的文件锁供上层调用。)
11、5.0以上利用 JobScheduler 机制拉活,系统会定时调用该进程以使应用进行一些逻辑操作。
12、利用账号同步机制拉活,Android 系统的账号同步机制会定期同步账号进行
13、QQ黑科技: 在应用退到后台后,另起一个只有 1 像素的页面停留在桌面上,让自己保持前台状态,保护自己不被后台清理工具杀死
14、在已经root的设备下,修改相应的权限文件,将App伪装成系统级的应用Android4.0系列的一个漏洞,已经确认可行
15、在NDK环境中将1中编写的C代码编译打包成可执行文件(BUILD_EXECUTABLE)。主进程启动时将守护进程放入私有目录下,赋予可执行权限,启动它即可。
16、联系厂商,加入白名单
问题:注册Service需要注意什么
Service还是运行在主线程当中的,所以如果需要执行一些复杂的逻辑操作,最好在服务的内部手动创建子线程进行处理,否则会出现UI线程被阻塞的问题
问题:Service与Activity怎么实现通信
方法一:
1、添加一个继承Binder的内部类,并添加相应的逻辑方法
2、Messager
3、AIDL
方法二:
通过BroadCast(广播)的形式 当我们的进度发生变化的时候我们发送一条广播,然后在Activity的注册广播接收器,接收到广播之后更新视图
3、BroadcastReceiver----------1
问题:注册广播接收器有哪几种方式,有什么区别
静态注册:在AndroidManifest.xml文件中进行注册,当App退出后,Receiver仍然可以接收到广播并且进行相应的处理
动态注册:在代码中动态注册,当App退出后,也就没办法再接受广播了
问题:如何通过广播拦截和abort一条短信;
要拦截首先设置权限:android.permission.SEND_SMS,android.permission.RECEIVE_SMS,设置receiver的优先级为最高1000,acticion为android.provider.Telephony.SMS_RECEIVED。
在4.4前,短信拦截都是通过动态注册高优先级BroadcastReceiver的方式进行拦截的,主要是用于跟竞品进行短信抢占。而现在ContenetObserver是并行通知的情况下,如果过滤逻辑不够快,依然有可能会被竞品抢先把短信先删除掉,导致拿到的最后一次短信是旧的短信。建议结合BroadcastReceiver和ContenetObserver进行拦截,BroadcastReceiver做内容校正和后备数据,以防拿到的最后一条短信是旧的时候,依然可以进行正常的拦截流程;
4.4以上引入了default sms机制,我们可以在不成为default sms的前提下实现短信拦截,利用App Ops权限管理功能,
但由于App Ops从4.3出现到4.4一直牌隐藏的状态,猜想google还在不断调整中;
Write SMS/MMS的权限开关的存在跟defaultsms本身是一个矛盾,之所以出现Write SMS/MMS的权限开关,完全是因为App Ops出现在前,而defaultsms出现在后所致。
6.0以上引入了新的动态权限管理,类似于iOS中的权限。6.0以前是在安装时一次性获取权限,6.0之后是在运行的时候选择。
问题:广播是否可以请求网络;
网络状态发生变化的时候,系统会发出 android.NET.conn.CONNECTIVITY_CHANGE,在onreceiver中使用ConnectivityManager监听网络状态,从4.0 开始所有的网络请求都需要在线程中,广播请求网络同理 开启线程在线程中请求网络
问题:广播引起anr的时间限制
10秒钟,所以在Onceive中耗时的操作一般新开线程处理
4、ContentProvider ----------1
问题:权限管理
读写分离(exported=true读设置Android:readPermission,写设置android:writePermisson
问题:权限控制-精确到表级(匹配URI),URL控制
5、Fragment ----------1
MS思考:Android面试一天一题(Day 24: 悲催的Fragment)
分析篇:Fragment 全解析
问题:Fragment生命周期
onAttach绑定activity,oncreate,onActivitycreated:Activity的onCreate方法已经执行完成并返回,onstart,onresume,onpause,onstop,onDesdroyview,onDesdroy,ondettach解除绑定;
问题:Fragment状态保存
人为返回出栈不调用onSaveInstanceState,在ondesdroy中保存(保存在能和Fragment一起共存的Argument:Bundle b = getArguments();),恢复状态在onActivityCreated中
问题:fragement里面可以再嵌套fragment?
getChildFragmentManager()
Android Fragment使用(二) 嵌套Fragments (Nested Fragments) 的使用及常见错误
6、Intent----------1
问题:显示Intent与隐式Intent的区别
对明确指出了目标组件名称的Intent,我们称之为“显式Intent”。 对于没有明确指出目标组件名称的Intent,则称之为“隐式 Intent”。
对于隐式意图,在定义Activity时,指定一个intent-filter,当一个隐式意图对象被一个意图过滤器进行匹配时,将有三个方面会被参考到:
动作(Action)
类别(Category ['kætɪg(ə)rɪ] )
数据(Data )
问题:Intent可以传递哪些数据类型
1.Serializable
2.charsequence: 主要用来传递String,char等
3.parcelable
4.Bundle
7、动画----------1
问题:Android中的动画有哪些,区别是什么
逐帧动画(Drawable Animation): 加载一系列Drawable资源来创建动画,简单来说就是播放一系列的图片来实现动画效果,可以自定义每张图片的持续时间
补间动画(Tween Animation): Tween可以对View对象实现一系列简单的动画效果,比如位移,缩放,旋转,透明度等等。但是它并不会改变View属性的值,只是改变了View的绘制的位置,比如,一个按钮在动画过后,不在原来的位置,但是触发点击事件的仍然是原来的坐标。
属性动画(Property Animation): 动画的对象除了传统的View对象,还可以是Object对象,动画结束后,Object对象的属性值被实实在在的改变了
问题:动画的原理:
1.动画的基本原理:其实就是利用插值器和估值器,来计算出各个时刻View的属性,然后通过改变View的属性来,实现View的动画效果。
2.View动画:只是影像变化,view的实际位置还在原来的地方。
3.帧动画是在xml中定义好一系列图片之后,使用AnimationDrawable来播放的动画。
4.View的属性动画:
1.插值器:作用是根据时间的流逝的百分比来计算属性改变的百分比
2.估值器:在1的基础上由这个东西来计算出属性到底变化了多少数值的类
问题:不使用动画,怎么实现一个动态的 View?
1、利用线程改变view的位置大小等
2、自定义view重绘
问题:View的补间动画有哪几种?补间动画效果的实现原理
8、ListView----------1
问题:怎么实现一个部分更新的 ListView?
intvisiblePosition = mListView.getFirstVisiblePosition();
//只有当要更新的view在可见的位置时才更新,不可见时,跳过不更新
if(itemIndex - visiblePosition >=0) {
//得到要更新的item的view
View view = mListView.getChildAt(itemIndex - visiblePosition);
问题:怎么实现ListView多种布局?
问题:ListView与数据库绑定的实现
9、View相关----------1
问题:Postvalidata与Validata有什么区别?
Validata只能在工作线程调用,Postvalidata内部使用了handler实现,可在工作线程调用
10、RecyclerView----------1
11、Scrollview----------1
问题:Scrollview怎么判断是否滑倒底部
android:怎么判断android中ScrollView滑动到了最底部?
12、Context----------1
问题:Context与ApplicationContext的区别,分别用在什么情况下
ApplicationContext的生命周期是与Application的生命周期相关的,context随着Application的销毁而销毁,伴随application的一生,与activity的生命周期无关.第二种中的context跟Activity的生命周期是相关的,但是对一个Application来说,Activity可以销毁几次,那么属于Activity的context就会销毁多次。
Application的Context是一个全局静态变量,SDK的说明是只有当你引用这个context的生命周期超过了当前activity的生命周期,而和整个应用的生命周期挂钩时,才去使用这个application的context。
在android中context可以作很多操作,但是最主要的功能是加载和访问资源。在android中有两种context,一种是 application context,一种是activity context,通常我们在各种类和方法间传递的是activity context。
在使用context的时候,小心内存泄露,防止内存泄露,注意一下几个方面:
1. 不要让生命周期长的对象引用activity context,即保证引用activity的对象要与activity本身生命周期是一样的
2. 对于生命周期长的对象,可以使用application context
3. 避免非静态的内部类,尽量使用静态类,避免生命周期问题,注意内部类对外部对象引用导致的生命周期变化
问题:Application(或者Service)和Activity都可以调用Context的startActivity方法,那么在这两个地方调用startActivity有区别吗?
Application(或者Service)需要给Intent设置Intent.FLAG_ACTIVITY_NEW_TASK才能正常启动Activity,Application(或者Service)需要给Intent设置Intent.FLAG_ACTIVITY_NEW_TASK才能正常启动Activity
问题:Context的实例是什么时候创建的?一个应用里面会有几个Context的实例?
Context数量 = Activity数量 + Service数量 + 1(Application)
问题:为什么Dialog不能用Application的Context
13、布局相关----------1
三、进程线程
1、进程----------1
问题:多进程开发以及多进程应用场景
例子:音乐播放服务,云平台客户端的同步服务
问题:多进程的好处
(1)Android系统对每个应用进程的内存占用是有限制的,占用内存越大的进程,通常被系统杀死的可能性越大。让一个组件运行在单独的进程中,可以减少主进程所占用的内存,降低被系统杀死的概率;
(2)如果子进程因为某种原因崩溃了,不会直接导致主程序的崩溃,可以降低主程序崩溃的概率;
(3)即使主进程退出了,子进程仍然可以继续工作,比如子进程是推送服务,在主进程退出的情况下,仍然能够保证用户可以收到推送消息。
问题:多进程使用场景
(1)BroadcastReceiver
一个程序发送广播,可以启动其他程序的BroadcastReceiver。拿到清单文件中BroadcastReceiver的intentFilter中的action属性值,可以在另一个应用中发送广播启动当前应用里的BroadcastReceiver。
(2)ContentProvider
一个应用通过ContentProvider向其他的应用暴露自己的数据,供其他应用访问
(3)启动其他应用的activity或者service
2、线程----------1
问题:什么时候使用CountDownLatch
问题:HandlerThread、Thread、Asynctask原理与区别
问题:生产者与消费者,手写代码 ****(多线程同步的框架的实现原理,以及如何用生产者消费者模型解决同步问题)
3、Socket编程
问题:socket短线重连怎么实现,心跳机制又是怎样实现,四次握手步骤有哪些(网络通讯原理)
4、ThreadLocal
四、数据存储
问题:数据持久化的四种方式有哪些?
文件存储: 通过java.io.FileInputStream和java.io.FileOutputStream这两个类来实现对文件的读写,java.io.File类则用来构造一个具体指向某个文件或者文件夹的对象。
SharedPreferences: SharedPreferences是一种轻量级的数据存储机制,他将一些简单的数据类型的数据,包括boolean类型,int类型,float类型,long类型以及String类型的数据,以键值对的形式存储在应用程序的私有Preferences目录(/data/data/<包名>/shared_prefs/)中,这种Preferences机制广泛应用于存储应用程序中的配置信息。
SQLite数据库: 当应用程序需要处理的数据量比较大时,为了更加合理地存储、管理、查询数据,我们往往使用关系数据库来存储数据。Android系统的很多用户数据,如联系人信息,通话记录,短信息等,都是存储在SQLite数据库当中的,所以利用操作SQLite数据库的API可以同样方便的访问和修改这些数据。
ContentProvider: 主要用于在不同的应用程序之间实现数据共享的功能,不同于sharepreference和文件存储中的两种全局可读写操作模式,内容提供其可以选择只对哪一部分数据进行共享,从而保证我们程序中的隐私数据不会有泄漏的风险
解析xml:
问题:Json有什么优劣势
分析篇:Json优劣势
1.JSON的速度要远远快于XML
2.JSON相对于XML来讲,数据的体积小
3.JSON对数据的描述性比XML较差
问题:数据库的知识,包括本地数据库优化点。