Android面试-自己使用(一)

#Android基础

##Activity的启动模式

4种启动模式

  • standard:标准模式,也是系统默认的启动模式。假如 activity A 启动了 activity B , activity B 则会运行在 activity A 所在的任务栈中。而且每次启动一个 Activity ,都会重新创建新的实例,不管这个实例在任务中是否已经存在。

  • singleTop:栈顶复用模式。假如 activity A 启动了 activity B ,就会判断 A 所在的任务栈栈顶是否是 B 的实例。如果是,则不创建新的 activity B 实例而是直接引用这个栈顶实例,同时 onNewIntent 方法会被回调,通过该方法的参数可以取得当前请求的信息;如果不是,则创建新的 activity B 实例。

  • singleTask:栈内复用模式。只要栈中已经存在了该 Activity 的实例,就会直接调用 onNewIntent() 方法来实现重用实例。重用时,直接让该 Activity 的实例回到栈顶,并且移除之前它上面的所有 Activity 实例。

  • singleInstance:单实例模式。这个是 singleTask 模式的加强版,它除了具有 singleTask 模式的所有特性外,它还有一点独特的特性,那就是此模式的 Activity 只能单独地位于一个任务栈,不与其他 Activity 共存于同一个任务栈。

##广播静态注册和动态注册的区别

  • 动态注册广播不是常驻型广播,也就是说广播跟随 Activity 的生命周期。注意在 Activity 结束前,移除广播接收器。 静态注册是常驻型,也就是说当应用程序关闭后,如果有信息广播来,程序也会被系统调用自动运行。
  • 当广播为有序广播时:优先级高的先接收(不分静态和动态)。同优先级的广播接收器,动态优先于静态
  • 同优先级的同类广播接收器,静态:先扫描的优先于后扫描的,动态:先注册的优先于后注册的。
  • 当广播为默认广播时:无视优先级,动态广播接收器优先于静态广播接收器。同优先级的同类广播接收器,静态:先扫描的优先于后扫描的,动态:先注册的优先于后册的。

##service的启动方式

  • startService ()

    其它组件调用 startService() 启动一个 Service。一旦启动,Service 将一直运行在后台,即使启动这个 Service 的组件已经被销毁。通常一个被 start 的 Service 会在后台执行单独的操作,也并不需要给启动它的组件返回结果。只有当 Service 自己调用 stopSelf() 或者其它组件调用 stopService() 才会终止.

  • bindServices()

其它组件可以调用 bindService() 来绑定一个 Service。这种方式会让 Service 和启动它的组件绑定在一起,当启动它的组件销毁的时候,Service 也会自动进行 unBind 操作。同一个 Service 可以被多个组件绑定,只有所有绑定它的组件都进行了 unBind 操作,这个 Service 才会被销毁。

##Handle机制

Handler机制中,相关的这几个类:Message、MessageQueue,Looper。

  • Message: Message 中有两个成员变量:target 和 callback。

target 其实就是发送消息的 Handler 对象
callback 是当调用 handler.post(runnable) 时传入的 Runnable 类型的任务。post 事件的本质也是创建了一个 Message,将我们传入的这个 runnable 赋值给创建的Message的 callback 这个成员变量。

  • MessageQueue: 消息队列很明显是存放消息的队列,值得关注的是 MessageQueue 中的 next() 方法,它会返回下一个待处理的消息。

  • **Looper **: Looper 消息轮询器其实是连接 Handler 和消息队列的核心。如果想要在一个线程中创建一个 Handler,首先要通过 Looper.prepare() 创建 Looper,之后还得调用 Looper.loop()开启轮询。

     prepare()。 这个方法做了两件事:首先通过ThreadLocal.get()获取当前线程中的Looper,如果不为空,则会抛出一个RunTimeException,意思是一个线程不能创建2个Looper。如果为null则执行下一步。第二步是创建了一个Looper,并通过 ThreadLocal.set(looper)。将我们创建的Looper与当前线程绑定。这里需要提一下的是消息队列的创建其实就发生在Looper的构造方法中。
    
    
     loop()。 这个方法开启了整个事件机制的轮询。它的本质是开启了一个死循环,不断的通过 MessageQueue的next()方法获取消息。拿到消息后会调用 msg.target.dispatchMessage()来做处理。msg.target 其实就是发送这个消息的 handler。这句代码的本质就是调用 handler的dispatchMessage()。
    
  • Handler: Handler 的分析着重在两个部分:发送消息和处理消息。

