1.接口的意义
1.提供一种协议()
2.提高代码可维护性和扩展性
3.在团队合作中,代码规范性
2.抽象类的意义
1.为子类提供一个公共的类型
2.封装子类内重复内容(成员变量和方法)
3.定义有抽象方法,子类虽然有不同的实现,但该方法的定义是一致的。
3.哪些情况下的对象会被垃圾回收机制处理掉
1.引用计数法
2. 可达性分析算法
4.进程和线程的区别
根本区别:进程是操作系统资源分配的基本单位,而线程是任务调度和执行的基本单位
在开销方面:每个进程都有独立的代码和数据空间(程序上下文),程序之间的切换会有较大的开销;线程可以看做轻量级的进程,同一类线程共享代码和数据空间,每个线程都有自己独立的运行栈和程序计数器(PC),线程之间切换的开销小。
所处环境:在操作系统中能同时运行多个进程(程序);而在同一个进程(程序)中有多个线程同时执行(通过CPU调度,在每个时间片中只有一个线程执行)
内存分配方面:系统在运行的时候会为每个进程分配不同的内存空间;而对线程而言,除了CPU外,系统不会为线程分配内存(线程所使用的资源来自其所属进程的资源),线程组之间只能共享资源。
包含关系:没有线程的进程可以看做是单线程的,如果一个进程内有多个线程,则执行过程不是一条线的,而是多条线(线程)共同完成的;线程是进程的一部分,所以线程也被称为轻权进程或者轻量级进程。
5.java中==和equals和hashCode的区别
基本数据类型比较的是值,引用类型(接口、类、数组)运用比较的是内存中的存放地址
6.什么导致线程阻塞
1.线程睡眠Thread.sleep
2.线程等待Thread.wait(),等待notify唤醒
3.线程礼让Thread.yield()
4.线程自闭Thread.join()
5.suspend() 和 resume() 方法
7.死锁的四个必要条件
1.互斥
2.请求和保持
3.循环等待
4.不可剥夺
8.进程优先级
前台线程-》可见进程-》服务进程-》后台进程-》空进程
9.ArrayMap对比HashMap
HashMap内部采用数组+链表的形式存储数据,默认容量为16,加载因子为0.75,达到16*0.75扩容到2倍
ArrayMap适合item小于1000的场景尤其是插入数据和删除数据不频繁的情况。并且Map中放置10.容器类之间的区别
List有序
Set唯一
Map用于存储key,value
11.抽象类接口区别
12.如何导入外部数据库
数据库本质就是文件
android系统下数据库应该存放在 /data/data/com…(package name)/ 目录下
所以导入数据库其实就是文件的复制操作
用到的就是文件流FileInputStream,熟悉java的话可以轻松的完成文件的复制
13.本地广播和全局广播有什么差别
LocalBroadcastReceiver不能静态注册,只能采用动态注册的方式。
在发送和注册的时候采用,LocalBroadcastManager的sendBroadcast方法和registerReceiver方法
14.intentService作用是什么,AIDL解决了什么问题
15.如何保证Service在后台不被kill
1、Service设置成START_STICKY(onStartCommand方法中),kill 后会被重启(等待5秒左右),重传Intent,保持与重启前一样
2、通过 startForeground将进程设置为前台进程,做前台服务,优先级和前台应用一个级别,除非在系统内存非常缺,否则此进程不会被 kill.具体实现方式为在service中创建一个notification,再调用void android.app.Service.startForeground(int id,Notificationnotification)方法运行在前台即可。
3、双进程Service:让2个进程互相保护,其中一个Service被清理后,另外没被清理的进程可以立即重启进程
4、AlarmManager不断启动service。该方式原理是通过定时警报来不断启动service,这样就算service被杀死,也能再启动。同时也可以监听网络切换、开锁屏等广播来启动service。
参考实现方式如下:
Intent intent =new Intent(mContext, MyService.class);
PendingIntent sender=PendingIntent
.getService(mContext, 0, intent, 0);
AlarmManager alarm=(AlarmManager)getSystemService(ALARM_SERVICE);
alarm.setRepeating(AlarmManager.RTC_WAKEUP,System.currentTimeMillis,5*1000,sender);
该方式基本可以保证在正常运行情况下,以及任务栏移除历史任务后(小米、魅族手机除外),service不被杀死。但是360等软件管家依然可以杀死。另外还有不断启动的逻辑处理麻烦。
5、QQ黑科技:在应用退到后台后,另起一个只有 1 像素的页面停留在桌面上,让自己保持前台状态,保护自己不被后台清理工具杀死
6、在已经root的设备下,修改相应的权限文件,将App伪装成系统级的应用(Android4.0系列的一个漏洞,已经确认可行)
Android系统中当前进程(Process)fork出来的子进程,被系统认为是两个不同的进程。当父进程被杀死的时候,子进程仍然可以存活,并不受影响。鉴于目前提到的在Android-Service层做双守护都会失败,我们可以fork出c进程,多进程守护。死循环在那检查是否还存在,具体的思路如下(Android5.0以下可行)
用C编写守护进程(即子进程),守护进程做的事情就是循环检查目标进程是否存在,不存在则启动它。
在NDK环境中将1中编写的C代码编译打包成可执行文件(BUILD_EXECUTABLE)。
主进程启动时将守护进程放入私有目录下,赋予可执行权限,启动它即可。
7、联系厂商,加入白名单
16:如何优化自定义View
(1)减少不必要的代码:对于频繁调用的方法,需要尽量减少不必要的代码。
(2)不在 onDraw 中做内存分配的事:先从 onDraw 开始,需要特别注意不应该在这里做内存分配的事情,因为它会导致 GC,从而导致卡顿。在初始化或者动画间隙期间做分配内存的动作。不要在动画正在执行的时候做内存分配的事情。
(3)减少 onDraw 被调用的次数:大多数时候导致 onDraw 都是因为调用了 invalidate().因此请尽量减少调用 invaildate()的次数。如果可能的话,尽量调用含有 4 个参数的 invalidate()方法而不是没有参数的 invalidate()。没有参数的 invalidate 会强制重绘整个 view。
(4)减少 layout 的次数:一个非常耗时的操作是请求 layout。任何时候执行 requestLayout(),会使得 Android UI 系统去遍历整个View 的层级来计算出每一个 view 的大小。如果找到有冲突的值,它会需要重新计算好几次。
(5)选用扁平化的 View:另外需要尽量保持 View 的层级是扁平化的(去除冗余、厚重和繁杂的装饰效果),这样对提高效率很有帮助。
(6)复杂的 UI 使用 ViewGroup:如果你有一个复杂的 UI,你应该考虑写一个自定义的 ViewGroup 来执行他的 layout 操作。(与内置的view 不同,自定义的 view 可以使得程序仅仅测量这一部分,这避免了遍历整个 view 的层级结构来计算大小。)继承 ViewGroup作为自定义 view 的一部分,有子 views,但是它从来不测量它们。而是根据他自身的 layout 法则,直接设置它们的大小。