字节跳动教育部门Android社招一面二面经验

一面:

算法:

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 超时
    static final int SERVICE_TIMEOUT = 20*1000; // 前台
    

static final int SERVICE_BACKGROUND_TIMEOUT = SERVICE_TIMEOUT * 10; // 后台

- Broadcast 超时

static final int BROADCAST_FG_TIMEOUT = 101000; // 前台
static final int BROADCAST_BG_TIMEOUT = 60
1000; // 后台

- InputDispatching 超时

static final int KEY_DISPATCHING_TIMEOUT = 5*1000;

- ContentProvider 超时

static final int CONTENT_PROVIDER_PUBLISH_TIMEOUT = 10*1000;

####绘制卡顿分析,解决

自行补充

####除了jni,链接java和c的通信方式
除了aidl 还有hidl

####使用过的设计模式:单例,代理,工厂方法,建造者

####单例也会产生内存泄露,为什么
![image.png](https://uploadfiles.nowcoder.com/files/20200503/258100_1588473892555_648225-662426595c1a7015.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、怎样检测内存泄露,生产上怎么定位内存泄***r>2、怎样定位native层叠内存泄***r>3、bindservice和startservice的区别
4、怎样不让别人绑定我的service服务
5、音乐播放器怎样实现退出页面还可以播放
6、contentprovider插入一条数据要做那些操作
7、数据库事务和普通操作的区别,自己怎样实现事务
8、内存泄露有哪些,handler,单例,webview,具体场景,怎样解决
9、touch的事件传递
10、怎样在子线程启动handler
11、浮窗是怎么实现的,window是由什么管理的
12、什么时候复写 measure layout draw
13、measure方法是怎样将大小传递给系统的
14、自定义控件的时候,canvas的savecanvas和restorecanvas的作用
15、home按键的事件是怎么处理的
16、音量键是怎样传递的
17、aidl的oneway的作用

#字节跳动社招内推Android一二面##字节跳动##社招##内推##面经##Android#
全部评论
activity生命周期 a启动b,应该是这样吧: a的onpause——b的oncreate——onstart——onresume——a的onstop,为了让b尽快展示所以a的onstop是要在最后吧
点赞 回复
分享
发布于 2020-05-27 16:30

相关推荐

5 40 评论
分享
牛客网
牛客企业服务