• Android 面试题汇总


    面试题基础储备

    1Activity相关

    aActivity的特点

    1、可见  2、可交互   

    他之所以可交互,是因为他同时实现了Window.CallbackKeyEvent.Callback, 可以处理与窗体用户交互的事件和按键事件.这两个特点,是他和service最大的区别。一个Activity在创建与销毁的过程中,会经历一些生命周期。

    bActivity的生命周期

     

    结论1、这个界面只要看不到了,它就一定执行了onStop方法

    结论2、只要这个界面显示出来了,它就一定执行了onResume方法

    结论3onPauseonStop的情况下这个activity都有可能会系统回收。(简单    来说,只要这个activity不处于活跃状态,那么它就有可能被回收)

    c、页面跳转必然会执行的方法

    onResume,所以可以在onResume方法里面进行数据刷新,保证当前activity显示的都是最新状态

    d、对话框的activity

    启动activity默认是占满整个屏幕,如果想让这个activity以对话框的方式展示,则需要配置:android:theme="@android:style/Theme.Dialog",此时它下面的activity并不会执行onStop方法,而是仅执行onPause方法

    e、横竖屏切换

    默认情况下,横竖屏切换的时候会重新创建新的activity,新的那个activity执行onCreate方法。可以通过AndroidManifest文件进行配置,让它横竖屏切换的时候不重新创建Activity,配置方法为

    android:configChanges="orientation|keyboardHidden|screenSize",配置之后就不会创建新的Activity,而是执行当前activityonConfigurationChanged。写死屏幕的方向:在AndroidManifest中配置

    android:screenOrientation="landscape"

    f、保存数据

    除了在栈顶的activity,其他的activity在系统资源匮乏的时候,都有可能会被系统回收。如果activity被系统没有onDestory的情况下就被系统回收了,这时候系统会调用onSaveInstanceState方法,我们可以往bundle里面存放数据。activity onCreate里面我们先判断一下bundle是不是为空,如果不为空,就代表这个activity之前被系统回收掉,应该恢复一下现场。我们就可以从bundle里面取值。

    g、栈相关

    概念:Android是用栈来管理Activity的,service是没有栈的。所以在service  启动activity一般要加上

          intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)来开辟一个  新的栈。四大组件中只有Activity是有栈的。

    启动模式:android:launchMode

      standard:默认的模式,没有限制,栈里爱有几个有几个

      singleTop:栈顶只有一个,栈内可以有多个

      singleTask:整个栈只有一个

      singleInstance:霸道,整个栈只有自己,单实例

    honNewIntent

    当启动某一个activity,这个activity在栈中存在,并且需要被复用的情况下,(也就是配置了singleTopsingleTasksingleInstance的 属性),会调用此方法。如果需要传递参数,需要在onNewIntent里面setIntent,这样才能更新这activityintent

     

     

    2Service相关

    aService的特点

    不可见、不可交互,在后台运行的四大组件之一。

      并不是所有的功能都需要界面。比如音乐播放。

    bService的启动方式

    startServicebindService

    cService的生命周期

    a、通过startService

    Service会经历 onCreate onStart,然后处于运行状态,stopService的时候调onDestroy方法。

    这种方式,activityservice是相互独立的。如果是调用者自己直接退出而没有调用stopService的话,Service会一直在后台运行

    b、通过bindService 

    Service会运行onCreate,然后是调用onBind, 这个时候调用者和Service定在一起。调用者解绑了,Service就会调用onUnbind->onDestroyed方法。

      这种方式,activity就和service相互捆绑在一起了。所谓绑定在一起就共存亡了。调用者也可以通过调用unbindService方法来停止服务,这时候Service会调用onUnbind->onDestroyed方法。

    简单来说,startService的方式启动之后,Activity是调用不到Service里面的方法。

    bindService方式启动之后,可以得到Service的实例,进而调用Service里面的方法。startServicebindService可以结合使用。无论怎么结合,Service的实例只有一个。

    d为什么使用Service

    普通的线程也可以达到在后台做事情的功能,那么为什么使用 Service呢?是因为Service是系统的组件,它的优先级比普通的线程要高,不容易被系统回收。而且线程不好控制,Service相对好控制一些。运行在前台的Activity是不会被系统回收的,而Service如果不想被系统回收,就需要在Service中设置一下

    startForeground(int,Notification)

    具体的使用场景有:

    a、拥有长连接QQ

    b、定时轮询

    c、服务里面注册广播接收者。有些广播接收者只能通过代码注册,比如屏幕锁屏、  屏幕解锁、电量发生变化等。

    eIntentService

    普通的service ,默认运行在ui main 主线程.Sdk给我们提供的方便的、带有异步处理的service,我们可以在OnHandleIntent() 处理耗时的操作

    四大组件都是运行在主线程中

     

    3、数据相关

    a、存储

    Android中数据可以存储在四个地方

    内存:读写速度最快,临时的值,程序退出或者界面退出就没有了

    SharedPreference:持久存储,主要保存一些配置信息,如一个功能的开关

    Sqlite:持久存储,关系型数据库,针对数据之间有很强关系的情况

    文件:持久存储,针对数据量较大、并且没啥关联的数据

     

    关于如何使用Sqlite来存储数据,传统的方式我们会使用到SQLiteOpenHelper 然后会自己写一些sql语句,在真实的开发当中,我们往往会借助于一些第三方框架帮我们处理数据相关的逻辑,这样可以帮助我们帮主要精力花在其他功能实现上。我比较常用的是LitePal,它可以帮我们很轻松的进行数据库操作。

    b、传递

    a、通过intent传递

    基本的数据类型:Stringintfloat

    对象:这个对象必须继承Parcelable接口。继承Parcelable接口代表这个对象可以   被序列化到内存中,和Serializable类似,只不过Serializable是将对象写到   文件当中。

    b、通过Application传递

    Application的特点:一个应用程序运行的时候只有一个,它的生命周期是最长的,比ActivityService都长,只要这个程序在运行,无论是否在前台,它都会有一个Application对象。往Application存某一些对象,在页面跳转的时候会非常方便。

    c、通过View来传递数据。在给View设置点击事件的时候,可以通过view.setTag来传递所需要传递的数据

    c、解析

    XML

    效率低,体积大

    JSON

    效率高,体积小,使用广,可以使用Gson解析,也可以使用JSONObject进行解析,fastjson其他第三方框架

        复杂的结构:使用Gson,创建javabean来进行解析

    简单的结构:{"success":"true"},直接使用JSONObject进行解析. 如果使用JSONObject进行解析的话,有几点需要记忆:

    {}---JSONObject

    []---JSONArray

    无符号:基础数据类型

    dContentProvider

    目的:将自己应用的数据提供给其他应用

    把自己的数据通过uri的形式共享出去,这个uri是事先约定好的。

    android  系统下不同程序 数据默认是不能共享访问,通过ContentProvider可以将自己应用的数据提供给别的应用。

    我们在写内容提供者的时候,需要写一个类继承ContentProvider,然后实现里面的增删改查方法

    query(Uri, String[], String, String[], String)

    insert(Uri, ContentValues)

    update(Uri, ContentValues, String, String[])

    delete(Uri, String, String[])

    工作中用的很少,我们几乎不需要写ContentProvider,因为没有这个需求。可能会用到的是调用系统的ContentProvider,比如获取系统联系人,系统短信。

     

    4、广播相关

    a、广播发送

       广播的发送有两类,一种是系统本身就有的,一种是我们自己写的广播。

       发送方式:

    有序广播sendOrderedBroadcast

    按顺序依次的发送给每一个接收者,而每一个接收者在收到这个广播的时候,可以将这个广播abort掉,也可以将这个广播继续传递到下一个广播接收者。广播接收者在注册的时候可以指定优先级,用于提高接收到广播的顺序。

    无序广播sendBroadcast

    不能被abort

    b、广播接收

       广播接收者注册的方式也有两种,一种是动态注册,一种是静态注册。有一些系统   的广播只能使用动态注册,这种广播产生的频率是比较高的。比如电量变化的广播,    屏幕解锁的广播。电量变化的广播。

    c、广播的作用

       广播一般是用于跨进程通讯的时候。两个进程间要进行通讯的情况下,使用广播显  得非常的方便。如打电话的时候状态栏颜色变了,此时就是可以使用广播在电话的进  程中发送一个广播,然后再状态栏的进程当中进行接收。接收到之后改变状态栏颜色。  onReceive方法也是在主线程当中运行的。在广播中启动Activity也是需要配置

      intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)来开辟一个新的栈。

     

    5、跨进程访问

    aAndroid中跨进程访问的方式:

    主要有三种:1、广播 2AIDL  3intent启动其他应用activity、内容提供者

    b、什么是AIDL

    AIDL的全称是android interface definition language  接口定义语言。它所做的事情就是跨进程调用另外一个服务里面的方法的。所以aidl就得使用到bindService方法。在手机卫士中挂断电话用到过AIDL。我们要获取手机系统的电话服务,用到了aidl 它其实工作的原理就是绑定到一个远程的服务上。然后这个远程服务会返回回来一个代理对象。这个代理对象里面的方法,就是我们定义的aidl里面的方法。 

    aidl的写法也非常简单,主要分两种。调用系统服务的话,直接找到那个服务的aidl拷贝到我们的项目中就可以了。另外一种是我们自己写aidl,主要注意的一点是aidl是没有访问修饰符的。因为aidl本身就是公开的,就是为了给别人调用的,不需要私有的private方法。

    其实,在实际的开发过程中,比较少会写这个aidl,但是你得懂它相关的知识点。

    在面试的时候,这个也是经常被问的。所以大家要熟悉这个问题的回答方法。

    我以前面试别人的时候,只要他能回答上几个关键点,我就会让他过我这关噢。

    1、跨进程  2aidl在服务端和客户端都需要有一份  3、通过绑定bindService的方式获取远程服务对象的代理IBinder,就可以调用相关的方法。

    c、跨进程的底层原理

        广播、aidl 的底层实现机制是BinderBinder是基于共享内存的一种IPC方式

    如何自己实现进程间的通信?

     

    6Handler相关

    a、为什么使用Handler

       Handler是用来进行线程间的通信。因为Android系统有一个特性,ui操作必须得   在主线程当中进行。所以在子线程进行完耗时操作的时候,如何告诉主线程进行ui       界面更新,这就需要使用到线程间的通讯了。

    bHandlerLooperMessageQueueMessage的关系

       任何一个线程,无论是子线程还是主线程,都维护着一个消息队列,这个消息队列   就是MessageQueue,有了这个消息队列之后,是需要不断的从这个消息队列里面取   出消息进行处理的,这个就是Looper做的事情。那么,谁往这个消息队列里面丢消   息呢?那就是Handler了。

       Looper是用来管理所属线程的消息队列MessageQueue的。

       每一个线程都需要有一个looper,每一个looper管理一个MessageQueue.

           Handler.sendMessage的意思是将某一个message放到MessageQueue中去,looper   是个死循环,不断的读MessageQueue中的新消息。

           要让looper的死循环运行起来,得调用Looper.loop()方法。

           我们通常都会在子线程中,发一个消息到主线程中的messagequeue中去。

       Handler到底是往主线程的MessageQueue发送消息呢还是往子线程的   MessageQueue发送消息呢?这取决于Handler在哪里创建。如果Handler在主线程     中创建,那么这个Handler就会把消息发到主线程的消息队列,如果Handler是在子     线程中创建,这个Handler就会把消息发到子线程的消息队列。这里需要注意的是,   子线程的Looper需要我们自己手动启动,要调用Looper.prepare()Looper.loop()   法,主线程的Looper系统已经帮我们启动了,因此我们不需要为主线程的     Looper调用loop()方法

     c、子线程-->主线程   主线程-->子线程?

    view.post(r)或者activity.runOnUiThread(r)都是将runnable对象丢到了主线程的消息队列中。

     

    7ANR相关

    a、什么是ANR

       ANRandroid not response   安卓无响应,这里指的是主线程无响应。将耗时的     操作放在子线程中进行可以有效的避免ANR

    b、出现的原因:消息的超时信息

       出现ANR的根本原因是主线程堵塞了,来不及处理消息。任何UI操作都是一个消   息,比如触摸、按键,弹框,setText等,当这些消息得不到及时的处理,就会出现   ANR了。每一个发往主线程的消息其实都带有一个超时时间,超过了这个时间,这   个消息还没有处理,就会出现ANR

       Activity的超时:5s

       BroadcastReceiver超时:10s

           Service超时:20s

    c、解决的方法

       如果出现了ANR,我们可以通过log信息以及traces.txt文件进行分析。

       traces.txt里面记录的是stack信息。

       traces.txt的路径:/data/anr/traces.txt

     

    8ListView的相关

    aListView为什么要优化?

    因为不优化的话,滑动ListView会卡顿。卡顿的原因在于getView太耗时了。

    getView是在主线程执行的,如果这里面太耗时的话,ui肯定卡顿。耗时主要集中在两个方面:加载布局文件、findViewById

    bListView怎么优化

    减少加载布局文件的次数:使用缓存convertView

    减少findViewById的次数:使用ViewHolder

    c、数据错乱的问题

    i、正是因为使用了缓存,所以才有可能造成数据错乱。所以在刷新数据的时候,一定要考虑周全。

     

    ii消息处理时机引起的数据错乱

    dListView展示多种布局类型

    i、告诉系统你有几种布局类型getViewTypeCount

    ii、告诉系统,什么情况下显示哪种布局类型getItemViewType(int position)

    iii、在getView中根据getItemViewType的返回值加载对应的布局文件。在刷新数据的时候也得根据getItemViewType的返回值进行数据刷新。

     

    9、自定义控件相关

    a、自定义属性

    步骤:

    1、起一个名字

    values的目录下需要建立一个文件,叫做attrs.xml 这个文件是定义属性规则的。一个属性的名字、取值类型、取值范围

                   

    2、用这个属性

    在布局文件中需要加入命名空间

     

        

    3、得到这个属性的值

       最后在自定义控件中获取这些值。 

     

    b、绘制流程

    涉及的方法:

       onMeasure:计算大小

       onLayout:计算位置

      onDraw:开始绘制

       调用顺序是onMeasure-->onLayout--->onDraw

       这三个方法是任何一个View在屏幕上呈现出来的时候都一定会调用的三个方法,三个方法的作用不一样。

    其他知识:

       int widthMeasureSpec---封装了两个信息,一个是具体大小的值,一个是模式

       模式就是父控件对你的限制。

    int widthSize = MeasureSpec.getSize(widthMeasureSpec);// 获取宽度

    int widthMode = MeasureSpec.getMode(widthMeasureSpec);// 宽度的模式

    // MeasureSpec.AT_MOST;--->wrap_content至多的模式。

    // MeasureSpec.EXACTLY;--->确定的模式,match_parent,写死成多少dp

    // MeasureSpec.UNSPECIFIED;--->未确定的模式 ScrollView:不对孩子的高度进行限定

     

    10、动画相关

    分类

    a、帧动画

    帧动画,就像GIF图片

     

              

    b、补间动画tween 

    只是改变了View对象绘制的流程,而没有改变View对象本身。AlphaAnimation   RotateAnimationScaleAnimationTranslateAnimation

    c、属性动画

       Android 3.0中才引进,更改的是对象的实际属性。如果要在2.x版本也要支持   属性动画,则需要加入兼容包nineoldandroids.jar 

       ValueAnimatorObjectAnimator的使用

    具体面试题:59

    11、设计模式相关

    a、单例:保证就只有一个实例

    单例的写法: 

    1、私有的构造方法 

    2、私有的,静态的对象instance 

    3、公开的,静态的getInstance方法

     注意事项:在getInstance的方法前加上线程同步synchronized

    b、适配器:数据和View的桥梁。

    c、观察者:本质就是回调,一堆回调

    dMVCMVC 是 ModelViewController 三部分组成的。其中 View 主要由 xml 局文件,或者用代码编写动态布局来体现。Model 是数据模型,其实类似 javabean,不过这些 JavaBean 封装了对数据库、网络等的操作。Controller 般由 Activity 负责,它根据用户的输入,控制用户界面数据的显示及更新model 对象的状态,它通过控制 View 和 Model 跟用户进行交互。

    MVCAndroid当中体现的并不是很明显,在web当中体现的明显些。

     

    回答设计模式相关的问题时,应该结合自身的开发经历进行开展。

    12、屏幕适配相关

    a、概述:

    dp  不用px  这仅仅是适配的一部分而已。这里需要注意的一点是,android不可能做到完全适配每一个屏幕的,只能达到大体相近。如果你要达到完全适配,你就必须在每一个drawable-目录下都放入整套切图,而且要建立不同分辨率的layout-854*480的布局文件,这简直是不可想象。没有一个公司会这么做。大部分的人是怎么做的呢?

    b、切图适配:

    一般都是找一个使用比较广泛的分辨率当作标准。比如1280x720  密度为2,然   后设计师就会根据这个分辨率进行设计,然后切图。我们就需要将设计师出的切图   放到drawable-xhdpi目录下就可以了。一般情况下,我们不需要在drawable-hdpi   目录、drawable-mdpi目录、drawable-xxhdpi目录下放切图了,只在drawable-xhdpi下放一套就够了。在真正运行的时候,系统会自动对图片进行处理。这时候,绝大部分切图显示都是正常的。如果你觉得哪几张图片显示不清晰了,就只要再出这几张切图放到drawable-xxhdpi目录或者其他目录即可。

    c、布局适配:

    尽量用一些确定的东西来确定不确定的东西。多用RelativeLayoutLinearLayout

     

    整体是一个LinearLayout,垂直方向。中间的edittextmatch_parent.最底下整体布局应该是RelativeLayoutOK按钮是layout_alignParentRight,确定好OK之后,在确定cancel的值,切勿不要先确定cancel的位置再确定ok的位置。

     

    按照上诉布局做法,在超大的屏幕上显示的时候发现,edittext变长了点,但是整个的位置结构是没变的,这个布局的适配就算是过关的。

    其实屏幕适配总结起来就几个方面:布局适配、图片适配、单位适配、代码适配

    13、图片相关

    a、图片的缓存(多图片的加载)

       任何一种缓存的目的是都是为了加载更快,那么存在哪里呢?存在内存中是最好的,   因为内存的读取速度最快,但是内存的大小是受限制的。所以,我们只能在内存中   加载一部分图片。使用LRUCache可以对内存中的图片进行有效管理。

       三级缓存:内存缓存--本地缓存--网络缓存

    b大图片的加载

       如果一张图片有几十M,那么这一张图片一加载肯定就OOM了,根本就不需要使   用LRUCache,所以加载大图片的时候需要注意:

    1仅请求图片的大小,inJustDecodeBounds = true,仅请求图片大小,而不会   加载图片到内存;

    2、得到图片的大小,再得到所需要显示控件的大小,根据这两个值,合理设置   BitmapFactory.OptionsinSampleSize值,减少图片内存占用

     

    14View的事件传递

    View:只有dispatchTouchEventonTouchEvent

    ViewGroupdispatchTouchEventonInterceptTouchEventonTouchEvent

    事件传递dispatchTouchEvent  为的就是找到响应的那个View  这个方法的返回值会使用 onInterceptTouchEvent的返回值,true代表找到响应的Viewfalse代表没有 找到响应的View

    事件拦截onInterceptTouchEvent 返回值为true代表将事件拦截在此ViewGroup中,此View 就是响应的那个ViewGroup

    事件响应onTouchEvent  true代表消费了这个事件,这个事件就不往上传递,false代表没有消费此事件,此事件继续向上传递。

    可以以爷爷、父亲、孩子吃苹果的例子加强记忆。一个苹果到了爷爷的手中,爷爷可以决定自己吃,也可以决定把苹果给父亲吃。如果爷爷吃了这个苹果,父亲肯定就得不到这个苹果。如果爷爷把苹果给了父亲,那父亲得到苹果之后也有两个选择,自己把苹果吃了,或者把苹果给孩子。孩子拿到苹果了,可以选择吃,也可以选择不吃。如果不吃的话,孩子没办法把苹果向下传递,他就会把苹果又还给父亲。父亲拿到苹果之后,可以吃了它,也可以再把它还给爷爷。爷爷拿到苹果之后也同样有两种选择。

    苹果从爷爷-父亲-孩子,代表事件传递

    苹果从孩子-父亲-爷爷,代表事件消费

    事件传递的方向是由父控件到子控件,事件响应的方向是从子控件到父控件。

     


     

    15、内存泄露相关

    垃圾回收机制:垃圾回收器仅会回收没有人引用的对象。

    内存泄露

    内存泄漏本身不会产生什么危害,真正有危害的是内存泄漏的堆积。Android应用内存泄漏的的原因有以下几个:

    1register之后没有unregister

    2查询数据库后没有关闭游标cursor  file没有close
    3构造Adapter时,没有使用 convertView 重用 (内存的溢出)
    4Bitmap对象不在使用时调用recycle()释放内存 
    5对象被生命周期长的对象引用,如activity被静态集合引用导致activity   不能释放

    内存泄漏如何解决:

    通过内存分析工具 MAT(Memory Analyzer Tool),找到内存泄露的对象

    生成hprof文件可以通过adt的工具也可以通过代码生成。debugdump方法

    16、提高ui流畅度

    1优化布局层次。不要不断的嵌套LinearLayout ,多使用RelativeLayout 尽可能的减布局的层次。左边是图片,右边是文字的,可以就使用一个TextView来完成。

    详见:提高UI流畅度_6.pdf文件 

    2、合理使用控件

    ListView嵌套GridView

    ScrollView嵌套ListView

    ListView嵌套ListView

    这些情况都应该避免。

    17、优化性能

    内存:

    a内存溢出(主要是图片,其次是无用的对象太多)

    b内存泄露

    布局:

    a尽可能减少布局的嵌套层级

    尽量多用RelativeLayout可以很有效的减少布局的嵌套层级。也可以使用hierarchyviewer这个工具来检查布局层次

    b、不用设置不必要的背景,避免过度绘制
    比如父控件设置了背景色,子控件完全将父控件给覆盖的情况下,那么父控件就没有必要设置背景。

    c、使用<include>标签复用相同的布局代码
    d、使用<merge>标签减少视图层次结构

    e、通过<ViewStub>实现 View 的延迟加载

    资源:

    f、线程池的使用

    18、使用过的一些工具

    monkeytraceviewmatbeyond comparehierarchyviewer

    monkey可以使用Monkey测试工具帮助我们完成程序的健壮性。

    命令如下:adb shell monkey -p 包名 --ignore-crashes --ignore-timeouts 10000

    具体工作的使用场景将会和logcat命令结合起来。

    adb logcat -v time > D:log.txt

    traceview:分析程序执行的方法效率,可以图形化的表现出方法的执行时长。从而帮助开发者优化性能。

    hierarchyviewer:分析布局视图

     

    来源于www.itcast.cn  之zheng_teacher

     

     

  • 相关阅读:
    避免文本字体大小重置
    为webapp应用制定IOS,Android桌面快捷图标
    兄弟节点 疑问的
    节点属性
    区别getElementByID,getElementsByName,getElementsByTagName
    三种快排四种优化(转载)
    快排(模板)
    二分法求解最大值或最小值(模板)
    中国剩余定理(转载)(中国剩余定理与扩展欧几里德的联系)
    简单母函数(转载)
  • 原文地址:https://www.cnblogs.com/rongsnow/p/5476186.html
Copyright © 2020-2023  润新知