android面试宝典

一.基础篇

1.activity生命周期

主要场景验证:

1.A启动跳转到B,B返回A。
控制台打印结果

进入A
A=====onCreate()
A=====onStart()
A=====onResume()
A跳转到B
A=====onPause()
B=====onCreate()
B=====onStart()
B=====onResume()
A=====onStop()
B返回A
B=====onPause()
A=====onStart()
A=====onResume()
B=====onStop()
B=====onDestroy()

2.A启动,App进入后台,App返回前台
控制台打印结果

进入A
A=====onCreate()
A=====onStart()
A=====onResume()
app进入后台
A=====onPause()
A=====onStop()
app返回前台
A=====onStart()
A=====onResume()
--------------------- 

2.Android的多线程模型有哪几种?

Android提供了四种常用的操作多线程的方式,分别是: 
1. Handler+Thread 
2. AsyncTask 
3. ThreadPoolExecutor 
4. IntentService 

3.ScrollView是否可以和listView混合使用?如何可以,说明混合使用的方式,如果不行,说明原因。 
可以,计算整个ListView的高度,填充数据后重新设置ListView高度,重写onMeasure和onInterceptTouchEvent方法

4.在创建fragment时如何传递初始化参数?

public static MyFragment newInstance(Bundle args) {
    MyFragment f = new MyFragment();
    f.setArguments(args);
    return f;
}
调用fragment:

Bundle args = new Bundle();
args.putString("text","Hello");
MyFragment f = MyFragment.newInstance(args)

5.如何规避oom? 

1.使用更小的图片

在设计给到资源图片的时候,我们需要特别留意这张图片是否存在可以压缩的空间,是否可以使用一张更小的图片。

2.资源文件需要选择合适的文件夹进行存放

我们知道hdpi/xhdpi/xxhdpi等等不同dpi的文件夹下的图片在不同的设备上会经过scale的处理。例如我们只在hdpi的目录下放置了一张100100的图片,那么根据换算关系,xxhdpi的手机去引用那张图片就会被拉伸到200200。需要注意到在这种情况下,内存占用是会显著提高的。对于不希望被拉伸的图片,需要放到assets或者nodpi的目录下。

3.谨慎使用static对象

因为static的生命周期过长,和应用的进程保持一致,使用不当很可能导致对象泄漏,在Android中应该谨慎使用static对象。

4.注意Bitmap复用以及对象的及时回收

5.避免在onDraw方法里面执行对象的创建

类似onDraw等频繁调用的方法,一定需要注意避免在这里做创建对象的操作,因为他会迅速增加内存的使用,而且很容易引起频繁的gc,甚至是内存抖动。

6、 Android的四大组件是哪些,它们的作用?

答:Activity:Activity是Android程序与用户交互的窗口,是Android构造块中最基本的一种,它需要为保持各界面的状态,做很多持久化的事情,妥善管理生命周期以及一些跳转逻辑

service:后台服务于Activity,封装有一个完整的功能逻辑实现,接受上层指令,完成相关的事物,定义好需要接受的Intent提供同步和异步的接口

Content Provider:是Android提供的第三方应用数据的访问方案,可以派生Content Provider类,对外提供数据,可以像数据库一样进行选择排序,屏蔽内部数据的存储细节,向外提供统一的借口模型,大大简化上层应用,对数据的整合提供了更方便的途径

BroadCast Receiver:接受一种或者多种Intent作触发事件,接受相关消息,做一些简单处理,转换成一条Notification,统一了Android的事件广播模型

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

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

8、 请介绍下Android的数据存储方式。

答:使用SharedPreferences存储数据;文件存储数据;SQLite数据库存储数据;使用ContentProvider存储数据;网络存储数据;

9、 如何启用Service,如何停用Service。

服务的开发比较简单,如下:

第一步:继承Service类

1

public class SMSService extends Service {}

第二步:在AndroidManifest.xml文件中的<application>节点里对服务进行配置:<service android:name=".SMSService" />

服务不能自己运行,需要通过调用Context.startService()或Context.bindService()方法启动服务。这两个方法都可以启动Service,但是它们的使用场合有所不同。使用startService()方法启用服务,调用者与服务之间没有关连,即使调用者退出了,服务仍然运行。使用bindService()方法启用服务,调用者与服务绑定在了一起,调用者一旦退出,服务也就终止,大有“不求同时生,必须同时死”的特点。