发送消息。其实发送消息除了 sendMessage 之外还有 sendMessageDelayed 和 post 以及 postDelayed 等等不同的方式。但它们的本质都是调用了 sendMessageAtTime。在 sendMessageAtTime 这个方法中调用了 enqueueMessage。在 enqueueMessage 这个方法中做了两件事:通过 msg.target = this 实现了消息与当前 handler 的绑定。然后通过 queue.enqueueMessage 实现了消息入队。

处理消息。 消息处理的核心其实就是dispatchMessage()这个方法。这个方法里面的逻辑很简单,先判断 msg.callback 是否为 null,如果不为空则执行这个 runnable。如果为空则会执行我们的handleMessage方法。

###Handle的关键问题:

能否在子线程创建Handle:

→   能  需要创建handle的时候准备一个Looper,使用Looper.prepare() 获取 Looper或者getMainLoop()来获取主线程启动时候给我准备好的Looper.

→  不能  原因是: 子线程需要准备一个Looper,会报错.

##Android与 js 是如何交互的

在 Android 中,Android 与js 的交互分为两个方面:Android 调用 js 里的方法、js 调用 Android 中的方法。

###Android调js: Android 调 js 有两种方法:

  1. WebView.loadUrl(“javascript:js中的方法名”)。 这种方法的优点是很简洁,缺点是没有返回值,如果需要拿到js方法的返回值则需要js调用Android中的方法来拿到这个返回值。

  2. WebView.evaluateJavaScript(“javascript:js中的方法名”,ValueCallback)。
    这种方法比 loadUrl 好的是可以通过 ValueCallback 这个回调拿到 js方法的返回值。
    缺点是这个方法 Android4.4 才有,兼容性较差。

###js 调 Android: js 调 Android有三种方法:

  1. WebView.addJavascriptInterface()。 这是官方解决 js 调用 Android 方法的方案,需要注意的是要在供 js 调用的 Android 方法上加上 @JavascriptInterface 注解,以避免安全漏洞。这种方案的缺点是 Android4.2 以前会有安全漏洞,不过在 4.2 以后已经修复了。

  2. 重写 WebViewClient的shouldOverrideUrlLoading()方法来拦截url, 拿到 url 后进行解析,如果符合双方的规定,即可调用 Android 方法。优点是避免了 Android4.2 以前的安全漏洞,缺点也很明显,无法直接拿到调用 Android 方法的返回值,只能通过 Android 调用 js 方法来获取返回值。

  3. 重写 WebChromClient 的 onJsPrompt() 方法,同前一个方式一样,拿到 url 之后先进行解析,如果符合双方规定,即可调用Android方法。最后如果需要返回值,通过 result.confirm(“Android方法返回值”) 即可将 Android 的返回值返回给 js。方法的优点是没有漏洞,也没有兼容性限制,同时还可以方便的获取 Android 方法的返回值。其实这里需要注意的是在 WebChromeClient 中除 了 onJsPrompt 之外还有 onJsAlert 和 onJsConfirm 方法。那么为什么不选择另两个方法呢?原因在于 onJsAlert 是没有返回值的,而 onJsConfirm 只有 true 和 false 两个返回值,同时在前端开发中 prompt 方法基本不会被调用,所以才会采用 onJsPrompt。

