Android面试题1(重点)

什么情况下会导致内存泄露

如何对Android 应用进行性能分析以及优化;

说一款你认为当前比较火的应用并设计(直播APP);

OOM的避免异常及解决方法;

1.什么是ANR 如何避免它?

Android App优化之ANR详解
ANR 应用程序无响应 根本原因不要在主线程(UI线程做繁重的工作)

使用主线程的地方

1.Activity的所有生命周期回调都是执行在主线城的
2.Service默认是执行在主线城的
3.BroadCastReceiver的onReceive回调是在主线程的
4.没有使用子线程的looper的Handler的handlerMessage,post(Runnable) 是在主线城的
5.AsyncTask的回调中除了doInBackground()方法,其他回调都是在主线城的
6.View的post(Runnable)是执行在主线城的

使用子线程的地方

1.使用Thread 方式
1)继承Thread 2)实现Runnable接口
2.使用AsyncTask方式
3.使用HandlerThread方式
Android中结合Handler和Thread的一种方式. 默认情况下Handler的handleMessage是执行在主线程的, 但是如果我给这个Handler传入了子线程的looper, handleMessage就会执行在这个子线程中的. HandlerThread正是这样的一个结合体:

 // 启动一个名为new_thread的子线程
HandlerThread thread = new HandlerThread("new_thread");
thread.start();
// 取new_thread赋值给ServiceHandler
private ServiceHandler mServiceHandler;
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
private final class ServiceHandler extends Handler {
    public ServiceHandler(Looper looper) {
      super(looper);
    }
    @Override
    public void handleMessage(Message msg) {
      // 此时handleMessage是运行在new_thread这个子线程中了.
    }
} 

4.IntentService
Service是运行在主线程的, 然而IntentService是运行在子线程的.
实际上IntentService就是实现了一个HandlerThread + ServiceHandler的模式.
以上HandlerThread的使用代码示例也就来自于IntentService源码

5.Loader
Android 3.0引入的数据加载器, 可以在Activity/Fragment中使用. 支持异步加载数据, 并可监控数据源在数据发生变化时传递新结果. 常用的有CursorLoader, 用来加载数据库数据.

 // Prepare the loader.  Either re-connect with an existing one,
// or start a new one.
// 使用LoaderManager来初始化Loader
getLoaderManager().initLoader(0, null, this);

//如果 ID 指定的加载器已存在,则将重复使用上次创建的加载器。
//如果 ID 指定的加载器不存在,则 initLoader() 将触发 LoaderManager.LoaderCallbacks 方法 //onCreateLoader()。在此方法中,您可以实现代码以实例化并返回新加载器

// 创建一个Loader
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
    // This is called when a new Loader needs to be created.  This
    // sample only has one Loader, so we don't care about the ID.
    // First, pick the base URI to use depending on whether we are
    // currently filtering.
    Uri baseUri;
    if (mCurFilter != null) {
        baseUri = Uri.withAppendedPath(Contacts.CONTENT_FILTER_URI,
                  Uri.encode(mCurFilter));
    } else {
        baseUri = Contacts.CONTENT_URI;
    }

    // Now create and return a CursorLoader that will take care of
    // creating a Cursor for the data being displayed.
    String select = "((" + Contacts.DISPLAY_NAME + " NOTNULL) AND ("
            + Contacts.HAS_PHONE_NUMBER + "=1) AND ("
            + Contacts.DISPLAY_NAME + " != '' ))";
    return new CursorLoader(getActivity(), baseUri,
            CONTACTS_SUMMARY_PROJECTION, select, null,
            Contacts.DISPLAY_NAME + " COLLATE LOCALIZED ASC");
}

// 加载完成
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
    // Swap the new cursor in.  (The framework will take care of closing the
    // old cursor once we return.)
    mAdapter.swapCursor(data);
} 

View的绘制流程

View的绘制是从ViewRoot的performTraversals()方法开始的,经过measure,layout,draw这个3大步骤。

measure的过程:

