2019年的面试条目总结

作者: 克拉丶 | 来源:发表于2019-07-10 18:22 被阅读0次

    2019年的面试条目总结

    一.熟练对Android Q版本适配

    1. 存储沙箱化, 每个应用访问自己沙箱内的文件。访问别的沙箱解决办法类似于FileUriExposedException,用FileProvider将file转换为content传递

    2. 设备唯一id获取,谷歌开放了新的设备id获取方式,目前不同手机获取的方式不同以前的 READ_PHONE_STATE 方式变为了READ_PRIVILEGED_PHONE_STATE

    3. 非SDK接口的限制,设置禁止对非sdk接口的依赖,主要是一些第三方的热修复,加固方案使用了这些被限制的SDK接口

    4. 限制了明文流量,只有使用https才可以访问

    二.安卓各版本的新特性

    1. Android 6.0(M) ,完整的权限控制,危险权限需要动态获取。 API 检测是否有授权,申请授权,权限失败解释

    2. Android7.0 (N) , 删除了三种静态广播 网络状态新照片和新视频

    3. Android8.0(P),自适应的图标类型,推送和通知的管理

    三.Glide源码解析

    四.EventBus源码解析

    五.Arouter源码解析

    六.Retrofit源码解析

    1. Retrofit使用Retrofit.create(Class)方法创建出Service 接口对象,使retrofit可以在Service中进行参数配置

    2. 然而在Retrofit.create()方法中,是使用Proxy.newProxyInstance()方法来创建Service接口实例,这个实例实现了所有的接口方法,调用实例的InvocationHandler成员变量的invoke()方法,InvocationHandler对象就会代理接口中的是设定。

    3. invoke()中的逻辑:

      1. loadServiceMethod(method)将interface中的方法信息读取并初步分析生成ServiceMethod

      2. OkHttpCall<Object> okHttpCall = new OkhttpCall<>(serviceMethod,args)负责将ServiceMethod封装到retrofit2.call对象,该对象在enqueue等的时候会调用okhttp.call对象,由它来进行网络请求的发起

      3. serviceMethod.adapt(okHttpCall) 中,serviceMethod里面的的callAdapter对象把okHttpCall转为新的retrofit.call类型对象。这个call中,后台线程发起的请求的返回中,调用主线程回调方法。还可以生成rxjava的Obervable等

    七.Okhttp3源码解析

    1. 首先创造出一个OkhttpClient进行网络配置,然后创建一个Request传入client,client创建一个call开始发起请求。

    2. Dispatcher dispatcher:调度器,调度后台发起的网络请求,可设置主机请求数和后台请求数

      List<Protocol> protocols:支持的应用层协议版本

      List<ConnectionSpec> connectionSpecs:应用层支持的Socket设置,即使用明文传输 还是TLS

      List<Interceptor> interceptors大多数的Interceptor都会配置在这里

      List<Interceptor> networkInterceptors:直接和网络请求交互的Interceptor配置到这里

      CookieJar cookieJar:管理Cookie的控制器,提供了基础的存取判断,剩下的需要自己实现

      Cache cache:Cache 存储的配置。默认是没有,如果需要⽤,得⾃⼰配置出 Cache 存储的⽂件位置以及存储空间上限。

      HostnameVerifier hostnameVerifier:⽤于验证 HTTPS 握⼿过程中下载到的证书所属者是否和⾃⼰要访问的主机名⼀致。

      Authenticator[ɔːˈθɛntɪkeɪtə] authenticator:用于自动重新认证。配置后收到401时会直接调用authenticator,重新发起请求

    3. OKHttp3通过拦截链的设计,让请求分成5个拦截器去处理,拦截器各司其职,扩展性非常高。拦截链是从自定义的拦截器开始,然后再到默认的5个拦截器。一般情况下我们想打印网络请求日志,所以可以自定义Log拦截器,如果要给所有请求添加Header,同样可以自定义Header拦截器。

      1. 失败重试、重定向拦截器。
      2. 桥拦截器:主要是添加和删除一些header
      3. 缓存拦截器:根据缓存策略,如果缓存可用,直接返回缓存数据。
      4. 连接池拦截器:连接池会缓存http链接,连接池的好处是复用连接,少了3次握手,所以请求会更快
      5. .真正访问网络的拦截器:内部使用okio去发请求

    八.内存泄漏优化

    关于内存泄漏的全部实战解决方式

    九.熟悉TCP/IP,http/https协议,熟悉用户登录和授权以及用户行为分析等方式

    十.熟悉对称/非对称加密、hash、base64的实现方式以及相关应用

    十一.Handler和AsyncTask机制

    handler机制
    方法一:使用sendMessage()

    步骤:
    步骤一:主线程匿名内部类创建Handler对象
    步骤二:创建消息对象
    通过Message message=Message.obtain()创建一个message
    步骤三:发送消息mHandler.sendMessage(msg);

    原理:

    UI线程创建一个Handler对象,然后在子线程中sendMessage发送到在主线程的MessageQueue中,最后通过Lopper(消息泵)对象去除MessageQueue中的消息,分发回Handler的handleMessage()

    AsyncTask机制
    AsyncTask的原理 = 线程池 + Handler

    线程池用于线程的调度、复用;handler用于异步通信

    内部有一个SerialExecutor任务队列线程池(任务调度)THREAD_POOL_EXECUTOR执行线程池(真正执行任务的线程池)内部handler(异步通信+消息传递),

    类、方法的介绍

    AsynTask属于抽象类需实现子类
    execute(Params... params):触发执行异步线程任务,必需在UI线程中调用
    onPreExecute():执行线程任务前的操作执行任务前调用,如显示进度条等操作
    doInBackground(Params params):接受输入参数,执行任务中的耗时操作,返回执行结果。
    onPostExecute(Resule result):接收线程任务执行结果,显示到UI组件
    onCancelled:将异步任务设置为取消状态,doInBackground()中判断终止任务
    点击查看AsynTask原理具体说明

    原理须知:

    同步锁修饰execute()从而保证AsyncTask中的任务是串行执行的

    十二.MVC以及MVP

    MVC的步骤:

    首先用户触摸View层(比如控件xml啥的都算view)
    Controller层(Activity,Fragment)做出反应去请求
    Model层(http, 数据库,sp)的数据,然后返回数据给C层,C层收到数据后通知View层进行更新

    MVP的步骤:

    首先用户触摸View层(Activity,Fragment)如点击请求网络
    然后view层调用Presenter(桥梁层)层去Model层(网络请求数据,数据库数据,sp数据,contentProvider)拿对应的数据
    最后P层通过初始化时持有的View层引用将view的更新通知给V层

    十三.组件化、插件化

    组件化

    组件化的优秀开源项目

    插件化

    将app拆分成很多块,每个模块都是一个apk,最终打包的时候讲宿主apk和插件apk分开打包,插件apk通过动态下发到宿主apk。
    用的是VirtualAPK

    过程

    1.宿主Module中的build.gradle中添加配置apply plugin
    2.application中进行初始化
    3.适当位置加载插件

      PluginManager pluginManager = PluginManager.getInstance(base);
      File apk = new File(Environment.getExternalStorageDirectory(), "plugin.apk");
      if (apk.exists()) {
        try {
          pluginManager.loadPlugin(apk);
        } catch (Exception e) {
          e.printStackTrace();
          }
        } else {
          Toast.makeText(getApplicationContext(),"SDcard根目录未检测到plugin.apk插件", Toast.LENGTH_SHORT).show();
      }
    

    4.加载插件

    public void click(View view){
        Intent intent = new Intent();
        intent.setClassName("com.emm.plugin","com.emm.plugin.Main2Activity");
        tartActivity(intent);
    }
    
    
    原理:大致方案如下

    原生apk就可作为插件加载,插件工程编译生成apk后,即可通过宿主app加载,并在宿主中创建LoadedPlugin对象。再次启动就会变得流畅
    插件apk需要在宿主Apk中提前占坑,通过Hook Activity的启动过程,“欺上瞒下”启动插件Apk中的Activity,其他三大组件都是通过代理的方式。

    十四.TCP/IP协议簇,http/https协议,用户登录授权、行为跟踪

    应用层 HTTP 、FTP
    传输层 TCP、UDP
    网络层 IP、ICMP、ARP
    数据链路层 FDDI、IEEE 802.1A

    用户登录授权

    Cookie是由服务器端生成,服务器需要客户端保存的内容,放在Set-Cookieheaders里返回,客户端会自动保存
    客户端保存的Cookie会在之后的所有请求里携带进Cookieheader里发回给服务器
    客户端保存Cookie是按照服务器域名来分类的

    行为跟踪

    简单的说就是Cookies追踪,利用第三方cookie来实现这一的机制
    很多第三方作为跨域提供了用户的token

    十五.工厂、模板、观察者、适配器设计模式

    工厂模式:宝马和奔驰类都实现car接口,用CarFactory返回实例化接口car,相当于一个工厂可以生产不同类型的实例
    模板模式:抽象模板角色类,实现了父类所声明的基本方法。子类实现需要强制实现的逻辑
    观察者模式:
    1.抽象被观察者接口,声明添加通知删除观察者方法

    public interface Observerable {
        public void registerObserver(Observer o);
        public void removeObserver(Observer o);
        public void notifyObserver();
    }
    

    2.定义一个抽象观察者接口

    public interface Observer {
        public void update(String message);
    }
    

    3.定义被观察者,实现了Observerable接口,对接口方法进行了具体实现

    public class WechatServer implements Observerable {
        //注意到这个List集合的泛型参数为Observer接口,设计原则:面向接口编程而不是面向实现编程
        private List<Observer> list;
        private String message;
        
        public WechatServer() {
            list = new ArrayList<Observer>();
        }
        
        @Override
        public void registerObserver(Observer o) {
            
            list.add(o);
        }
        
        @Override
        public void removeObserver(Observer o) {
            if(!list.isEmpty())
                list.remove(o);
        }
    
        //遍历
        @Override
        public void notifyObserver() {
            for(int i = 0; i < list.size(); i++) {
                Observer oserver = list.get(i);
                oserver.update(message);
            }
        }
        
        public void setInfomation(String s) {
            this.message = s;
            System.out.println("微信服务更新消息: " + s);
            //消息更新,通知所有观察者
            notifyObserver();
        }
    
    }
    

    4.定义具体观察者,微信公众号具体观察者为用户User

    public class User implements Observer {
        private String name;
        private String message;
        
        public User(String name) {
            this.name = name;
        }
        
        @Override
        public void update(String message) {
            this.message = message;
            read();
        }
        
        public void read() {
            System.out.println(name + " 收到推送消息: " + message);
        }
    }
    

    5.编写一个测试类,首先注册了三个用户,ZhangSan、LiSi、WangWu。公众号发布了一条消息"PHP是世界上最好用的语言!",三个用户都收到了消息。
    用户ZhangSan看到消息后颇为震惊,果断取消订阅,这时公众号又推送了一条消息,此时用户ZhangSan已经收不到消息,其他用户

    public class Test {
        public static void main(String[] args) {
            WechatServer server = new WechatServer();
            
            Observer userZhang = new User("ZhangSan");
            Observer userLi = new User("LiSi");
            Observer userWang = new User("WangWu");
            
            server.registerObserver(userZhang);
            server.registerObserver(userLi);
            server.registerObserver(userWang);
            server.setInfomation("PHP是世界上最好用的语言!");
            
            System.out.println("----------------------------------------------");
            server.removeObserver(userZhang);
            server.setInfomation("JAVA是世界上最好用的语言!");
        }
    }
    

    适配器模式:

    十六.viewStub、ViewPager2、CoordinatorLayout

    ViewStub:宽高都为 0 的不可见 View. 通过延迟加载布局的方式优化布局提升渲染性能,通过setVisibility或者直接调用inflate都会渲染布局文件
    ViewPager2:核心为RecyclerView+LinerLayoutManager,所以支持横向和竖向的滚动,viewpager2可以承载fragment,需要继承它提供的FragmentStateAdapter,还可以完整支持notifyDataSetChanged()
    CoordinatorLayout:
    1.CoordinatorLayout继承自viewgroup,但是使用类似于framLayout,只有CoordinatorLayout的直接子布局才能响应。
    2.是需要CoordinateLayout+AppBarLayout+CollapingToolbarLayout结合才有效果。

    
    <android.support.design.widget.CoordinatorLayout
        android:id="@+id/main_content"
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
     
        <android.support.design.widget.AppBarLayout
            android:id="@+id/appbar"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">
     
            <android.support.v7.widget.Toolbar
                android:id="@+id/toolbar"
                android:layout_width="match_parent"
                android:layout_height="?attr/actionBarSize"
                android:background="?attr/colorPrimary"
                app:layout_scrollFlags="scroll|enterAlways"
                app:popupTheme="@style/ThemeOverlay.AppCompat.Light"/>
    
        </android.support.design.widget.AppBarLayout>
     
        <android.support.v7.widget.RecyclerView
            android:id="@+id/recyclerView"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            app:layout_behavior="@string/appbar_scrolling_view_behavior"/>
     
        <android.support.design.widget.FloatingActionButton
            android:id="@+id/fab"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="end|bottom"
            android:layout_margin="15dp"
            android:src="@drawable/add_2"/>
     
    </android.support.design.widget.CoordinatorLayout>
    
    1. AppBarLayout设置属性:layout_scrollFlags
      1. scroll|exitUntilCollapsed,子控件可以向上滚动出NestedScrollView父布局时会折叠到顶端
      2. scroll|enterAlways:只要向下滚动该布局就会显示出来,向上滚动该布局就会收缩
      3. scroll|enterAlwaysCollapsed:向下滚动到最低端时,该布局才会显示出来

    十七.jni使用

    使用CMake进行ndk开发,它是一种比nake更高级的编译配置工具,通过CMakeLists.txt,可以控制生成的Makefile,从而控制编译过程、生成源码包、生成当前平台安装包。

    使用流程
    1. 在java文件中创建本地方法
    2. build项目后自动生成.h文件
    3. 创建.cpp文件,实现.h文件中的方法
    4. 配置Cmake文件,生成.so文件

    十八.屏幕适配

    1. 官方适配方案:
      使用dp方式适配
      使用资源目录名加上-1920*1280等字段
      百分比布局库PercentRelativeLayoutPercentFrameLayout
            android:layout_width="0dp"
            android:layout_height="0dp"
            android:background="#ff0000"
            app:layout_heightPercent="30%"
            app:layout_widthPercent="70%"
    

    ConstraintLayout
    layout_constraintHorizontal_chainStyle
    Guideline
    layout_constraintHorizontal_bias layout_constraintVertical_bias

    1. 开源适配方案:
      今日头条适配方案px=dp*density,动态修改设备的density值,在不同分辨率下达到相同的像素密度

    十九.Arouter、RxJava

    Arouter
    RxJava

    二十.动画、svg自定义控件

    补间动画
    主要通过xml中定义具有旋转、缩放、平移、透明度的动画

    Animation animation = AnimationUtils.loadAnimation(MainActivity.this,R.anim.viewanimation);
                    textView.startAnimation(animation);
    

    属性动画
    补间动画只能定义两个关键帧在透明(alpha)、旋转(rorate)、位移(translate)和缩放(scale)这四个属性的变换,但是属性动画可以定义任何属性的变化。
    补间动画只能对 UI 组件执行动画,但属性动画可以对任何对象执行动画。
    Animator: 提供创建属性动画的基类,基本不会直接使用这个类。
    ValueAnimator:属性动画用到的主要的时间引擎,负责计算各个帧的属性值。
    ObjectAnimator: ValueAnimator 的子类,对指定对象的属性执行动画。
    AnimatorSet:Animator 的子类,用于组合多个 Animator。

    二十一.https HTTP over SSL

    定义:给HTTP增加一个安全层,用于保障HTTP的加密传输,可以接受的对称加密,非对称加密,hash算法
    Https在与服务器进行数据交互之前,会与服务器进行一次通信(握手)

    1、浏览器将自身支持的加密算法发送给服务端

    2、服务端筛选出一套加密算法,以证书的形式发给浏览器

    3、浏览器根验证证书的合法性,据拿到的证书里的公钥加密一串消息发给服务端

    4、服务端使用私钥解密信息,验证哈希,并加密响应消息给浏览器

    5、浏览器解密响应消息,并对消息进行验证,如果验证通过,则可以进行加密数据交互

    触摸事件的冲突解决

    解决触摸事件冲突:

    外部拦截。ViewGroup重写onInterceptTouchEvent方法,默认不拦截,事件往下分发给子View,若返回true,则拦截此次事件,将事件传给ViewGroup的onTouchEvent处理。
    内部拦截。重写子View的dispatchTouchEvent方法,方法中调用getParent().requestDisallowInterceptTouchEvent(true)方法,传true则代表不希望ViewGroup拦截事件,传false则代表希望ViewGroup拦截事件。
    内部拦截。子View重写onTouchEvent方法,返回true,则子View消费该次事件,返回false,该次事件返回给ViewGroup的onTouchEvent处理。

    相关文章

      网友评论

        本文标题:2019年的面试条目总结

        本文链接:https://www.haomeiwen.com/subject/aolkkctx.html