##Android 中如何捕获未捕获的异常

  • UncaughtExceptionHandler

    自 定 义 一 个 Application , 比 如 叫 MyApplication 继 承 Application 实 现UncaughtExceptionHandler。
    覆写 UncaughtExceptionHandler 的 onCreate 和 uncaughtException 方法。 注意:上面的代码只是简单的将异常打印出来。在 onCreate 方法中我们给 Thread 类设置默认异常处理 handler,如果这句代码不执行则一切都是白搭。在 uncaughtException 方法中我们必须新开辟个线程进行我们异常的收集工作,然后将系统给杀死。
    在 AndroidManifest 中配置该 Application:<application android:name=“com.example.uncatchexception.MyApplication”

  • Bug 收集工具 Crashlytics

    Crashlytics 是专门为移动应用开发者提供的保存和分析应用崩溃的工具。国内主要使用的是友盟做数据统计。
    Crashlytics 的好处:
    1.Crashlytics 不会漏掉任何应用崩溃信息。
    2.Crashlytics 可以象 Bug 管理工具那样,管理这些崩溃日志。
    3.Crashlytics 可以每天和每周将崩溃信息汇总发到你的邮箱,所有信息一目了然。

#框架问题

##网络框架

  • okhttp和Retrofit的对比

###okHttp的特点:

1.OkHttp特性:它的设计和实现的首要目标便是高效,有如下特性:

• 支持SPDY、连接池、Gzip和Http缓存

• 支持SPDY,因此可以同一IP多个连接共享同一个socket(SPDY并不是一种用于替代HTTP的协议,而是对HTTP协议的增强);

• 在Http/2不可用时, 连接池可极大减少延时;

• 支持Gzip压缩响应体,降低传输内容的大小;

• 支持Http缓存,避免重复请求;

• 服务器配置多IP情况下,当前IP请求失败,支持自动切换到其他IP;

• 使用Okio来简化数据的访问与存储,提高性能;

• OkHttp还处理了代理服务器问题和SSL握手失败问题

缺点:

•  是消息回来需要切到主线程,主线程要自己去写。
•  调用比较复杂,需要自己进行封装。
•  缓存失效:网络请求时一般都会获取手机的一些硬件或网络信息,比如使用的网络环境。同时为了信息传输的安全性,可能还会对请求进行加密。

在这些情况下OkHttp的缓存系统就会失效了,导致用户在无网络情况下不能访问缓存

缓存失效解决方案:先过滤可变参数,然后进行手动缓存;不要使用随网络状态变化的参数;

###Retrofit优缺点优点:

优点:

•  可以配置不同HTTP client来实现网络请求,如okhttp、httpclient等;

•  请求的方法参数注解都可以定制;

•  支持同步、异步和RxJava;

•  超级解耦;

•  可以配置不同的反序列化工具来解析数据,如json、xml等;

•  使用非常方便灵活;

•  框架使用了很多设计模式

缺点:

• 不能接触序列化实体和响应数据;

• 执行的机制太严格;

• 使用转换器比较低效;

• 只能支持简单自定义参数类型

##图片加载框架 Glide

Glide读缓存时机就是先内存缓存查找再到磁盘缓存查找最后网络,写入缓存则就是在获取到原始source图片之后,先写入磁盘缓存,再加入内存缓存.

###三级缓存原理

当 Android 端需要获得数据时比如获取网络中的图片,首先从内存中查找(按键查找),内存中没有的再从磁盘文件或sqlite中去查找,若磁盘中也没有才通过网络获取

####LruCache 底层实现原理:

LruCache 中 Lru 算法的实现就是通过 LinkedHashMap 来实现的。LinkedHashMap 继承于 HashMap,它使用了一个双向链表来存储 Map中的Entry顺序关系

对于get、put、remove等操作,LinkedHashMap除了要做HashMap做的事情,还做些调整Entry顺序链表的工作。

LruCache中将LinkedHashMap的顺序设置为LRU顺序来实现LRU缓存,每次调用get(也就是从内存缓存中取图片),则将该对象移到链表的尾端。
调用put插入新的对象也是存储在链表尾端,这样当内存缓存达到设定的最大值时,将链表头部的对象(近期最少用到的)移除

视频播放框架

  • ijkplayer

Ijkplayer 是Bilibili发布的基于 FFplay 的轻量级 Android/iOS 视频播放器。实现了跨平台功能,API 易于集成;编译配置可裁剪,方便控制安装包大小;支持硬件加速解码,更加省电;提供 Android 平台下应用弹幕集成的解决方案。

  • ExoPlayer

