android 面试题(答案)

一、android网络加载框架

Retrofit

   1、retrofit(底层用okhttp做网络处理)使用

         (1)添加依赖(在gradle中)

         (2)创建用于网络请求的接口(使用注解描述网络请求参数)

         (3)创建retrofit实例(设置网络请求url地址)

         (4)发送请求(请求分为同步请求和异步请求)

    2、retrofit添加扩展

         (1)OkhttpClient(.client(mClient))

              扩展Interceptor拦截器(addInterceptor(InterceptorUtil.LogInterceptor()))

         (2)addConverterFactory(.addConverterFactory(GsonConverterFactory.create()))

             对返回数据类型自动转换,可以自定义GsonConverterFactory,在其中可以对上传数据加密,返回数据解密

         (3)addCallAdapterFactory(.addCallAdapterFactory(RxJava2CallAdapterFactory.create()))

             把retrofit中执行的网络请求的Call对象转换为接口中定义的Call对象

     3、retrofit实现原理(动态代理、方法注解、建造者,适配器)

         (1)动态代理

             ServiceMethod 存储我们传入网络请求的所有信息,为后面是适配转换提供转换目标

             Retrofit内部默认使用OkhttpCall对象处理网络请求,返回的网络工作对象是经过适配器转换的

         (2)建造者模式(.build())

             创建OkHttpClient处理网络请求

             设置默认的callAdapterFactory(Platform中为Android系统设定 ExecutorCallAdapterFactory)

         (3)具体过程

             首先根据NetService中定义的函数,解析函数,得到函数具体定义,并生成对应的ServiceMethod

             然后根据这个ServiceMethod,实现一个OkHttpCall的Call对象,负责Retrofit底层实现网络请求

             其中,在网络访问返回的网络数据时,根据ServiceMethod实现数据转换最后,利用上一节中匹配

             的适配器,把OkhttpCall对象转换为NetService要求的Call网络请求对象

         (4)网络请求

             OkHttpCall继承的retrofit2.Call接口是为了依赖倒置解藕,真正的网络请求是有OkHttpCall内部引用的。         

             okhttp3.call处理的,这个okhttp3.call是借道ServoceMethod获取deRetrofit中的callFactory, 也就是retrofit

             中的okhttpclient,最终的网络请求是由OkHttpCall调用的OkHttpClient发出的,调用和回调过程,也就是在

             OkHttpCall处理

         (5)数据转换

            因为回调是在OkHttpCall中处理的,所以对回调数据的转换也在OkHttpCall中出发,为了符合接口函数中定义

            的返回数据类型,OkHttpCall会调用ServiceMethod来转换Response返回数据对象

            (引用:https://www.jianshu.com/p/f57b7cdb1c99)

   4、优点

       (1)可以将定义与使用分离开来

       (2)支持多种返回数据解析的Conveter快速进行数据转换

       (3)和Rxjava集成的很好

       (4)继承OkHttp优秀性能,使用Okio来大大简化数据的访问与存储,增强java.io和java.nio

           所以Retrofit性能比AsyncTask和Volley快

Volley

    1、2.3以下是Httpclient。 2.3以上基于HttpUrlconnection

    2、HttpClient存在的API数量过多,扩展困难

okhttp

   1、使用

        (1)创建okhttpClient对象

            OkhttpClient client = new OkhttpClient()

        (2)创建Request

            Request request = new Request.Builder()

                          .url(url)

                          .get()

                          .build();

         (3)创建Call对象

             Call call = client.newCall(request);

         (4)通过 execute(),enqueue()方法获得请求响应Response对象

             Response response = call.execute()


二、RxJava

    1、观察者模式

        (1)Observable(被观察者)

        (2)Observer(观察者,订阅者)

    2、异步和链式编程

        (1)Scheduler(调度器)

           observeOn(AndroidSchedulers.mainThread()) 事件回调线程

           subscribeOn(Schedulers.io()) 事件执行的线程 Schedulers.io()子线程(可以重用空闲线程)

       (2)切换线程

          subscribeOn()指定被观察者的执行线程,对前面被观察者起作用创建一个新的Observable返回

         下游,然后它重写call中,没有调用subscribe()而是直接调用了上游的call(),因为它除了切换线程之

         外并没有其他事情需要做,对同一个Observable进行多次切换线程,起作用的只有第一个线程.(多

         次执行线程切换,不论外面包多少层线程,都是在最内部线程执行的)ObservableSubscribeOn()设

         置Disposable,最重要的就是scheduler.scheduleDirect(new SubscribeTask(parent)),这个方法首

         先创建SubscribeTask,这个其实就是一个runable,在run方法里进行订阅操作

     
        observeOn()指定观察者的执行线程

        对后面的subscribe方法起作用,subscribe用了设置我们的观察者,也就是我们对于观察者发送的数据

        的处理方法执行observeOn(),先将Observable封装成ObservableObserveOn ,创建Worker封装冲

        ObserveOnObserver因为observeOn对后面的obsever起作用,所以最后subscribe执行的线程将会是最

        外面线程    


       subscribe() 

       Rxjava订阅入口,直接返回disposable,最终subscribe调用subscribeActual,最终调用到Observble的

       subscribleActual

三、Get与Post


    1、get是从服务器上获取数据,post向服务器传送数据

    2、get传送的数据量较小,不能大于2kb,post传送数据量较大,一般被默认不受限制

    3、get安全性非常低,post安全性比较高,但执行效率却比post方法好

四、图片加载框架


    1、Glide

    2、Picasso

    3、fresco

五、三级缓存


     1、网络缓存 从资源获取资源(异步加载) 网络缓存,不优先加载,速度慢,浪费流量

     2、本地缓存 从本地获取数据(File存储) 本地缓存,次优先加载,速度快

     3、内存缓存 从内存获取数据(LruCache) 内存缓存,优先加载,速度还

六、多线程应用


1、继承Thread类


                    
  (1)线程的生命周期: 
                                         
                                 

                               android 面试题(答案)_第1张图片
  (2)join()

       join()方法的作用是使所属的线程对象x正常执行run()方法中的任务,而使当前线程z进行无限期的阻

       塞,等待线程x销毁后再继续执行线程z后面的代码. join()内部调用wait(),所以join()具有释放锁的特点

  (3)wait()(等待) sleep()(睡眠)

      wait()来自Object ,释放了对象锁,使得其他线程可以使用同步控制块或方法sleep()来自Thread,没有释

      放对象锁wait(),notify(),notifyAll()必须在synchronized执行

 (4)yield()

      礼让一下别的线程

 (5)线程的终止

    1、使用标志位来突出

    2、使用interrupt()方法

          分两种状态:阻塞状况和正常情况

          阻塞情况:例如线程休眠时,使用interrupt()方法来抛出InterruptedException异常外,还会调用interrupted()

          函数,调用时能获取中断状态时true的状态,调用完之后会复位中断状态为false,所以异常抛出之后通过

          isInterrupt()获取不到中断状态时true,从而不能退出循环.

  3、stop方法

          强行终止,很危险,一般任何进行加锁的代码块,都是为了保护数据的一致性,stop()该线程所持有的锁的

          突然释放,那么被保护数据就有可能呈现不一致性,其它线程可能 使用这些被破坏的数据


2、实现Runnable接口


      此方法实现多线程,这样耦合性更低,而且可以实现类的扩展性更好,因为java类支持实现多接口

      (1)避免基础Thread类的单继承和局限性【类只能单继承,继承Thread类就不能继承其他类,而实现

           Runnable接口就可以继承其他类和实现其他接口】

      (2)降低类线程对象和线程任务的耦合性,增强了程序的扩展性【实现Runnable接口的方式,把设置线

          程任务和开启新线程进行了分离(实现解耦)实现类中,重写了run方法来设置线程任务创建Thread类

          对象,调用start方法来开启新线程创建Thread类对象,构造方法中传递Runnable接口的实现类对象,

          可以传递不同的实现类(可扩展性)】

      (3)实现Runnable接口将线程单独进行对象的封装,更符合面向对象思想。


3、Handler()(android提供用来更新UI一套机制,一套消息处理机制)

      (1)Message:消息,就是一个载体,包含消息ID,消息处理对象和消息等,统一放到MessageQueue,由Handler处理

      (2)Handler:用于同一个进程放入线程间通信,消息处理

      (3)MessageQueue插入和删除Message

      (4)Looper轮询Message

      (5)Handler发送消息调用MessageQueue的enqueueMessage向插入一条信息到MessageQueue,

          Looper不断轮询调用MessageQueue的next方法,发现message就调用handler的dispatchMessage,

          调用handlerMessage处理消息

      (6)创建新的线程,真正卡死线程操作的是在回调方法onCreate,onStart,onResume等操作时间过长

          会导致ANR,Looper.loop()本身不会导致应用卡死


4、AsyncTask


     (1)原理

          AsyncTask的实现原理 = 线程池 + Handler

          线程池用于线程调度、复用&执行任务;

          Handler用于异步通信,将工作线程的执行结果传递给主线程

    (2)核心方法

         execute(params):触发异步任务,ui线程调用

         onPreExecute()执行任务前自动调用,用于界面初始化

         doInBackground(params)执行耗时操作,不能更改ui组件,调用publishProgress()更新进度

         onProgressUpdate(progress):显示线程任务进度,调用publsihProgress(),自动调用

         onPostExecute(result)执行结果显示到ui组件,执行结束自动调用

         onCancelled():将异步设置取消状态,异步任务被取消时,自动调用

    (3)多个运行方式

         在1.6之前,AsyncTask是串行执行任务

         1.6的时候,AsyncTask是并行执行任务

         3.0开始时,AsyncTask是串行执行任务 
     

5、HandlerThread


      1、特点

          HandlerThread本质是一个线程类,它继承Thread;HandlerThread有自己的内部Looper对象,可以进行looper循环;

          通过获取HandlerThread的looper对象传递给Handler对象,可以在handleMessage,方法中执行异步任务;

          创建HandlerThread后必须先调用HandlerThread.start(),Thread会调用run方法,创建Looper对象.

      2、使用步骤
           HandlerThread handlerThread = new HandlerThread(“downloadImage”);
           handlerThread.start();
          class ChildCallback implements Handler.CallBack{
          handleMessage(Message msg){
                mUIHandler.sendMessage(msg1);
                Return false;
             }
          }
         Handler childHandler = new Handler(handlerThread.getLooper(),new ChildCallback());


6、IntentService


  1、 特点

         本质是一种特殊的Service,继承自Service并且本身就是一个抽象类,可以在后台执行耗时异步任务,

         任务完成自动停止,拥有较高优先级,适合执行较高优先级高的异步任务 内部通过HandlerThread和

         Handler实现异步任务,创建只需要onHandleIntent和构造方法,onHandleIntent为异步,可以耗时

2、与Service区别

      (1) Service中的程序运行中主程序中,IntentService中的程序运行在异步后台程序中

      (2) Service中当我们后台服务执行完毕需要在外部组件中调用stopService()销毁服务,IntentService()

           会在执行完毕后自动销毁

七、android设计模式

       1、单例模式

           (1)构造函数为private,不对外开发

           (2)通过一个静态方法返回单例对象

           (3)饿汉式,懒汉式

              饿汉式:保证线程的安全性,由于类加载的时候会创建实例,会降低内存的使用率,

                         访问量大或访问线程多的时候,使用饿汉式

             懒汉式:非线程安全,懒加载,第一次使用才会实例化单例对象, 访问量小的时候,

                         可以使用饿汉式

         (4)单例模式的使用场景

            需要频繁的进行创建和销毁的对象;

            创建对象时耗时过多或浪费资源过多,但经常用到对象

            工具类对象;

            频繁访问数据库或文件的对象


八、数据库


      1、使用 

            重写SQLiteOpenHelper——>建表(execSQL(sql))——>增删改查

      2、事物(transaction())

           使用(beginTransaction()、setTransactionSuccessful()、endTransaction())

           作用:判断事务的标记是否成功,如果不成功,回滚错误之前执行的sql语句

     3、升级

          onUpgrate():通过数据库版本比较写SQL增加表字段、创建新表等操作来到达数据库升级功能


九、集合


1、分类

     (1)List、Set两个继承Collection接口,Map为独立接口

     (2)Set下有HashSet、LinkedHashSet、TreeSet

     (3)List下有ArrayList、Vector、LinkedList

     (4)Map下有Hashtable、LinkedHashMap、HashMap、TreeMap

2、总结

     (1)List有序,可重复

         ArrayList   :底层是数组,查询快,增删慢  线程不安全,效率高

         Vector       :底层是数组、查询快、增删慢  线程安全、效率低

         LinkedList :底层是链表、查询慢、增删快  线程不安全、效率高

    (2)Set无序,唯一

        HashSet           :底层哈希表,保证唯一性的两个方法(hashCode()和equals())

        LinkedHashSet:底层是链表和哈希表、有序和元素唯一性

        TreeSet            :底层是红黑树、唯一、有序

    (3)Map

       TreeMap            :实现sortMap,能够把保存的记录按照键排序(默认生序)

       HashMap           :非线程安全,最多只允许一条记录的键为null,允许许多记录值为null

                                 (可以使用synchronziedMap或concurrentHashMap有同步能力)
       HashTable         :线程安全,不允许记录的键或值为空
       LinkedHashMap:HashMap的子类,保持记录的插入顺序


十、事件分发机制


1、dispatchTouchEvent()     事件分发方法

     (1)该方法会将根元素的事件自上而下以此分发到内层元素,返回false则不拦截继续向下分发,

2、onInterceptTouchEvent()  事件拦截方法

     (1)返回false不拦截事件,Touch事件就会向下传递给其子View返回true,事件被拦截,被当前ViewGroup处理,

    调用该OnTouchEvent()方法

3、onTouchEvent()           事件响应方法

      (1)返回true则表示该View能处理该事件,事件将终止向上传递返回false表示不能处理,则把事件传递

         给onTouchEvent()

4、总结

     (1)onTouchEvent()返回true来表示对该事件处理,返回false则没有成功处理事件,将会 将事件逐层向上传递,

        交给上层View的onTouchEvent()方法处理,依次类推,直至某一 View成功处理事件,或者到顶层View处理仍

        返回false则放弃对该事件处理,事件消失

5.onClick、onLongClick与onTouchEvent()

   (1)同一个View同时覆写了三个方法,onTouchEvent最先捕捉到ACTION_DOWN和ACTION_UP事件,其次出

       发onClick或者onLongClick

  (2)onTouch ACTION_DOWN ->onTouch ACTION_UP -> onClick

  (3)onTouch ACTION_DOWN ->onLongClick ->onTouch ACTION_UP

  (4)onTouch ACTION_DOWN ->onLongClick ->onTouch ACTION_UP ->onClick

十一、activity启动模式
     

1、standard:activity默认的启动模式,每次启动一个activity都会实例化一个activity,新创建的activity会在堆栈中的栈顶

2、singleTop:如果当前要启动的activity在栈顶的位置,那么就会复用该activity,并且不会重走oncreate(),会直接走它的

                        onNewIntent(),如果不再栈顶和standard一样,例如:推送,如果当前的activity已在前台显示,突然来了一

                       条推送,此时不想让接收推送的消息的activity再次创建,那么此时正好可以用该启动模式,如果之前activity栈中   

                       是 A-->B-->C如果点击了推动的消息还是A-->B--C,不过此时C是不会再次创建的,而是调用C的onNewIntent。而 

                       如果现在activity中栈是A-->C-->B,再次打开推送的消息,此时跟正常的启动C就没啥区别了,当前栈中就是A-- 

                       >C-->B-->C了

3、singleTask:在activity堆栈中只要一个activity,例如:一般首页用到这种启动模式

4、singleInstance:activity永远在一个单独栈里,一旦activity实例化在栈中,任何激活该activity的行为都会重启该栈中的activity

 

 

你可能感兴趣的:(android)