如果打算采用Context.startService()方法启动服务,在服务未被创建时,系统会先调用服务的onCreate()方法,接着调用onStart()方法。如果调用startService()方法前服务已经被创建,多次调用startService()方法并不会导致多次创建服务,但会导致多次调用onStart()方法。采用startService()方法启动的服务,只能调用Context.stopService()方法结束服务,服务结束时会调用onDestroy()方法。

如果打算采用Context.bindService()方法启动服务,在服务未被创建时,系统会先调用服务的onCreate()方法,接着调用onBind()方法。这个时候调用者和服务绑定在一起,调用者退出了,系统就会先调用服务的onUnbind()方法,接着调用onDestroy()方法。如果调用bindService()方法前服务已经被绑定,多次调用bindService()方法并不会导致多次创建服务及绑定(也就是说onCreate()和onBind()方法并不会被多次调用)。如果调用者希望与正在绑定的服务解除绑定,可以调用unbindService()方法,调用该方法也会导致系统调用服务的onUnbind()-->onDestroy()方法。

服务常用生命周期回调方法如下:

onCreate() 该方法在服务被创建时调用,该方法只会被调用一次,无论调用多少次startService()或bindService()方法,服务也只被创建一次。

onDestroy()该方法在服务被终止时调用。

与采用Context.startService()方法启动服务有关的生命周期方法

onStart() 只有采用Context.startService()方法启动服务时才会回调该方法。该方法在服务开始运行时被调用。多次调用startService()方法尽管不会多次创建服务,但onStart() 方法会被多次调用。

与采用Context.bindService()方法启动服务有关的生命周期方法

onBind()只有采用Context.bindService()方法启动服务时才会回调该方法。该方法在调用者与服务绑定时被调用,当调用者与服务已经绑定,多次调用Context.bindService()方法并不会导致该方法被多次调用。

onUnbind()只有采用Context.bindService()方法启动服务时才会回调该方法。该方法在调用者与服务解除绑定时被调用

10、 注册广播有几种方式,这些方式有何优缺点?请谈谈Android引入广播机制的用意。

答:首先写一个类要继承BroadcastReceiver

第一种:在清单文件中声明,添加

<receive android:name=".IncomingSMSReceiver " >

<intent-filter>

<action android:name="android.provider.Telephony.SMS_RECEIVED")

<intent-filter>

<receiver>

第二种使用代码进行注册如:

IntentFilter filter =  new IntentFilter("android.provider.Telephony.SMS_RECEIVED");

IncomingSMSReceiver receiver = new IncomgSMSReceiver();

registerReceiver(receiver.filter);

两种注册类型的区别是:

1)第一种不是常驻型广播,也就是说广播跟随程序的生命周期。

2)第二种是常驻型,也就是说当应用程序关闭后,如果有信息广播来,程序也会被系统调用自动运行。

11、 简要解释一下activity、 intent 、intent filter、service、Broadcase、BroadcaseReceiver

答:一个activity呈现了一个用户可以操作的可视化用户界面;一个service不包含可见的用户界面,而是在后台运行,可以与一个activity绑定,通过绑定暴露出来接口并与其进行通信;一个broadcast receiver是一个接收广播消息并做出回应的component,broadcast receiver没有界面;一个intent是一个Intent对象,它保存了消息的内容。对于activity和service来说,它指定了请求的操作名称和待操作数据的URI,Intent对象可以显式的指定一个目标component。如果这样的话,android会找到这个component(基于manifest文件中的声明)并激活它。但如果一个目标不是显式指定的,android必须找到响应intent的最佳component。它是通过将Intent对象和目标的intent filter相比较来完成这一工作的;一个component的intent filter告诉android该component能处理的intent。intent filter也是在manifest文件中声明的。

12、 如果后台的Activity由于某原因被系统回收了,如何在被系统回收之前保存当前状态?

答:重写onSaveInstanceState()方法,在此方法中保存需要保存的数据,该方法将会在activity被回收之前调用。通过重写onRestoreInstanceState()方法可以从中提取保存好的数据

13、 如何将一个Activity设置成窗口的样式。

答:<activity>中配置:android :theme="@android:style/Theme.Dialog"

另外android:theme="@android:style/Theme.Translucent" 是设置透明

14、Service生命周期?

service 启动方式有两种,一种是通过startService()方式进行启动,另一种是通过bindService()方式进行启动。不同的启动方式他们的生命周期是不一样.

通过startService()这种方式启动的service,生命周期是这样:调用startService() --> onCreate()--> onStartConmon()--> onDestroy()。这种方式启动的话,需要注意一下几个问题,第一:当我们通过startService被调用以后,多次在调用startService(),onCreate()方法也只会被调用一次,而onStartConmon()会被多次调用当我们调用stopService()的时候,onDestroy()就会被调用,从而销毁服务。第二:当我们通过startService启动时候,通过intent传值,在onStartConmon()方法中获取值的时候,一定要先判断intent是否为null。