measure过程是对整个view树的所有控件计算宽高
measure是冲ViewRoot类中的host.measure开始的,内部调用的是View的measure(int widthMeasureSpec,int heightMeasureSpec)方法,measure方法里面调用了onMeasure(int widthMeasureSpec,int heightMeasureSpec)方法,方法中的两个参数都是是MeasureSpec类型(指父控件对子控件宽高的期望值,它是一个32位的int类型数,前两位表示测量模式,后30位表示测量大小)
测量模式一共有3种:
1)EXACTLY 精确测量模式,xml文件中写200dp,march_parent等代表使用该模式,
2)AT_MOST 最大模式,xml文件中写wrap_content表示使用该模式。
3)UNSPECIFIED 无限大测量模式,只有在绘制特定自定义View时才用的到这个模式。
真正代表测量结束的方法是setMeasuredDimension方法,该方法传入的两个参数是宽高的SpecSize。测量结束后我们可以通过getMeasureHeight和getMeasureWidth来获取测量宽高。
自定义ViewGroup一定要重写onMeasure方法,用于测量子View的宽高,不重写的话子View没有宽高。
自定义View如果在xml中使用了wrap_content属性,就需要重写onMeasure方法来设置wrap_content的默认大小,不然会显示出match_parent的效果。

layout的过程:

ViewGroup用来将子View放在合适的位置上。
layout是从ViewRoot类中的host.layout开始的,内部调用的是ViewGroup的layout方法。在ViewGroup的layout方法中,先调用setFrame来确定自己的左上右下的位置,再调用onLayout来确定子View的位置。
自定义ViewGroup一定要重写layout方法来确定子View的位置,自定义View一般不需要重写该方法,它的位置是右父控件确定的。

draw过程:

此过程是真正将内容展示在屏幕上让我们能够看到的过程。
draw是从ViewRoot类中的host.draw开始的,内部调用的是View的draw方法。
draw的步骤:
1)绘制背景。
2)绘制内容,也就是调用onDraw方法。
3)绘制子View,调用的是dispatchDraw方法。
4)绘制装饰,如listview的滚动条等。

对于View的绘制过程,既可以说是简单的,也可以说是复杂的,简单的在于Google已经帮我们将draw框架写好了,我们在自定义ViewGroup时不用管draw过程,只需要实现measure和layout过程。复杂在于,我们写继承View的自定义控件的时候需要重写onDraw方法,这样才能绘制出你自定义的View的内容,onDraw(Canvas canvas)方法中最重要的两个东西是Paint和Canvas,这个使用起来算是比较复杂的。
Android View的绘制流程

自定义View如何考虑机型适配

  • 合理使用warp_content,match_parent.
  • 尽可能的是使用RelativeLayout
  • 针对不同的机型,使用不同的布局文件放在对应的目录下,android会自动匹配。
  • 尽量使用点9图片。
  • 使用与密度无关的像素单位dp,sp
  • 引入android的百分比布局。
  • 切图的时候切大分辨率的图,应用到布局当中。在小分辨率的手机上也会有很好的显示效果。

自定义View的事件分发机制

安卓自定义View进阶-事件分发机制详解

安卓自定义View进阶-事件分发机制原理

View和ViewGroup分别有哪些事件分发相关的回调方法

自定义View如何提供获取View属性的接口

自定义属性+接口回调Demo

Art和Dalvik对比

在程序运行过程中Dalvik虚拟机不断的进行将字节码转换为机器码的工作。
而Art引入了AOT这种预编译技术,在应用程序的安装过程中已经将所有的字节码编译为了机器码,在运行的时候直接调用。Art极大的提高了程序的运行效率,同时减少了手机的耗电量,在垃圾回收机制上也有很大的优化,但是Art模式下应用程序的安装需要消耗更多的时间,同时也需要跟多的安装空间。
Dalvik 是Android4.4及以下平台的虚拟机。
Art 是在Android4.4以上平台使用的虚拟机。

虚拟机原理,如何自己设计一个虚拟机(内存管理,类加载,双亲委派);

JVM内存模型及类加载机制

内存对象的循环引用及避免

ddms 和 traceView的区别

1, ddms:是android开发环境中的dalvik虚拟机调试监控服务;
ddms能够提供,测试设备截屏,针对特定的进程查看正在运行的线程以及堆信息,Logcat,广播状态信息,模拟电话呼叫,接收sms,虚拟地理坐标等。
2,traceView是android平台配备的性能分析的工具;它可以通过图形化让我们了解要跟踪的程序的性能,并且能具体到方法。
区别:ddms是一个程序执行查看器,在里面可以看见线程和堆栈等信息,traceView是程序性能分析器。

