一面:
算法:
1、n!
public static int recursive(int n){
if(n<=1){
return 1;
}else{
return n*recursive(n-1);
}
}
2、实现 double base 的 int expand 次幂
public class Solution {
public double Power(double base, int exponent) {
double mul=1.0;
/* 如果exponent = 0 输出1 */
if(exponent == 0)
{
return 1.00000;
}
/* 如果base = 0 输出0 */
if(base >= -0.000001 && base <= 0.000001)
{
return 0;
}
/* 如果指数大于0 */
if(exponent > 0)
{
for(int index = 0; index < exponent; index++)
{
mul *= base;
}
}
else
{
exponent = -exponent;
for(int index = 0; index < exponent; index++)
{
mul *= base;
}
mul = 1.0/mul;
}
return mul;
}
}
retrofit原理:
反观一下Retrofit,其内部的设计结构非常清晰,
通过动态代理来处理接口,
通过OkHttp来处理网络请求,
通过CallAdapterFactory来适配OkHttpCall,
通过ConverterFactory来处理数据格式的转换,
这符合面对对象设计思想的,同时,Retrofit对CallAdpaterFactory和ConverterFactory的依赖都是依赖其接口的,这就让我们可以非常方便的扩展自己的CallAdpaterFactory和ConverterFactory,这符合;不管Retrofit内部的实现如何复杂,比如动态代理的实现、针对注解的处理以及寻找合适的适配器等,Retrofit对开发者隐藏了这些实现细节,只提供了简单的Api给开发者调用,开发者只需要关注通过的Api即可实现网络请求,这种对外隐藏具体的实现细节的思想符合。另外,Retrofit内部大量使用了设计模式,比如构造Retrofit对象时使用了,处理接口时是用来,适配OkHttpCall时使用了,生成CallAdpater和Converter时使用了。Retrofit的设计正是因为遵循了面向对象的思想,以及对设计模式的正确应用,才使得其具备结构清晰、易于扩展的特点。
怎样保证两个线程不死锁
执行顺序,避免循环等待,设置锁的超时时间
1、activity生命周期 a启动b,2、如果b是透明的
a的onpause——onstop——b的oncreate——onstart——onresume
anr异常产生,分析
当主线程在 Sleep 的时候,如果 UI线程不需要进行操作,也就是说没有消息会发送给UI线程并要求UI线程进行处理的时候 Sleep 30秒就不会导致ANR,因为没有 出现 ANR(应用没有响应)的情况啊,没有人向线程请求什么东西,也就不需要响应了,既然没有响应了,那怎么会有ANR呢?
Android N 的 ANR时间
- Service 超时
// How long we wait for a service to finish executing.
static final int SERVICE_TIMEOUT = 20*1000; // 前台
// How long we wait for a service to finish executing.
static final int SERVICE_BACKGROUND_TIMEOUT = SERVICE_TIMEOUT * 10; // 后台
- Broadcast 超时
// How long we allow a receiver to run before giving up on it.
static final int BROADCAST_FG_TIMEOUT = 10*1000; // 前台
static final int BROADCAST_BG_TIMEOUT = 60*1000; // 后台
- InputDispatching 超时
// How long we wait until we timeout on key dispatching.
static final int KEY_DISPATCHING_TIMEOUT = 5*1000;
- ContentProvider 超时
// How long we wait for an attached process to publish its content providers
// before we decide it must be hung.
static final int CONTENT_PROVIDER_PUBLISH_TIMEOUT = 10*1000;
绘制卡顿分析,解决
自行补充
除了jni,链接java和c的通信方式
除了aidl 还有hidl
使用过的设计模式:单例,代理,工厂方法,建造者
单例也会产生内存泄露,为什么
image.png不管外面传入什么Context,最终都会使用Applicaton的Context,而我们单例的生命周期和应用的一样长,这样就防止了内存泄漏。
okhttp的责任链模式有哪些
自行补充
git和svn的优缺点
1.SVN优缺点
优点:
1、 管理方便,逻辑明确,符合一般人思维习惯。
2、 易于管理,集中式服务器更能保证安全性。
3、 代码一致性非常高。
4、 适合开发人数不多的项目开发。
缺点:
1、 服务器压力太大,数据库容量暴增。
2、 如果不能连接到服务器上,基本上不可以工作,看上面第二步,如果服务器不能连接上,就不能提交,还原,对比等等。
3、 不适合开源开发(开发人数非常非常多,但是Google app engine就是用svn的)。但是一般集中式管理的有非常明确的权限管理机制(例如分支访问限制),可以实现分层管理,从而很好的解决开发人数众多的问题。
Git优缺点
优点:
1、适合分布式开发,强调个体。
2、公共服务器压力和数据量都不会太大。
3、速度快、灵活。
4、任意两个开发者之间可以很容易的解决冲突。
5、离线工作。
缺点:
1、学习周期相对而言比较长。
2、不符合常规思维。
3、代码保密性差,一旦开发者把整个库克隆下来就可以完全公开所有代码和版本信息。
tcp三次握手和四次挥手
自行补充
recycleview listview的优缺点
recycler:
1、4级缓存
2、局部刷新
3、viewholder重用
4、动画
5、列表,瀑布流,
6、自己实现onclicklistener()
listview:
1、二级缓存
2、自己实现viewholder
3、没有动画,
4、不能局部刷新
5、自定义瀑布流
怎么设计一个框架,跨平台和不跨平台的方案
业务层:具体的业务模块
组件层:网络,图片,ui,mvp,打印机,扫描,推送等,数据库等等组件
底盘层:apm,推送
SharedPreferences进程间为什么不安全
原因:只有在创建SharedPreferences对象的时候才会从磁盘中国进行读取,读取完以后值保存在内存(HashMap)当中,下次获取SharedPreferences对象优先从缓存当中获取,所以在当前进程修改了SharedPreferences的值,其他进程的SharedPreferences对象的值并不会改变。只有把当前另外的进程关闭(如:关闭手机、或杀死该app重新进入),再次创建进程时才会重新从磁盘中再次读取文件。
sp在创建的时候会把整个文件全部加载进内存,如果你的sp文件比较大,那么会带来几个严重问题:
第一次从sp中获取值的时候,有可能阻塞主线程,使界面卡顿、掉帧。
解析sp的时候会产生大量的临时对象,导致频繁GC,引起界面卡顿。
这些key和value会永远存在于内存之中,占用大量内存。
SharedPreferences 是线程安全的吗?它的 commit 和 apply 方法有什么区别
1.SharePreferences是线程安全的 里面的方法有大量的synchronized来保障。
2.SharePreferences不是进程安全的 即使你用了MODE_MULTI_PROCESS 。
3.第一次getSharePreference会读取磁盘文件,异步读取,写入到内存中,后续的getSharePreference都是从内存中拿了。
4.第一次读取完毕之前 所有的get/set请求都会被卡住 等待读取完毕后再执行,所以第一次读取会有ANR风险。
5.所有的get都是从内存中读取。
6.提交都是 写入到内存和磁盘中 。apply跟commit的区别在于
apply 是内存同步 然后磁盘异步写入任务放到一个单线程队列中 等待调用。方法无返回 即void commit 内存同步 只不过要等待磁盘写入结束才返回 直接返回写入成功状态 true or false
7.从 Android N 开始, 不再支持 MODE_WORLD_READABLE & MODE_WORLD_WRITEABLE. 一旦指定, 会抛异常 。也不要用MODE_MULTI_PROCESS 迟早被放弃。
8.每次commit/apply都会把全部数据一次性写入到磁盘,即没有增量写入的概念 。 所以单个文件千万不要太大 否则会严重影响性能。
准备好要问的问题
自行补充
greendao的优缺点
1、方便快速开发,提高效率
缺点:有些复杂sql语句不支持
事件分发机制,action_down,action_move,action_up的区别
1,ACTION_DOWN 事件决定着接下来的一系列事件的传递方向。返回TRUE ,则该一系列操作事件将由当前View的onToucheEvent 处理。返回false 事件将继续传递。直至返回Activity. Activity接收到其分发出去的ACTION_DOWN返回值false,则不再分发接下来的MOVE UP 事件。
2、dispatchTouchEvent 分两种情况:ACTION_DOWN 时return 和 ACTION_MOVE 、ACTION_UP return 。ACTION_DOWN:返回TRUE和该View 的onTouchEvent ACTION_DOWN返回true 是一样的即告诉activity 当前View可以处理接下来的事件流。 返回false 结束事件剩下的也不再传递。ACTION_MOVE 、ACTION_UP :这种情况说明其子View中已经开始处理事件流,在这里return直接导致该部分事件流不再继续传递,对于没有return的还按照正常的流程传递。
3、onInterceptTouchEvent 不论什么时候拦截,接下来的事件都将传递给当前的onTouchEvent处理接下来的事件流。例如在当前View的onInterceptTouchEvent 的ACTION_MOVE 中返回了true,则接下来的ACTION_MOVE、ACTION_UP都将传递给当前view的onTouchEvent处理。其子View将不再接收处理剩下的事件。
1.在所有的事件微观表现中,action_down是整个事件的基础,是任何宏观事件的起始事件,一旦action_down return false,表示事件继续向外层冒泡,当有某一层的action_down
中return true,表示此层消费了此action_down事件,那么在接下里的action_move、action_up等事件中,将直接先传入此层中,且不管action_move、
action_up等返回false还是true,事件都不会继续冒泡到外层。事件由此被消费掉。
2.由此可以得知,action_down在整个事件传递中的重要作用。如果某层发生了action_move或者action_up微观事件,那么一定发发生过action_down微观事件。
关于setOnTouchListener、setOnClickListener和setOnLongClickListener:
Android中,有时候经常见到针对同一控件可能设置不同的事件监听器(如setOnTouchListener、setOnClickListener和setOnLongClickListener),对于这些事件监听器的执行顺序,
setOnTouchListener是最先执行的。并且只有当此空间完整走完action_down和action_up流程后,才可能调用performClick()方法,及调用onclick执行。而onLongClick则是在action_down
之后开始,并且是在一个新的线程中去判断按压的时间,条件满足则调用performLongClick()函数,及调用onLongClick()函数。
二面:
1、怎样检测内存泄露,生产上怎么定位内存泄露
2、怎样定位native层叠内存泄露
3、bindservice和startservice的区别
4、怎样不让别人绑定我的service服务
5、音乐播放器怎样实现退出页面还可以播放
6、contentprovider插入一条数据要做那些操作
1.继承contentprovider
2.重写6个抽象方法
ContentProvider的六个抽象方法的含义分别是:
onCreate():代表ContentProvider的创建,可以用来进行一些初始化操作
getType(Uri uri):用来返回一个Uri请求所对应的MIME类型
insert(Uri uri, ContentValues values):插入数据
query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder):查询数据
update(Uri uri, ContentValues values, String selection, String[] selectionArgs):更新数据
delete(Uri uri, String selection, String[] selectionArgs):删除数据
<provider
android:name=".MyContentProvider"
android:authorities="com.czy.contentprovideremo.MyContentProvider"
android:exported="true" />
name:ContentProvider的全称类名
authorities:唯一标识了一个ContentProvider,外部应用通过该属性值来访问我们的ContentProvider。因此该属性值必须是唯一的,建议在命名时以包名为前缀
exported:表明是否允许其他应用调用ContentProvider,true表示支持,false表示不支持。默认值根据开发者的属性设置而会有所不同,如果包含 Intent-Filter 则默认值为true,否则为false
看栗子:https://www.jianshu.com/p/601086916c8f
7、数据库事务和普通操作的区别,自己怎样实现事务
8、内存泄露有哪些,handler,单例,webview,具体场景,怎样解决
handler
静态,弱引用,ondestroy移除removeallcallbacks
单例传入applicaton的context,不要使用activity的或者是fragment的
webview采用单独进程,使用完成干掉进程
9、touch的事件传递
image.png
10、怎样在子线程启动handler
创建looper:Looper.prepare()
启动looper:Looper.loop()
11、浮窗是怎么实现的,window是由什么管理的
12、什么时候复写 measure layout draw
13、measure方法是怎样将大小传递给系统的
就是那个setMeasureDimension()
image.png14、自定义控件的时候,canvas的save()和restore()的作用
save() : 用来保存Canvas的状态,save()方法之后的代码,可以调用Canvas的平移、放缩、旋转、裁剪等操作!
restore():用来恢复Canvas之前保存的状态(可以想成是保存坐标轴的状态),防止save()方法代码之后对Canvas执行的操作,继续对后续的绘制会产生影响,通过该方法可以避免连带的影响
15、home按键的事件是怎么处理的
16、音量键是怎样传递的
17、aidl的oneway的作用
oneway说明是异步调用
18、怎样获取控件大小
在oncreate的时候获取到的大小为0,需要使用
imageView.measure(0, 0);
int height = imageView.getMeasuredHeight();
int width = imageView.getMeasuredWidth();
网友评论