通过bindService()方式进行绑定,这种方式绑定service,生命周期走法:bindService-->onCreate()-->onBind()-->unBind()-->onDestroy()  bingservice 这种方式进行启动service好处是更加便利activity中操作service,比如加入service中有几个方法,a,b ,如果要在activity中调用,在需要在activity获取ServiceConnection对象,通过ServiceConnection来获取service中内部类的类对象,然后通过这个类对象就可以调用类中的方法,当然这个类需要继承Binder对象

15、Broadcast注册方式与区别 

此处延伸:什么情况下用动态注册

 

Broadcast广播,注册方式主要有两种.

第一种是静态注册,也可成为常驻型广播,这种广播需要在Androidmanifest.xml中进行注册,这中方式注册的广播,不受页面生命周期的影响,即使退出了页面,也可以收到广播这种广播一般用于想开机自启动啊等等,由于这种注册的方式的广播是常驻型广播,所以会占用CPU的资源。

 

第二种是动态注册,而动态注册的话,是在代码中注册的,这种注册方式也叫非常驻型广播,收到生命周期的影响,退出页面后,就不会收到广播,我们通常运用在更新UI方面。这种注册方式优先级较高。最后需要解绑,否会会内存泄露

广播是分为有序广播和无序广播。

16、View的绘制流程

自定义控件:

1、组合控件。这种自定义控件不需要我们自己绘制,而是使用原生控件组合成的新控件。如标题栏。

2、继承原有的控件。这种自定义控件在原生控件提供的方法外,可以自己添加一些方法。如制作圆角,圆形图片。

3、完全自定义控件:这个View上所展现的内容全部都是我们自己绘制出来的。比如说制作水波纹进度条。

 

View的绘制流程:OnMeasure()——>OnLayout()——>OnDraw()

 

第一步:OnMeasure():测量视图大小。从顶层父View到子View递归调用measure方法,measure方法又回调OnMeasure。

 

第二步:OnLayout():确定View位置,进行页面布局。从顶层父View向子View的递归调用view.layout方法的过程,即父View根据上一步measure子View所得到的布局大小和布局参数,将子View放在合适的位置上。

 

第三步:OnDraw():绘制视图。ViewRoot创建一个Canvas对象,然后调用OnDraw()。六个步骤:①、绘制视图的背景;②、保存画布的图层(Layer);③、绘制View的内容;④、绘制View子视图,如果没有就不用;

⑤、还原图层(Layer);⑥、绘制滚动条。

 

17、View,ViewGroup事件分发

1. Touch事件分发中只有两个主角:ViewGroup和View。ViewGroup包含onInterceptTouchEvent、dispatchTouchEvent、onTouchEvent三个相关事件。View包含dispatchTouchEvent、onTouchEvent两个相关事件。其中ViewGroup又继承于View。

2.ViewGroup和View组成了一个树状结构,根节点为Activity内部包含的一个ViwGroup。

3.触摸事件由Action_Down、Action_Move、Aciton_UP组成,其中一次完整的触摸事件中,Down和Up都只有一个,Move有若干个,可以为0个。

4.当Acitivty接收到Touch事件时,将遍历子View进行Down事件的分发。ViewGroup的遍历可以看成是递归的。分发的目的是为了找到真正要处理本次完整触摸事件的View,这个View会在onTouchuEvent结果返回true。

5.当某个子View返回true时,会中止Down事件的分发,同时在ViewGroup中记录该子View。接下去的Move和Up事件将由该子View直接进行处理。由于子View是保存在ViewGroup中的,多层ViewGroup的节点结构时,上级ViewGroup保存的会是真实处理事件的View所在的ViewGroup对象:如ViewGroup0-ViewGroup1-TextView的结构中,TextView返回了true,它将被保存在ViewGroup1中,而ViewGroup1也会返回true,被保存在ViewGroup0中。当Move和UP事件来时,会先从ViewGroup0传递至ViewGroup1,再由ViewGroup1传递至TextView。

6.当ViewGroup中所有子View都不捕获Down事件时,将触发ViewGroup自身的onTouch事件。触发的方式是调用super.dispatchTouchEvent函数,即父类View的dispatchTouchEvent方法。在所有子View都不处理的情况下,触发Acitivity的onTouchEvent方法。