内存回收机制与GC算法(各种算法的优缺点以及应用场景)

gc是java的垃圾回收机制

  • 引用计数法(Reference Counting Collector):使用计数器来区分存活对象和不再使用的对象。一般来说,堆中的每个对象对应一个引用计数器。当每一次创建一个对象并赋给一个变量时,引用计数器置为1。当对象被赋给任意变量时,引用计数器每次加1当对象出了作用域后(该对象丢弃不再使用),引用计数器减1,一旦引用计数器为0,对象就满足了垃圾收集的条件。

  • 标记算法(Tracing Collector):使用了根集的概念,基于tracing算法的垃圾收集器从根集开始扫描,识别出哪些对象可达,哪些对象不可达,并用某种方式标记可达对象。

  • 整理算法(Compacting Collecotr):该算法会将所有的对象移到堆的一端。能解决堆碎片的问题。

  • 复制算法:将内存分为两个区域(from space 和 to space)。所有的对象都分配到from space。清理时先将所有标为活动对象copy到to space,然后清除from space空间。然后互换from space和to apce的身份,每次清理都重复上述过程。
    gc收集器:

  • serial收集器:单线程,工作时必须暂停其他工作线程,多用于client机器上,使用复制算法。

  • ParNew收集器:serial的多线程版本,server模式下jvm首选的新生代收集器。复制算法。

  • Parallel Scavenge收集器:可控制吞吐量的收集器,吞吐量指有效运行时间。复制算法。

  • Serial Old收集器:serial的老年代版本,使用整理算法。

  • Parallel Old收集器:Parallel Scavenge收集器的老版本,多线程,标记整理。

  • CMS收集器:整理算法。最短回收停顿时间,缺点是产生碎片。

  • GI收集器:基本思想是化整为零,将堆分为多个Region,优先回收价值最大的Region。并行并发,分代收集,空间整合。整理算法。

GC原理时机以及GC对象

内存泄露场景及解决方法

屏幕适配的处理技巧都有哪些

Android 屏幕适配

四大组件及生命周期

Activity
Service
Service 官方资料 需翻墙
Service 资料
ContentProvider
BroadcastReceiver

ContentProvider的权限管理(读写分离,权限控制-精确到表级,URL控制);

Activity的四种启动模式对比

Android 深入解析 Activity 的 launchMode 启动模式,Intent Flag,taskAffinity

Activity状态保存于恢复

什么是AIDL 以及如何使用

AIDL:android interface definition language的缩写。
AIDL是用来实现进程间通信的,可以帮我们实现发布以及调用远程服务。
使用:
1)服务端:创建一个Service用来监听客户端的连接请求,然后创建一个AIDL文件,将服务端暴露给客户端的接口在这个文件中声明,最后在Service中实现这个AIDL接口。
2)客户端:首先绑定服务端的Service,绑定成功后将服务端返回的Binder对象转成AIDL接口所属的类型,接着就可以调用AIDL中的方法。

请解释下在单线程模型中Message、Handler、Message Queue、Looper之间的关系

Android--异步消息处理机制(Handler、Looper、Message、MessageQueue)

Fragment生命周期

onAttach(),onCreate(),onCreateView(),onActivityCreated(),onViewStateRestore(),onStart(),onResume(),onPause(),onStop(),onDestroy(),onDestroyView(),onDetach(),

Fragment状态保存

startActivityForResult是哪个类的方法,在什么情况下使用,如果在Adapter中使用应该如何解耦

AsyncTask原理及不足

intentService原理

HandlerThread+ServiceHandler

Activity 怎么和Service 绑定,怎么在Activity 中启动自己对应的Service

请描述一下Service 的生命周期;

启动服务的生命周期 onCreate->onStartCommand()->onDestroy()
绑定服务的生命周期 onCreate()->onBind()->onUnBind()->onDestroy()

AsyncTask+HttpClient与AsyncHttpClient有什么区别;

如何保证一个后台服务不被杀死,比较省电的方式是什么