ExpPlayer是一个开源的,App等级的媒体API,它的开源项目包含了library和示例:ExoPlayer library - 这部分是核心的库

  • GSYVideoPlayer

视频播放器,支持基本的拖动,声音、亮度调节,支持边播边缓存,支持视频本身自带rotation的旋转(90,270之类),重力旋转与手动旋转的同步支持,支持列表播放 ,直接添加控件为封面,列表全屏动画

MVP与MVC

  • MVC全名是Model–View–Controller,是模型(model)-视图(view)-控制器(controller)的缩写,一种软件设计典范,用一种业务逻辑、数据、界面显示分离的方法组织代码,在改进和个性化定制界面及用户交互的同时,不需要重新编写业务逻辑。其中Model层处理数据,业务逻辑等;View层处理界面的显示结果;Controller层起到桥梁的作用,来控制View层和Model层通信以此来达到分离视图显示和业务逻辑层。我们一般理解为Activity为MVC模式中的Controller.

  • MVP其实是MVC的一种演进版本,它更简单,将MVC中的Controller改为了Presenter,View通过接口与Presenter进行交互,降低耦合,方便进行单元测试。

View:负责绘制UI元素、与用户进行交互(Activity、View、Fragment都可以做为View层);

Model:对数据的操作、对网络等的操作,和业务相关的逻辑处理;

Presenter:作为View与Model交互的中间纽带,处理与用户交互的逻辑。可以把Presenter理解为一个中间层的角色,它接受Model层的数据,并且处理之后传递给View层,还需要处理View层的用户交互等操作。

项目问题

视频压缩:

常见的视频压缩都是使用ffmpeg方案(FFMPEG技术),集成fdk-aac与264编码,使用NDK编译成需要的so库,依赖导入进来.

##视频上传: 七牛+上传到阿里云的oss上.

  • 上传到七牛,需要先获取七牛云的UploadToken,获取Uploadtoken之后进行适配上传.

  • 上传到阿里云的oss : 首先要获取根据阿里云开通的oss服务中找打 END_POINT 、BUCKET_NAME 、Access Key ID、Access Key Secret 等信息,通过oss服务上的这些参数来获取临时访问的权限,获取权限后再进行上传.

适配问题:

适配的方案+ 全面屏适配+刘海屏适配+虚拟导航栏适配

方案:

##官方方案:

  1. 使用dp来根据使用中屏幕的实际密度按需要以透明方式处理 dp 单位的任何缩放.编写代码的大小使用dp来指定.

  2. dimens:通过脚本把既定分辨率按比例生成dimen供引用

  3. 使用百分比布局支持库

  4. 使用ConstraintLayout

全面屏适配 步骤:

1.声明最大屏幕高宽比
清单文件添加:

2.根据是否显示虚拟导航键进行适配:

window.setNavigationBarColor (int color)

三级缓存

三级缓存 那三种缓存;

我们一般是直接数据请求来获取我们需要的数据,也就是网络加载 之后我们保存到磁盘中, 还有就是保存在我们的内存中,

三级缓存就是: 网络加载 磁盘缓存和内存缓存

顺序就是:

 	if(内存缓存){
     加载内存缓存中的数据
	}elseif(磁盘缓存){
	加载磁盘缓存
	}else{
最后是网络加载, 保存到内存和磁盘缓存中
}

我们常说的lru算法和lrucache 是使用在内存缓存中的;

lrucache 使用的算法就是 lru 全名是: last recently use 最近最少使用原则;

内部使用的是 LinkedHashMap(内部是一个数组加双向链表的形式来存储数据,也就是说当我们通过get方法获取数据的时候,数据会从队列跑到队头来。反反复复,队尾的数据自然是最少使用到的数据。)来进行保存,当内存满的使用会使用算法,将最近最少使用的算法进行清理.

磁盘缓存是保存在磁盘上的,常见的有sp保存等.

持久化数据保存

1 使用SharedPreferences存储数据;
2 文件存储数据;xml,json
3 SQLite数据库存储数据;
4 使用ContentProvider存储数据;
5 网络存储数据;

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值