7.onInterceptTouchEvent有两个作用:1.拦截Down事件的分发。2.中止Up和Move事件向目标View传递,使得目标View所在的ViewGroup捕获Up和Move事件。

 

18、Android UI适配

字体使用sp,使用dp,多使用match_parent,wrap_content,weight

图片资源,不同图片的的分辨率,放在相应的文件夹下可使用百分比代替。

19、HybridApp WebView和JS交互

Android与JS通过WebView互相调用方法,实际上是:

Android去调用JS的代码

1. 通过WebView的loadUrl(),使用该方法比较简洁,方便。但是效率比较低,获取返回值比较困难。

2. 通过WebView的evaluateJavascript(),该方法效率高,但是4.4以上的版本才支持,4.4以下版本不支持。所以建议两者混合使用。

JS去调用Android的代码

1. 通过WebView的addJavascriptInterface()进行对象映射 ,该方法使用简单,仅将Android对象和JS对象映射即可,但是存在比较大的漏洞。

 

漏洞产生原因是:当JS拿到Android这个对象后,就可以调用这个Android对象中所有的方法,包括系统类(java.lang.Runtime 类),从而进行任意代码执行。

解决方式:

(1)Google 在Android 4.2 版本中规定对被调用的函数以 @JavascriptInterface进行注解从而避免漏洞攻击。

(2)在Android 4.2版本之前采用拦截prompt()进行漏洞修复。

 

2. 通过 WebViewClient 的shouldOverrideUrlLoading ()方法回调拦截 url 。这种方式的优点:不存在方式1的漏洞;缺点:JS获取Android方法的返回值复杂。(ios主要用的是这个方式)

 

(1)Android通过 WebViewClient 的回调方法shouldOverrideUrlLoading ()拦截 url

(2)解析该 url 的协议

(3)如果检测到是预先约定好的协议,就调用相应方法

 

3. 通过 WebChromeClient 的onJsAlert()、onJsConfirm()、onJsPrompt()方法回调拦截JS对话框alert()、confirm()、prompt() 消息

这种方式的优点:不存在方式1的漏洞;缺点:JS获取Android方法的返回值复杂。

20、设计模式

此处延伸:Double Check的写法被要求写出来。

单例模式:分为恶汉式和懒汉式

恶汉式:

public class Singleton 

    private static Singleton instance = new Singleton(); 

    public static Singleton getInstance() 

    { 

        return instance ; 

    } 

}

 

懒汉式:

 

public class Singleton02 

    private static Singleton02 instance; 

 

    public static Singleton02 getInstance() 

    { 

        if (instance == null) 

        { 

            synchronized (Singleton02.class) 

            { 

                if (instance == null) 

                { 

                    instance = new Singleton02(); 

                } 

            } 

        } 

        return instance; 

    } 

}

 

21、RecyclerView和ListView的区别

RecyclerView可以完成ListView,GridView的效果,还可以完成瀑布流的效果。同时还可以设置列表的滚动方向(垂直或者水平);

RecyclerView中view的复用不需要开发者自己写代码,系统已经帮封装完成了。

RecyclerView可以进行局部刷新。

RecyclerView提供了API来实现item的动画效果。

在性能上:

如果需要频繁的刷新数据,需要添加动画,则RecyclerView有较大的优势。

如果只是作为列表展示,则两者区别并不是很大。

 

22、Universal-ImageLoader,Picasso,Fresco,Glide对比

Fresco 是 Facebook 推出的开源图片缓存工具,主要特点包括:两个内存缓存加上 Native 缓存构成了三级缓存,

优点:

1. 图片存储在安卓系统的匿名共享内存, 而不是虚拟机的堆内存中, 图片的中间缓冲数据也存放在本地堆内存, 所以, 应用程序有更多的内存使用, 不会因为图片加载而导致oom, 同时也减少垃圾回收器频繁调用回收 Bitmap 导致的界面卡顿, 性能更高。

 

2. 渐进式加载 JPEG 图片, 支持图片从模糊到清晰加载。

 

3. 图片可以以任意的中心点显示在 ImageView, 而不仅仅是图片的中心。

 

4. JPEG 图片改变大小也是在 native 进行的, 不是在虚拟机的堆内存, 同样减少 OOM。

 

5. 很好的支持 GIF 图片的显示。

 

缺点:

1. 框架较大, 影响 Apk 体积

2. 使用较繁琐

 

Universal-ImageLoader:(估计由于HttpClient被Google放弃,作者就放弃维护这个框架)

优点:

1.支持下载进度监听