Android中通过Service实现后台任务。
方法一:
通过将Service绑定到Notification,成为一个前提服务,可以提高存活率
在Service中创建一个Notification,再调用Service.startForeground(int id,Notification notification)方法运行在前台即可。这个方式使用360等如阿健管家可以杀死。

方法二:
通过定时警报来不断启动Service,这样就算Service被杀死,也能再启动。同时也可以监听网络切换,开锁屏等广播启动Service。
参考:
Intent intent = new Intent(mContext,MyService.class);
PendingIntent sender = PendingIntent.getService(mContext,0,intent,0);
AlarmManager alarm = (AlarmManager)getSystemService(ALARM_SERVICE);
alarm.setRepeating(AlarmManager.RTC_WAKEUP,System.currentTimeMillis(),5*10000,sender);
这种方式不断启动的逻辑处理起来很麻烦。

方法三:
通过jni调用c,在c语音中启动一个进程fork()。 可以保证360等手机管家不会清理。但是带来了jni交互,稍微有点麻烦。

如何通过广播拦截和abort一条短信;

广播是否可以请求网络

广播引起anr的时间限制

进程间通信,AIDL

事件分发中的onTouch 和onTouchEvent 有什么区别,又该如何使用?

说说ContentProvider、ContentResolver、ContentObserver 之间的关系;

请介绍下ContentProvider 是如何实现数据共享的

Android提供了ContentProvider,一个程序可以通过实现一个ContentProvider的抽象接口将自己的数据完全暴露出去,而且ContentProvicer是以类似数据库中表的方式将数据暴露。也就是说ContentProvider就像一个“数据库”。那么外界获取其提供的数据,也就应该与从数据库中获取数据的操作基本一样,只不过是采用URI来表示外界需要访问的“数据库”。外部访问通过ContentResolver去访问并操作这些被暴露的数据。

Handler机制及底层实现

Handler包括四个角色:
Handler:负责发送消息处理消息。
Message:消息实体对象,handler通过sendMessage将实体放到消息队列中。
MessageQueQue:存放消息的队列。
Looper:消息轮询器,不停的从消息队列中取出消息交给handler处理。
在主线程创建Handler,在需要发送消息的地方创建一个Message,通过handler发送。这个消息回到MessageQueQue中,然后Looper会将这个消息取出交给handler处理。

Handler可以有多个,但是在同一线程中Looper和MessageQueQue只能有一个。

Binder机制及底层实现

Binder包含四个角色:

Server 服务器
Client 客户终端 ,获得实名Binder的引用。Server向ServiceManger注册了Binder实体及名字后,Client就可以通过名字获得该Binder的引用。例如我们申请获得名字叫张三的Binder的引用,ServiceManager收到这个连接请求,从请求数据包里获得Binder的名字。再找到该名字对应的条目,从条目中取出Binder的引用。将该引用作为回复发送给发起请求的Client。
ServiceManager 域名服务器(DNS),负责将字符形式的Binder名字转化成Client中对该Binder的应用,使得Client能通过Binder名字获得Server中Binder实体的引用。
Binder驱动 可以理解为路由器。Binder驱动负责进程之间Binder通信的建立,Binder在进程间的传递。
Binder使用Client-Server通信方式,安全性好,简单高效。再加上其面向对象的设计思想,独特的接收缓存管理和线程池管理方式,成为Android进程间通信的中流砥柱。

ListView 中图片错位的问题是如何产生的

错位原理: 如果我们只是简单的显示数据,没有convertView的复用和异步操作,就不会产生图片错位。重用convertView但没有异步操作也不会有错位现象。例如我们的listView中刚好显示7个item,当向下滑动时,显示出item8,而item8是重用的item1,如果此时异步网络请求item8的图片,比item1的图片慢,那么item8就会显示item1的图片。当item8下载完成,此时用户向上滑显示item1时,又复用的item8的image。这样就导致的图片错位。
解决方法: 对imageview设置tag,并预设一张图片。向下滑动后,item8显示,item1隐藏。但由于item1是第一次进来就显示所以一般情况下,item1都会比item8先下载完,此时可见的item8的tag和隐藏了的item1的url不匹配,所以就算item1的图片下载完也不会显示到item8中,因为tag标识的永远是可见图片中的url

