美文网首页
android面试基础汇集

android面试基础汇集

作者: 那个那个谁哇 | 来源:发表于2019-05-05 15:17 被阅读0次

    Kotlin

    Kotlin跟Java比,kotlin具有哪些优势?
    1、Kotlin语言简练,
    2、更安全,Kotlin里面可以没有空指针问题,在Android中使用Java就会存在很多令人头大的空指针问题
    3、完全与java互操作

    kotling特性
    lambda以及高阶函数
    kotlin扩展函数、属性
    kotlin博客

    Java

    android中的java面试题
    接口与抽象的区别
    深拷贝与浅拷贝
    ArrayList和LinkedList的区别
    List、Set、Map

    image.png
    image.png
    image.png
    Java实现线程同步的几种方式
    volatile和synchronized的区别
    泛型
    java中equals,hashcode和==的区别
    final、finally、finalize的区别
    Java中的注解
    Dalvik虚拟机与java虚拟机的区别

    android事件分发机制详解

    handler消息机制

    Design Support Library

    Android Design Support Library v28 新增组件详解

    Android Design Support Library v28 新增组件详解kotlin

    https://www.jianshu.com/p/94ceeb8bbf87

    android自定义view1

    android自定义view2

    android图片压缩方法

    Android四大组件分别是哪些?各自有什么作用和特点?

    活动(Activity):Activity是Android程序与用户交互的窗口,是Android构造中最基本的一种,它需要为保持各界面的状态,做很多持久化的事情,妥善管理生命周期以及一些跳转逻辑。
    服务(Service):后台服务于Activity,封装有一个完整的功能逻辑实现,接受上层指令,完成相关的事务,定义好需要接受的Intent提供同步和异步接口。
    内容提供者(Content Provider):是Android提供的第三方应用数据的访问方案,可以派生Content Provider类,对外提供数据,可以像数据库一样进行选择排序,屏蔽内部数据的存储细节,向外提供统一的接口模型,大大简化上层应用,对数据的整合提供了更方便的途径。
    广播接收器(BroadCast Receiver):接受一种或者多种Intent作触发时间,接受相关消息,做一些简单处理,转换成一条Notification,统一了Android的事件广播模型。(如接受系统通知,向通知栏发送消息)

    activity的生命周期

    image.png

    onCreate :创建Act实例时调用。通常进行一些数据的初始化,比如获取控件、申请数组或集合的内存、变量赋值
    onRestart : Act停留在onStop但是没有onDestory
    onStart :该方法在onCreate或者onRestart之后调用,调用之后,Act进入可视生命周期
    onResume : onStart之后调用,调用该方法后Act进入活动(运行、前台)状态,可以和用户进行交互,比如响应用户的输入、点击、触摸等操作
    onPause :在onResume之后,调用该方法,此Act就不能继续和用户交互,用户自定义的一些数据可以在此方法中进行保存
    onStop : onPause之后进行调用,一旦调用onStop,Act就退出了可视状态,但是Act实例并没有销毁
    onDestroy :此方法是在销毁Act的时候调用,一旦调用表明该Act实例的生命周期就结束了,通常会在此方法做一些释放资源的操作,比如将引用变量值置为null

    Activity的四种加载(启动)模式分别是?各自有什么特点?

    standard:特点是每一次启动该Act时,会重建一个新的该Act实例
    singleTop:特点是每一次该Act时,检查栈顶是否存在该Act的实例 存在:则直接重用该Act实例 不存在:则需要新建一个该Act的实例
    singleTask:特点是每一次启动该Act时,需要在栈中去检查栈中是否存在该Act的实例 存在: 在栈顶:直接复用该Act的实例 不在栈顶:首先要把其上的Act实例移除掉,使该Act的实例回到栈顶去,然后再复用该Act的实例 不存在:新建一个该Act的实例
    singleInstance:看进程中是否有该Act实例 存在:直接从该独享栈中取出该Act的实例复用 不存在:新建一个栈,然后新建一个该Act的实例,放入该栈中

    什么是OOM?如何避免OOM?

    OOM概念:内存溢出(OutOfMemor),内存占有量超过了JVM分配的最大内存。
    避免OOM:
    <1.避免对activity的超过生命周期的引用(尽量使用application代替activity)。 因为程序一般是由很多个Activity构成的,从一个Activity跳转了以后, 系统就有可能回收这个Activity的各种内存占用。可是此时如果你的一些不可回收变量(比如静态变量)保持了对此Activity对象的引用, 那么GC就不会对此Activity进行回收,无故占用了大量的内存。这种情况最好的办法就是用application代替activity。 用Context.getApplicationContext() 或者 Activity.getApplication()可以很方便的得到application对象。
    <2.在展示高分辨率图片时,先将图片进行压缩到与空间大小相近,Luban压缩框架。
    <3.及时释放不使用的Bitmap,动态回收内存,方法:bitmap.recycle()。
    <4.对适配器视图进行优化处理,避免过多加载数据和对象的生成。

    Activity意外退出时,如何进行数据保存和恢复?

    答: 开发者提前可以复写onSaveInstanceState方法,创建一个Bundle类型的参数,把数据存储在这个Bundle对象中,这样即使Activity意外退出,Activity被系统摧毁,当重新启动这个Activity而调用onCreate方法时,上述Bundle对象会作为参数传递给onCreate方法,开发者可以从Bundle对象中取出保存的数据,利用这些数据将Activity恢复到被摧毁之前的状态。

    什么是ANR?产生ANR的原因是什么?如何避免ANR的发生?

    ANR概念: 应用程序无响应(application not response)。
    原因: 主线程中做了非常耗时的操作。
    解决办法:
    <1.运行在主线程里的任何方法都尽可能少做事情,尽量用Handler来处理UIthread和别的thread之间的交互;
    <2.应用程序应该避免在BroadcastReceiver里做耗时的操作或计算;
    <3.避免在BroadcastReceiver里启动一个Activity,因为它会创建一个新的画面,并从当前用户正在运行的程序上抢夺焦点;

    Service的两种使用方式分别是什么?它们的生命周期分别怎样迁移?

    答:
    方式1:通过startService,Service会经历onCreate->onStart,stopService的时候直接onDestroy
    方式二:通过bindService,Service只会运行onCreate,这个时候TestServiceHolder和TestService绑定在一起,TestServiceHolder退出了,Srevice就会调用onUnbind->onDestroyed

    什么是AIDL?AIDL的作用是什么?它的基本使用流程是怎么样的?

    答:AIDL是一种android内部进程通信接口的描述语言,通过它我们可以定义进程间的通信接口
    作用:
    1、多个应用程序之间建立共同的服务机制;
    2、通过AIDL在不同应用程序之间达到数据的共享和数据相互操作;
    3、主要是用于多应用之间的数据交互(而 在单个应用内或者说该应用如果不需要和其它第三方应用进行交互则不需要实现aidl接口);
    流程:
    1、编写aidl文件
    2、编写自己的Service
    3、在自己的Service的onBind方法中,将aidl文件生成的类中的Stud的子类返回(需要继承Stud重写接口方法)
    4、在AndroidManifest.xml中配置你的Service类,示例 注意:service android:name="com.aidl.SerachService"中,android:name属性必须填写你的Service的名字,包括包名,不能写aidl生成的类的名字,因为那不是个Servic
    5、编写调用aidl服务的客户端
    6、把之前编写的aidl文件(注意不是生成的java文件)和它的包目录拷贝到客户端的src目录中
    7、在需要的地方用一下方法绑定,new Intent构造器中的action填写的就是之前<action android:name="com.aidl.ISerachService" />中的android:name的字符串

    什么是BroadcastReceiver?它有什么作用?

    答:BroadcastReceiver是Android四大组件之一,本质是一种 全局的监听器,用于监听系统全局的广播消息。因此它可以非常方便的实现不同组件之间的通信。 作用:通过该机制,使得消息能在各个组件间、各个进程间传递,起到邮递员的作用。

    什么是有序广播?有序广播有什么特点?什么是系统广播?

    有序广播:是通过Context.sendOrderedBroadcast来发送。所有的receiver依次执行。 有序广播特点即从优先级别最高的广播接收器开始接收,接收完了如果没有丢弃,就下传给下一个次高优先级别的广播接 收器进行处理,依次类推,直到最后。 系统广播:当系统发生事件时,就会发送出广播,通过广播中的关键字段,系统将寻找所有关注这个广播的应用,并触发他们注册的Receiver

    什么是粘性广播?它跟普通广播有什么区别?

    定义:没有注册的接收者,在后来注册后也能收到广播,进程间通信 当发布该广播后它还驻留在周围,它可以让其他接收者迅速的检索到数据,通过一个方法的(动态注册接收者方法)返回值 这个返回值就是意图
    粘性广播的特点是Intent会一直保留到广播事件结束,而这种广播也没有所谓的10秒限制,10秒限制是指普通的广播如果onReceive方法执行时间太长,超过10秒的时候系统会将这个广播置为可以干掉的candidate,一旦系统资源不够的时候,就会干掉这个广播而让它不执行。

    Broadcast注册方式与区别

    1、代码动态注册:
    实例化自定义的广播接收者
    实例化意图过滤器,并设置要过滤的广播类型(如,我们接收收到短信系统发出的广播)
    使用Context的registerReceiver(BroadcastReceiver, IntentFilter, String, Handler)方法注册广播
    2、在Manifest.xml中静态注册
    不同点:
    1.第一种不是常驻型广播,也就是说广播跟随程序的生命周期。
    2.第二种是常驻型,也就是说当应用程序关闭后,如果有信息广播来,程序也会被系统调用自动运行。
    无序广播:所有的接收者都会接收事件,不可以被拦截,不可以被修改。
    有序广播:按照优先级,一级一级的向下传递,接收者可以修改广播数据,也可以终止广播事件。

    什么是ContentProvider?如何自定义一个ContentProvider?

    ContentProvider(内容提供者)是Android中的四大组件之一。主要用于对外共享数据,也就是通过ContentProvider把应用中的数据共享给其他应用访问,其他应用可以通过ContentProvider对指定应用中的数据进行操作。
    1)ContentProvider为存储和获取数据提供了统一的接口。ContentProvide对数据进行封装,不用关心数据存储的细节。使用表的形式来组织数据。
    2)使用ContentProvider可以在不同的应用程序之间共享数据。 总的来说使用ContentProvider对外共享数据的好处是统一了数据的访问方式。
    自定义ContentProvider: 编写一个类,必须继承自ContentProvider类; 实现ContentProvider类中的所有的抽象方法; onCreate();getType();query();Insert();update();delete();等方法 在清单文件中声明注册ContentProvider <provider android:name=".MyWordsprovider" android:authorities="heying.provider.wordsconetenprovider" android:exported="true" /> 将Uri提供出去

    常用的数据持久化(长久保存数据)方式有哪些?

    1、SharedPreference,共享参数形式,一种以Key-Value的键值对形式保存数据的方式,Android内置的,一般应用的配置信息 ,推荐使用此种方式保存,不能存文件也不适合。其存储的位置在/data/data/packageName/shared_prefs文件夹下面。
    2、Internal Storage:把数据存储到手机内部的存储空间,主要用来保存私有数据/data/data/packageName/files文件夹下 面
    3、External Storage:把数据存储到手机的外部存储SD卡中,主要用来保存非私有和大型数据,它有应用程序专用的文件夹 ,也有所有程序公用的文件夹(这个文件夹不会随着应用程序的卸载而卸载),需要赋予应用程序访问Sdcard的权限,Android的权限 控制尤为重点,在Android程序中,如果需要做一些越界的操作,均需要对其进行授权才可以访问。在AndroidManifest.xml中添加代码 :<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>   4、SQLite Databases:以表格形式存储信息的一个轻量级的小型数据库
    5、Network Connection:将数据存储到网络服务器上
    6、ContentProvider:他提供一种方式实现两个不同应用程序之间的通讯

    ShareedPrefrence的读写数据的基本方法?

    它保存的数据主要是简单类型的Key-value对。并且Value部分只能是一些基本数据类型:boolean、float、int、long、String等 。

    SQLiteOpenHelper的作用是什么?

    SQLiteOpenHelper主要是用来创建数据库和表格,以及为数据库升级的作用。在Android系统中,既然可以通过Context类的 openOrCreateDatabase()函数打开或创建SQLite数据库,并且可以通过其返回值(即SQLiteDatabase对像)调用execSQL()函数对数据 库做任何的操作(CRUD),

    AsyncTask中几个回调方法运行在哪个线程、DoInBackGround执行在哪个线程?

    4个回调方法,其中三个运行在主线程(初始化,UI更新,进度条更新),DoInBackGround运行在子线程
    doInBackground:必须重写,异步执行后台线程要完成的任务,耗时操作将在此方法中完成.
    onPreExecute:执行后台耗时操作前被调用,通常用于进行初始化操作.
    onPostExecute:当doInBackground方法完成后,系统将自动调用此方法,并将doInBackground方法返回的值传入此方法.通过此方法进行UI的更新.
    onProgressUpdate:当在doInBackground方法中调用publishProgress方法更新任务执行进度后,将调用此方法.通过此方法我们可以知晓任务的完成进度.

    runOnUiThread为什么可以用来更新UI?

    该方法内部做了判断当前线程是否为UI线程的操作 不是UI线程则将该action添加到mHandler所在的UI线程的消息队列中,使用Handler+Thread的方式在子线程更新UI时,Handler对象可以在子线程中创建吗?不能,只能在主线程创建,再传到子线程中

    Handler的post方法为什么可以用来更新UI?

    该方法内部实际上是发送一个延迟的消息给该线程的Handler处理,该方法内部将消息对象加入了消息队列,最终也是把Runnable对象给放到了UI线程中执行,如果是更新UI,则这个Handler对象必须创建在UI线程中

    handler

    在使用handler的时候,在handler所创建的线程需要维护一个唯一的Looper对象, 每个线程对应一个Looper,每个线程的Looper通过ThreadLocal来保证与相应线程对应
    Looper对象的内部又维护有唯一的一个MessageQueue,所以一个线程可以有多个handler,
    但是只能有一个Looper和一个MessageQueue。
    Message在MessageQueue不是通过一个列表来存储的,而是将传入的Message存入到了上一个
    Message的next中,在取出的时候通过顶部的Message就能按放入的顺序依次取出Message。
    Looper对象通过loop()方法开启了一个死循环,不断地从looper内的MessageQueue中取出Message,
    然后通过handler将消息分发传回handler所在的线程。

    view的事件分发:

    image.png

    dispatchTouchEvent:进行事件的分发(传递)。返回值是 boolean 类型,受当前onTouchEvent和下级view的dispatchTouchEvent影响
    onInterceptTouchEvent:对事件进行拦截。该方法只在ViewGroup中有,View(不包含 ViewGroup)是没有的。一旦拦截,则执行ViewGroup的onTouchEvent,在ViewGroup中处理事件,而不接着分发给View。且只调用一次,所以后面的事件都会交给ViewGroup处理。
    onTouchEvent:进行事件处理。

    scroller实现滚动:

    image.png

    处理事件冲突:

    外部拦截法:指点击事件都先经过父容器的拦截处理,如果父容器需要此事件就拦截,否则就不拦截。具体方法:需要重写父容器的onInterceptTouchEvent方法,在内部做出相应的拦截。

    内部拦截法:指父容器不拦截任何事件,而将所有的事件都传递给子容器,如果子容器需要此事件就直接消耗,否则就交由父容器进行处理。具体方法:需要配合requestDisallowInterceptTouchEvent方法。

    view的绘制流程:

    先measure测量,用于确定View的测量宽高,再 layout布局,用于确定View的最终宽高和四个顶点的位置,最后 draw绘制,用于将View 绘制到屏幕上

    · MeasureSpec封装了从父级传递给子级的布局要求。 每个MeasureSpec代表宽度或高度的要求。

    · MeasureSpecs实现为32位的int,由size和mode组成,高2位代表mode,低30位代表size,它通过将mode和size打包成一个int值来减少对象内存分配,并提供打包和解包的方法。

    · mode分类:

    · UNSPECIFIED:父容器不对View有任何限制,给它想要的任何尺寸。一般用于系统内部,表示一种测量状态。

    · EXACTLY:父容器已经检测出view的精确大小,这时候view的大小就是size所指定的值。它对应于LayoutParams中的match_parent和具体数值两种模式。

    · AT_MOST:父容器指定了一个可用大小,即size,子view的大小不能大于这个值,具体值要看vew的实现

    SurfaceView和View的区别?

    SurfaceView是从View基类中派生出来的显示类,他和View的区别有:
    View需要在UI线程对画面进行刷新,而SurfaceView可在子线程进行页面的刷新
    SurfaceView在底层已实现双缓冲机制,而View没有,因此SurfaceView更适用于需要频繁刷新、刷新时数据处理量很大的页面

    invalidate()和postInvalidate()的区别?

    invalidate()与postInvalidate()都用于刷新View,主要区别是invalidate()在主线程中调用,若在子线程中使用需要配合handler;而postInvalidate()可在子线程中直接调用

    请介绍下Android中常用的五种布局。

    常用五种布局方式,分别是:FrameLayout(框架布局),LinearLayout (线性布局),AbsoluteLayout(绝对布局),RelativeLayout(相对布局),TableLayout(表格布局)。新加个约束布局减少布局嵌套,提高性能

    一、FrameLayout:所有东西依次都放在左上角,会重叠,这个布局比较简单,也只能放一点比较简单的东西。
    二、LinearLayout:线性布局,每一个LinearLayout里面又可分为垂直布局(android:orientation="vertical")和水平布局(android:orientation="horizontal" )。当垂直布局时,每一行就只有一个元素,多个元素依次垂直往下;水平布局时,只有一行,每一个元素依次向右排列。
    三、AbsoluteLayout:绝对布局用X,Y坐标来指定元素的位置,这种布局方式也比较简单,但是在屏幕旋转时,往往会出问题,而且多个元素的时候,计算比较麻烦。
    四、RelativeLayout:相对布局可以理解为某一个元素为参照物,来定位的布局方式。
    五、TableLayout:表格布局,每一个TableLayout里面有表格行TableRow,TableRow里面可以具体定义每一个元素。每一个布局都有自己适合的方式

    android中的动画有哪几类,它们的特点和区别是什么种,

    一种是Tween动画、Frame动画、属性动画。
    Tween动画:这种实现方式可以使视图组件移动、放大、缩小以及产生透明度的变化;
    Frame动画:传统的动画方法,通过顺序的播放排列好的图片来实现,类似电影。
    属性动画:

    android 中有哪几种解析xml的类?官方推荐哪种?以及它们的原理和区别。

    XML解析主要有三种方式,SAX、DOM、PULL。常规在PC上开发我们使用Dom相对轻松些,但一些性能敏感的数据库或手机上还是主要采用SAX方式,SAX读取是单向的,优点:不占内存空间、解析属性方便,但缺点就是对于套嵌多个分支来说处理不是很方便。而DOM方式会把整个XML文件加载到内存中去,这里Android开发网提醒大家该方法在查找方面可以和XPath很好的结合如果数据量不是很大推荐使用,而PULL常常用在J2ME对于节点处理比较好,类似SAX方式,同样很节省内存,在J2ME中我们经常使用的KXML库来解析。

    activity在屏幕旋转时的生命周期

    不设置Activity的android:configChanges时,切屏会重新调用各个生命周期,切横屏时会执行一次,切竖屏时会执行两次;设置Activity的android:configChanges="orientation"时,切屏还是会重新调用各个生命周期,切横、竖屏时只会执行一次;设置Activity的android:configChanges="orientation|keyboardHidden"时,切屏不会重新调用各个生命周期,只会执行onConfigurationChanged方法

    如何退出Activity?如何安全退出已调用多个Activity的Application?

    对于单一Activity的应用来说,退出很简单,直接finish()即可。当然,也可以用killProcess()和System.exit()这样的方法。
    对于多个activity,
    1、记录打开的Activity:每打开一个Activity,就记录下来。在需要退出时,关闭每一个Activity即可。
    2、发送特定广播:在需要结束应用时,发送一个特定的广播,每个Activity收到广播后,关闭即可。
    3、递归退出:在打开新的Activity时使用startActivityForResult,然后自己加标志,在onActivityResult中处理,递归关闭。为了编程方便,最好定义一个Activity基类,处理这些共通问题。

    recycleview support-v7与listview的区别

    1、RecyclerView 复用 Item 的工作 Google 全帮你搞定,不再需要像 List View 需要自己写viewholder然后setTag
    2、rv支持局部刷新
    3、rev多种方向的布局(横竖网)
    4、整体上看RecyclerView架构,提供了一种插拔式的体验,高度的解 耦,异常的灵活,通过设置它提供的不同LayoutManager,ItemDecoration , ItemAnimator实现令人瞠目的效果

    多线程Android提供了四种常用的操作多线程的方式,分别是:

    1.Handler+Thread
    Android主线程包含一个消息队列(MessageQueue),该消息队列里面可以存入一系列的Message或Runnable对象。通过一个Handler你可以往这个消息队列发送Message或者Runnable对象,并且处理这些对象。每次你新创建一个Handle对象,它会绑定于创建它的线程(也就是UI线程)以及该线程的消息队列,从这时起,这个handler就会开始把Message或Runnable对象传递到消息队列中,并在它们出队列的时候执行它们
    Handler把压入消息队列有两类方式,Post(传递一个Runnable)和sendMessage(Message)
    2.AsyncTask
    在类中实现异步操作,并提供接口反馈当前异步执行的程度(可以通过接口实现UI进度更新),最后反馈执行的结果给UI主线程,通过一个阻塞队列BlockingQuery<Runnable>存储待执行的任务,利用静态线程池THREAD_POOL_EXECUTOR提供一定数量的线程,默认128个。
    3.ThreadPoolExecutor
    ThreadPoolExecutor提供了一组线程池,可以管理多个线程并行执行。这样一方面减少了每个并行任务独自建立线程的开销,另一方面可以管理多个并发线程的公共资源,从而提高了多线程的效率。所以ThreadPoolExecutor比较适合一组任务的执行,Executors利用工厂模式对ThreadPoolExecutor进行了封装,使用起来更加方便。
    4.IntentService
    IntentService,利用一个work线程依次处理顺序过来的请求

    intentService与service的区别

    1、Service 也不是一个线程,它和线程没有任何关系,所以它不能直接处理耗时操作。如果直接把耗时操作放在 Service 的 onStartCommand() 中,很容易引起 ANR .如果有耗时操作就必须开启一个单独的线程来处理。IntentService 内有一个工作线程来处理耗时操作,当任务执行完后,IntentService 会自动停止,而不需要我们去手动控制

    具体来说,ANR会在以下几种情况中出现:

    1、输入事件(按键和触摸事件)5s内没被处理
    2、BroadcastReceiver的事件(onRecieve方法)在规定时间内没处理完(前台广播为10s,后台广播为60s)
    3、service 前台20s后台200s未完成启动 Timeout executing service
    4、ContentProvider的publish在10s内没进行完

    分析ANR: 在发生ANR的时候,系统会收集ANR相关的信息提供给开发者:首先在Log中有ANR相关的信息,其次会收集ANR时的CPU使用情况,还会收集trace信息,也就是当时各个线程的执行情况。trace文件保存到了/data/anr/traces.txt中,此外,ANR前后该进程打印出的log也有一定价值,
    1、从log中找到ANR反生的信息会找到ANR发生的log,该行会包含了ANR的时间、进程、是何种ANR等信息
    2、分析log之后的CPU usage的信息,cpu被其他进程占用或者是anr进程占用cpu过高
    3、确定问题需要我们进一步分析trace文件。trace文件记录了发生ANR前后该进程的各个线程的stack

    MVC与MVP

    MVC:
    1.视图层(View):一般采用XML文件进行界面的描述,使用的时候可以非常方便的引入。
    2.控制层(Controller):Android的控制层通常是在Acitvity中实现。
    3.模型层(Model):对数据库的操作、对网络等的操作都应该在Model里面处理,当然对业务计算等操作也是必须放在的该层的。
    MVC缺点:
    1、Activity并不是MVC中标准的Controller,既有Controller的职责也有View的职责,导致Activity的代码过于臃肿。
    2、View层和Model层互相耦合,耦合过重,代码量过大,不易于开发和维护。

    MVP:
    MVP (Model-View-Presenter):MVP其实是由MVC演变而来的,其中的M依然是指逻辑模型,V依然是指视图模型,而P(中间桥梁)则代替了C成为了逻辑控制器的角色
    区别就在于MVP中View并不直接使用Model,它们之间的通信是通过Presenter (MVC中的Controller)来进行的,所有的交互都发生在Presenter内部,而在MVC中View会直接从Model中读取数据而不是通过 Controller,在MVC模型里,Model不依赖于View,但是View是依赖于Model的

    MVP 架构的优缺点?

    MVP优点:
    (1)降低耦合度
    (2)模块职责划分明显
    (3)代码复用presenter
    (4)代码灵活性
    缺点:
    1、由于对视图的渲染放在了Presenter中,所以视图和Presenter的交互会过于频繁还有一点需要明白,如果Presenter过多地渲染了视图,往往会使得它与特定的视图的联系过于紧密。一旦视图需要变更,那么Presenter也需要变更了。
    2、接口多,导致维护接口的成本非常大

    MVP四大要素

    (1)View:负责绘制UI元素、与用户进行交互(在Android中体现为Activity);

    (2)View interface:需要View实现的接口,View通过View interface与Presenter进行交互,降低耦合,方便进行单元测试;

    (3)Model:负责存储、检索、操纵数据(有时也实现一个Model interface用来降低耦合);

    (4)Presenter:作为View与Model交互的中间纽带,处理与用户交互的负责逻辑。

    String,Stringbuffer,Stringbuilder 区别

    1、String:字符串常量,字符串长度不可变
    2、StringBuffer:字符串变量(Synchronized,即线程安全)。如果要频繁对字符串内容进行修改,出于效率考虑最好使用StringBuffer,如果想转成String类型,可以调用StringBuffer的toString()方法。
    3、StringBuilder:字符串变量(非线程安全)。在内部,StringBuilder对象被当作是一个包含字符序列的变长数组

    Java中equals和==的区别

    java中的数据类型,可分为两类:
    1.基本数据类型,也称原始数据类型他们之间的比较,应用双等号(==),比较的是他们的值。基本数据类型比较(string 除外), == 和 Equals 两者都是比较值;
    2.复合数据类型(类)
    当他们用(==)进行比较的时候,比较的是他们在内存中的存放地址,所以,除非是同一个new出来的对象,他们的比较后的结果为true,否则比较后结果为false。

    JAVA当中所有的类都是继承于Object这个基类的,在Object中的基类中定义了一个equals的方法,这个方法的初始行为是比较对象的内存地址, 对于复合数据类型之间进行equals比较,在没有覆写equals方法的情况下,他们之间的比较还是基于他们在内存中的存放位置的地址值的

    线程安全:

    如果你的代码所在的进程中有多个线程在同时运行,而这些线程可能会同时运行这段代码。如果每次运行结果和单线程运行的结果是一样的,而且其他的变量的值也和预期的是一样的,就是线程安全的
    Android UI不是线程安全的, android UI 中提供invalidate()来更新界面,而invalidate()方法是线程不安全,也就是说可能在非UI线程中刷新界面的时候,UI线程(或者其他非UI线程)也在刷新界面,这样就导致多个界面刷新的操作不能同步,导致线程不安全

    引起内存泄露的原因(leakcanary)

    1、单例中引用的上下文Context(静态对象持有context)
    2、非静态内部类的静态实例,静态实例持有context
    3、Handler作为非静态内部类,同样会持有外部类的引用,如果它们的内部有延迟操作,在延迟操作还没有发生的时候,销毁了外部类,那么外部类对象无法回收,从而造成内存泄漏(一般套路就是把 Handler为静态内部类,这样它们就不再持有 MainActivity 的引用了)
    4、注册对象未注销,如BraodcastReceiver 未取消注册,
    5、资源性对象未关闭。比如Cursor、File文件等,InputStream 未关闭
    6、线程必须在activity退出的时候关闭

    android 图片占用内存相关参数

    1、将图片转成bitmap 来使用的时候,图片所占的内存,不是它原来的大小,是与 图片的宽度,高度,和颜色深度(图片的颜色模式)有关系。颜色深度:
    Bitmap.Config ALPHA_8
    Bitmap.Config ARGB_4444(16位)
    Bitmap.Config ARGB_8888 (32位)
    Bitmap.Config RGB_565

    sleep和wait有什么区别

    功能差不多,都用来进行线程控制,他们最大本质的区别是:sleep()不释放同步锁,wait()释放同步缩. 还有用法的上的不同是:sleep(milliseconds)可以用时间指定来使他自动醒过来,如果时间不到你只能调用interreput()来强行打断;wait()可以用notify()直接唤起

    Dalvik虚拟机与java虚拟机的区别

    1、java虚拟机运行的是Java字节码(class),Dalvik虚拟机运行的是Dalvik字节码(dex)
    2、java虚拟机与Dalvik虚拟机架构不同。java虚拟机基于栈架构。Dalvik虚拟机基于寄存器架构,数据的访问通过寄存器间直接传递,这样的访问方式比基于栈方式快的多.

    进程间通信的方式

    (1)AIDL,(Android接口定义语言)
    服务端定义好aidl接口文件即提供给客户端使用的方法,(clean下会自动生成stub接口)接着在service中实现stub,当客户端bindservice的时候将具体stub传给客户端,然后客户端通过具体的stub来使用服务端提供的方法,从而达到进程通讯。客户端也需要有一份同包名的aidl文件、实现Parcelable接口的数据类型
    规则有以下几点:
    1、AIDL文件以 .aidl 为后缀名
    2、AIDL支持的数据类型分为如下几种:
    八种基本数据类型:byte、char、short、int、long、float、double、boolean,String,CharSequence
    实现了Parcelable接口的数据类型
    List 类型。List承载的数据必须是AIDL支持的类型,或者是其它声明的AIDL对象
    Map类型。Map承载的数据必须是AIDL支持的类型,或者是其它声明的AIDL对象
    3、AIDL文件可以分为两类。一类用来声明实现了Parcelable接口的数据类型,以供其他AIDL文件使用那些非默认支持的数据类型。还有一类是用来定义接口方法,声明要暴露哪些接口给客户端调用,定向Tag就是用来标注这些方法的参数值
    4、定向Tag。我再来讲下三种定向Tag之间的差别。上边使用的是 InOut 类型,服务端对数据的改变同时也同步到了客户端,因此可以说两者之间数据是双向流动的
    In 类型的表现形式是:数据只能由客户端传向服务端,服务端对数据的修改不会影响到客户端
    Out类型的表现形式是:数据只能由服务端传向客户端,即使客户端向方法接口传入了一个对象,该对象中的属性值也是为空的,即不包含任何数据,服务端获取到该对象后,对该对象的任何操作,就会同步到客户端这边
    5、明确导包。在AIDL文件中需要明确标明引用到的数据类型所在的包名,即使两个文件处在同个包名下
    (2)广播
    (3)Messenger
    (4)contentprovider

    Serializable和Parcelable使用区别

    Serializable使用IO读写存储在硬盘上。序列化过程使用了反射技术,并且期间产生临时对象。优点代码少。
    Parcelable是直接在内存中读写,我们知道内存的读写速度肯定优于硬盘读写速度,所以Parcelable序列化方式性能上要优于Serializable方式很多。但是代码写起来相比Serializable方式麻烦一些。

    HttpClient与HttpUrlConnection的区别

    HttpClient的API数量过多,使得我们很难在不破坏兼容性的情况下对它进行升级和扩展,所以目前Android团队在提升和优化HttpClient方面的工作态度并不积极,轻量极的HTTP客户端,使用它来进行HTTP操作可以适用于大多数的应用程序。虽然HttpURLConnection的API提供的比较简单,但是同时这也使得我们可以更加容易地去使用和扩展它

    Service的两种启动方式

    (1)startService(),
    使用这种start方式启动的Service的生命周期如下:
    onCreate()--->onStartCommand() ---> onDestory()
    说明:如果服务已经开启,不会重复的执行onCreate(), 而是会调用onStart()和onStartCommand()。
    服务停止的时候调用 onDestory()。服务只会被停止一次。
    特点:一旦服务开启跟调用者(开启者)就没有任何关系了。
    开启者退出了,开启者挂了,服务还在后台长期的运行。
    开启者不能调用服务里面的方法
    (2)bindService()(unbindService解绑)
    使用这种start方式启动的Service的生命周期如下:
    onCreate() --->onBind()--->onunbind()--->onDestory()
    注意:绑定服务不会调用onstart()或者onstartcommand()方法
    特点:bind的方式开启服务,绑定服务,调用者挂了,服务也会跟着挂掉。
    绑定者可以调用服务里面的方法。

    保活手段

    当前业界的Android进程保活手段主要分为** 黑、白、灰 **三种,其大致的实现思路如下:
    黑色保活:不同的app进程,用广播相互唤醒(包括利用系统提供的广播进行唤醒)
    白色保活:启动前台Service,就是调用系统api启动一个前台的Service进程,这样会在系统的通知栏生成一个Notification,用来让用户知道有这样一个app在运行着
    灰色保活:利用系统的漏洞启动前台Service,
    思路一:API < 18,启动前台Service时直接传入new Notification();
    思路二:API >= 18,同时启动两个id相同的前台Service,然后再将后启动的Service做stop处理;

    Android应用程序启动过程

    (1)启动的起点发生在Launcher活动中,启动一个app说简单点就是启动一个Activity,那么我们说过所有组件的启动,切换,调度都由AMS来负责的,所以第一步就是Launcher响应了用户的点击事件,然后通知AMS
    (2)AMS得到Launcher的通知,就需要响应这个通知,主要就是新建一个Task去准备启动Activity,并且告诉Launcher你可以休息了(Paused);
    (3)Launcher得到AMS让自己“休息”的消息,那么就直接挂起,并告诉AMS我已经Paused了;
    (4)AMS知道了Launcher已经挂起之后,就可以放心的为新的Activity准备启动工作了,首先,APP肯定需要一个新的进程去进行运行,所以需要创建一个新进程,这个过程是需要Zygote参与的,AMS通过Socket去和Zygote协商,如果需要创建进程,那么就会fork自身,创建一个线程,新的进程会导入ActivityThread类,这就是每一个应用程序都有一个ActivityThread与之对应的原因;
    (5)进程创建好了,通过调用上述的ActivityThread的main方法,这是应用程序的入口,在这里开启消息循环队列,这也是主线程默认绑定Looper的原因;
    (6)这时候,App还没有启动完,要永远记住,四大组建的启动都需要AMS去启动,将上述的应用进程信息注册到AMS中,AMS再在堆栈顶部取得要启动的Activity,通过一系列链式调用去完成App启动;

    android系统版本差异

    Android9.0Android9.0又称Android P(pie)
    1.对全面屏的支持模仿了ios提高屏占比的方案(前摄像头没有比较好的隐藏方案),即支持齐刘海。借助最新的提供的DisplayCutout类,开发者可以找到非功能区域的位置和形状,而非功能区域是不应显示功能的;使用getDisplayCutout()就可以获取这个区域的详细信息。
    2.通知栏(状态栏)现在只允许显示最多4个通知图标,不管当前设备是否是齐刘海,多出来的通知显示为三个点。Android P版本中,你还可以在消息中展示图像;新的Notification.Person类可以识别对话中的任务,包括他们的头像和URI。
    Android8.0
    1.PinnedShortcuts功能
    类似苹果的3DTouch,长按一个软件后可以弹出子菜单,然后就可以通过这个方式快捷的使用该应用的部分功能。

    Android6.0
    1.完整的权限控制
    危险的权限都需要向系统动态申请,只静态注册申请权限会无效化。对于一些隐私权限会在第一时间提示用户是否授权
    android5.0
    1、转场动画
    2、增加供开发者使用的官方控件,引入抽屉布局(DrawerLayout)、RecyclerView、CardView、SwipeRefreshLayout、ToolBar、drawerToggle等,开始能够自定义状态栏、标题栏、导航栏的颜色,设置控件阴影

    相关文章

      网友评论

          本文标题:android面试基础汇集

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