2.可以在 View 滚动中暂停图片加载,通过 PauseOnScrollListener 接口可以在 View 滚动中暂停图片加载。

3.默认实现多种内存缓存算法 这几个图片缓存都可以配置缓存算法,不过 ImageLoader 默认实现了较多缓存算法,如 Size 最大先删除、使用最少先删除、最近最少使用、先进先删除、时间最长先删除等。

4.支持本地缓存文件名规则定义

     

Picasso 优点

1. 自带统计监控功能。支持图片缓存使用的监控,包括缓存命中率、已使用内存大小、节省的流量等。

 

2.支持优先级处理。每次任务调度前会选择优先级高的任务,比如 App 页面中 Banner 的优先级高于 Icon 时就很适用。

 

3.支持延迟到图片尺寸计算完成加载

 

4.支持飞行模式、并发线程数根据网络类型而变。 手机切换到飞行模式或网络类型变换时会自动调整线程池最大并发数,比如 wifi 最大并发为 4,4g 为 3,3g 为 2。  这里 Picasso 根据网络类型来决定最大并发数,而不是 CPU 核数。

 

5.“无”本地缓存。无”本地缓存,不是说没有本地缓存,而是 Picasso 自己没有实现,交给了 Square 的另外一个网络库 okhttp 去实现,这样的好处是可以通过请求 Response Header 中的 Cache-Control 及 Expired 控制图片的过期时间。

 

 Glide 优点

1. 不仅仅可以进行图片缓存还可以缓存媒体文件。Glide 不仅是一个图片缓存,它支持 Gif、WebP、缩略图。甚至是 Video,所以更该当做一个媒体缓存。

 

2. 支持优先级处理。

 

 

3. 与 Activity/Fragment 生命周期一致,支持 trimMemory。Glide 对每个 context 都保持一个 RequestManager,通过 FragmentTransaction 保持与 Activity/Fragment 生命周期一致,并且有对应的 trimMemory 接口实现可供调用。

 

4. 支持 okhttp、Volley。Glide 默认通过 UrlConnection 获取数据,可以配合 okhttp 或是 Volley 使用。实际 ImageLoader、Picasso 也都支持 okhttp、Volley。

 

 

5. 内存友好。Glide 的内存缓存有个 active 的设计,从内存缓存中取数据时,不像一般的实现用 get,而是用 remove,再将这个缓存数据放到一个 value 为软引用的 activeResources map 中,并计数引用数,在图片加载完成后进行判断,如果引用计数为空则回收掉。内存缓存更小图片,Glide 以 url、view_width、view_height、屏幕的分辨率等做为联合 key,将处理后的图片缓存在内存缓存中,而不是原始图片以节省大小与 Activity/Fragment 生命周期一致,支持 trimMemory。图片默认使用默认 RGB_565 而不是 ARGB_888,虽然清晰度差些,但图片更小,也可配置到 ARGB_888。

 

6.Glide 可以通过 signature 或不使用本地缓存支持 url 过期

 

 

转载于:https://my.oschina.net/u/1402366/blog/2996202

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
5. Android中的动画有哪几类,它们的特点和区别是什么? 两种.一种是Tween动画.还有一种是Frame动画. Tween动画,这种实现方式可以使视图组件移动.放大.缩小以及产生透明度的变化; 另一种Frame动画,传统的动画方法,通过顺序的播放排列好的图片来实现,类似电影. 6. 什么是嵌入式实时操作系统,Android操作系统属于实时操作系统吗? 嵌入式实时操作系统是指当外界事件或数据产生时,能够接受并以足够快的速度予以处理,其处理的结果又能在规定的时间之内来控制生产过程或对处理系统作出快速响应,并控制所有实时任务协调一致运行的嵌入式操作系统.主要用于工业控制,军事设备,航空航天等领域对系统的响应时间有苛刻的要求,这就需要使用实时系统.又可分为软实时和硬实时两种,而Android是基于linux内核的,因此属于软实时. 7. Handler机制的原理? Andriod提供了Handler和Looper来满足线程间的通信.Handler先进先出原则.Looper类用来管理特定线程内对象之间的消息交换(Message Exchange). 1)Looper:一个线程可以产生一个Looper对象,由它来管理此线程里的Message Queue(消息队列). 2)Handler:你可以构造Handler对象来与Looper沟通,以便push新消息到Message Queue里;或者接收Looper从Message Queue取出)所送来的消息. 3) Message Queue(消息队列):用来存放线程放入的消息. 4)线程:UI thread通常就是main thread,而Android启动程序时会替它建立一个Message Queue.

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值