holder.img.setTag(imgUrl);
holder.img.setImageResource(R.drawable.ic_launcher);
if(imageView.getTag() != null && imageView.getTag().equals(imageUrl)){ imageView.setImageBitmap(result);}

在manifest 和代码中如何注册和使用BroadcastReceiver

<receiver android:name="包名.自己扩展的广播接收者名">
<intent-filter>
<action android:name="android.provider.Telephony.SMS_RECEIVED"/>
</intent-filter>
</receiver>

说说Activity、Intent、Service 是什么关系

ApplicationContext和ActivityContext的区别

这是两种不同的context,也是最常见的两种.第一种中context的生命周期与Application的生命周期相关的,context随着Application的销毁而销毁,伴随application的一生,与activity的生命周期无关.第二种中的context跟Activity的生命周期是相关的,但是对一个Application来说,Activity可以销毁几次,那么属于Activity的context就会销毁多次.至于用哪种context,得看应用场景,个人感觉用Activity的context好一点,不过也有的时候必须使用Application的context.application context

一张Bitmap所占内存以及内存占用的计算

Serializable 和Parcelable 的区别

在Android上应该尽量采用Parcelable,它效率更高。
Parcelabe代码比Serializable多一些。
Parcelabe比Serializable速度高十倍以上。
Serializable只需要对某个类以及它的属性实现Serializable接口即可,无需实现方法。缺点是使用的反射,序列化的过程较慢,这种机制会在序列化的时候创建许多的临时对象。容易触发GC。
Parcable方法实现的原理是将一根完整的对象进行分解,而分解后的每一部分都是Intent所支持的数据类型,这样也就实现传递对象的功能。

请描述一下BroadcastReceiver

请描述一下Android 的事件分发机制

请介绍一下NDK

一 : NDK是一系列工具的集合
NDK提供了一系列的工具,帮助开发者快速开发C或C++的动态库,并能自动将so和java应用一起打包成apk。这些工具对开发者的帮助是巨大的。
NDK集成了交叉编译器,并提供了相应的mk文件隔离CPU,平台,ABI等差异。开发人员只需要简单修改mk文件(指出哪些文件需要编译,编译特性要求等)就可以创建出so。
NDK可以自动将so和java应用一起打包,极大的减轻了开发人员的打包工作。
二 : NDK提供了一份稳定,功能有限的API头文件声明。
Google明确声明该API是稳定的,在后续所有版本中都稳定支持当前发布的API。从该版本的NDK中看出,这些API支持的功能非常有限,包含:c标准库,标准数学库,压缩库,Log库。

什么是NDK库,如何在jni中注册native函数,有几种注册方式

AsyncTask 如何使用;

对于应用更新这块是如何做的?(灰度,强制更新,分区域更新);

混合开发,RN,weex,H5,小程序(做Android的了解一些前端js等还是很有好处的)

混合开发就是在一个App中内嵌一个轻量级的浏览器,一部分源生的功能改为Html5来开发,这部分功能不仅能够在不升级App的情况下动态更新,也可以在Android或者iOS的App上同时运行,让用户的体验更好又可以节省开发的资源。
混合开发最主要的是Html5和Native的交互
在Android中WebView本来就支持js和java相互调用,只需要开启WebView的脚本执行,然后通过mWebView.addJavascriptInterface(new JsBridge(),"bxbxbai");向Html5页面注入一股Java对象,然后就可以在Html5页面中调用Native的功能了。
Android4.2以后的系统规定允许被js调用的Java方法必须以@JavascriptInterface进行注解。

两个Activity 之间跳转时必然会执行的是哪几个方法?

答:一般情况下比如说有两个activity,分别叫A,B,当在A 里面激活B 组件的时候, A 会调用onPause()方法,然后B 调用onCreate() ,onStart(), onResume()。
这个时候B 覆盖了窗体, A 会调用onStop()方法. 如果B 是个透明的,或者是对话框的样式, 就不会调用A 的onStop()方法。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,884评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,347评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,435评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,509评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,611评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,837评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,987评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,730评论 0 267
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,194评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,525评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,664评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,334评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,944评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,764评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,997评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,389评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,554评论 2 349

推荐阅读更多精彩内容