转载:http://stane.sinaapp.com/android面试必过-android常见问题/常见问题/
水平有限,请提出错误。
Android常见的问题
标签(空格分隔): 移动开发
- 常见算法问题 Java 实现
算法是许多公司必须面试的,国内 BAT 基有基本面试,尤其是百度。
- 常见的设计模式 Java 实现
- Android 开源项目源码分析
Android 开源项目源代码分析网页版本。无论如何,只要是高级开发人员,我就会问他项目中使用的库原理,这是我对高级开发人员的一般要求。
国内中大型企业和优秀初创企业更注重原则,知道为什么。
- 你可以遇到问题@的那些 Android 开发者
首先,我们建议遇到问题。 Google,无果可 @ GitHub 上的 Android 开发者(好像我暴露了他们。( ⊙ o ⊙ ))。
- Java 基础之 String、StringBuilder、StringBuffer、CharSequence 区别
两个更好的答案:
NO1
1) CharSequence接口:字符序列.String StringBuilder 和 StringBuffer都实现了它. 2) String类:是常量,不可变. 3) StringBuilder类别;单线程只能修改(线程不安全). 4) StringBuffer类别:多线程(线程安全)可以改变. 5)Stringbuilder比StringBuffer效率高,应尽量使用StringBuilder.
NO2
1.CharSequence是一个java接口,代表一个char序列,String、StringBuilder、StringBuffer接口已经实现,CharSequence通过调用实例toString该方法可转化为String对象。 2.String类是final是的,不能派生子,内部包装是char[],另外,android下的String类和jdk中的String类别不同,android下的String类中部分API通过native实现方法,效率相对较高。 3.String使用’ 当字符串拼接时,编译期将转换为StringBuilder#append方式 4.String内存中有一个常量池,两个相同的串在池中只有一个例子(String s = “abc”方式或者String#intern在池中分配方法),使用new String方式会在heap每一次创建都是一个全新的例子。 5.StrigBuilder & StringBuffer它们都是可扩展的串,提供了一系列apped拼接不同类型对象的方法 6.StringBuffer于jdk1.0引入,线程安全(多线程场景使用),StringBuilder于jdk1.线程不安全,效率更高。 7.StringBuilder & StringBuffer初始容量为16,开发者应指定其容量,以避免多次扩容带来的性能问题。
- Java 基础继承与接口的区别
- 抽象类:
抽象体现了数据抽象的思想,是实现多态化的机制。它定义了一组抽象实现的一组抽象方法。同时,抽象类提供了继承的概念,其出发点是继承,否则就没有存在的意义。因此,定义的抽象类必须用于继承。同时,在以抽象类为节点的继承关系等级链中,叶节必须是具体的实现类。 语法: 1.由abstract关键词修饰的类称为抽象类。 2.抽象类中未实现的方法称为抽象方法,也需要添加关键字abstract。 3.抽象类也可以没有抽象方法,比如HttpServlet方法。 4.抽象类中可以定义成员变量的方法。
- 接口: 界面用于建立类与类之间的协议,它只提供一种形式,没有具体实现。同时,要实现接口的实现必须通过使用实现接口的所有方法implements关键字。 接口是抽象类的延伸,java为了确保数据的安全,不能多次继承,也就是说,继承只能有一个父亲,但接口不同,一个类可以同时实现多个接口,无论这些接口之间是否有关系,所以接口弥补了抽象类不能多次继承的缺陷, 语法方面: 1.由interface关键词修改称为接口; 成员变量可以在接口中定义,但这些成员的变量是默认的public static final的常量。 3.界面中没有实现的方法,都是抽象的。 3.界面中没有实现的方法,都是抽象的。 4.一个类实现一个接口,必须实现界面中定义的所有方法。 5.一个类可以实现多个接口。
区别: 一.语法水平:如上所述。 二.设计层次: 1、 不同层次的抽象。抽象是对类抽象,接口是行为抽象。抽象是抽象整个类,包括属性和行为,但接口是抽象局部(行为)。 2、 跨域不同。抽象类所跨域的是具有相似特点的类,而接口却可以跨域不同的类。我们知道抽象类是从子类中发现公共部分,然后泛化为抽象类。子类可以继承父类,但接口不同。实现它的子类可以没有任何关系和共同点。比如猫狗可以抽象成动物抽象,有叫的方法。鸟,飞机可以飞Fly接口,有飞行行为,这里我们不能把鸟,飞机共享一个父亲!因此,抽象类反映了一种继承关系。为了使继承关系合理,父类和衍生类必须存在。is-a” 关系,即父类和衍生类在概念本质上应该是一样的。接口不是,接口的实现者和接口定义在概念本质上是一致的, 只是实现了界面定义的合同,相当于like-a”的关系。 3、 不同层次的设计。对于抽象类,它是自下而上设计的。我们需要知道子类可以抽象父类,而接口是不同的。它根本不需要知道子类的存在。它只需要定义一个规则。我们不知道什么子类,什么时候如何实现。比如我们这里只有一只猫,如果你抽象成动物,设计是不是有点过分?我们至少应该有两种动物,猫和狗在这里。让我们在抽象中形成动物抽象!所以说抽象类往往都是通过重构而来的!但是接口是不同的。例如,我们不知道飞行接口将实现什么。我们不知道如何实现它。我们需要做的是提前定义飞行行为接口。因此,抽象类是自底向上抽象的,接口是自顶向下设计的。
附加,空接口的作用: 通常作为标记,你就像这样Serializable、Cloneable。
- Android何时在开发过程中使用多进程?
要知道如何使用多个过程,首先要知道Android多过程概念。一般来说,应用程序是一个过程进程名称就是应用程序包名。我们知道进程是系统分配资源和调度的基本单位,所以每个进程都有自己独立的资源和内存空间,别的进程是不能任意访问其他进程的内存和资源的。那如何让自己的应用拥有多个进程?很简单,我们的四大组件在AndroidManifest文件中注册的时候,有个属性是 android:process
:
-
这里可以指定组件的所处的进程。默认就是应用的主进程。指定为别的进程之后,系统在启动这个组件的时候,就先创建(如果还没创建的话)这个进程,然后再创建该组件。你可以重载Application类的onCreate方法,打印出它的进程名称,就可以清楚的看见了。再设置android:process属性时候,有个地方需要注意:如果是android:process=”:deamon”,以:开头的名字,则表示这是一个应用程序的私有进程,否则它是一个全局进程。私有进程的进程名称是会在冒号前自动加上包名,而全局进程则不会。一般我们都是有私有进程,很少使用全局进程。他们的具体区别不知道有没有谁能补充一下。 源文档地址
-
使用多进程显而易见的好处就是分担主进程的内存压力。我们的应用越做越大,内存越来越多,将一些独立的组件放到不同的进程,它就不占用主进程的内存空间了。当然还有其他好处,有心人会发现Android后台进程里有很多应用是多个进程的,因为它们要常驻后台,特别是即时通讯或者社交应用,不过现在多进程已经被用烂了。典型用法是在启动一个不可见的轻量级私有进程,在后台收发消息,或者做一些耗时的事情,或者开机启动这个进程,然后做监听等。还有就是防止主进程被杀守护进程,守护进程和主进程之间相互监视,有一方被杀就重新启动它。应该还有还有其他好处,这里就不多说了。
-
坏处的话,多占用了系统的空间,大家都这么用的话系统内存很容易占满而导致卡顿。消耗用户的电量。应用程序架构会变复杂,应为要处理多进程之间的通信。这里又是另外一个问题了。
- 设备横竖屏切换的时候,接下来会发生什么
我们一般看到的答案:
-
不设置Activity的android:configChanges时,切屏会重新调用各个生命周期,切横屏时会执行一次,切竖屏时会执行两次
-
设置Activity的android:configChanges=”orientation”时,切屏还是会重新调用各个生命周期,切横、竖屏时只会执行一次
-
设置Activity的android:configChanges=”orientation|keyboardHidden”时,切屏不会重新调用各个生命周期,只会执行onConfigurationChanged方法
这个是不完整的。下面的文字引自Android Developer:
Caution: Beginning with Android 3.2 (API level 13), the "screen size"
also changes when the device switches between portrait and landscape orientation. Thus, if you want to prevent runtime restarts due to orientation change when developing for API level 13 or higher (as declared by the minSdkVersion and targetSdkVersion attributes), you must include the “screenSize” value in addition to the “orientation” value. That is, you must decalare android:configChanges=”orientation|screenSize”. However, if your application targets API level 12 or lower, then your activity always handles this configuration change itself (this configuration change does not restart your activity, even when running on an Android 3.2 or higher device).
也就是说:当API >12时,需要加入screenSize属性,否则屏幕切换时即使你设置了orientation系统也会重建Activity.
- 要做一个尽可量流畅的ListView,你可以做到的优化手段是什么?越详细越多手段越好
- 复用convertView
- 使用ViewHolder
- item中有图片时,异步加载
- 快速滑动时,不加载图片
- item中有图片时,应对图片进行适当压缩
- 分批和分页加载
- java虚拟机的运行原理
- 继承viewGroup后必须实现哪些方法,这些方法有谁调用
继承ViewGroup后,IDE会提示提供构造方法和实现 onLayout()
方法。
在ViewGroup中只有一个抽象的方法 onLayout()
,所以必须实现它;如果执行 requestLayout()
请求重新调整位置会调用到 onLayout()
。
- android 关于安全的问题,你所知道的所有的安全问题
- 错误导出组件
- 参数校验不严
- WebView引入各种安全问题
- 不混淆、不防二次打包
- 明文存储关键信息
- 错误使用HTTPS
- 山寨加密方法
- 对称加密和非对称加密
对称加密,就是加密和解密数据都是使用同一个key,这方面的算法有DES。 非对称加密,加密和解密是使用不同的key。发送数据之前要先和服务端约定生成公钥和私钥,使用公钥加密的数据可以用私钥解密,反之。这方面的算法有RSA。ssh 和 ssl都是典型的非对称加密。
- Activity的四种launchMode
Activity一共有以下四种launchMode:
- standard
- singleTop
- singleTask
- singleInstance
我们可以在AndroidManifest.xml配置的android:launchMode属性为以上四种之一即可。 下面我们结合实例一一介绍这四种lanchMode: 1.standard standard模式是默认的启动模式,不用为配置android:launchMode属性即可,当然也可以指定值为standard。standard启动模式,不管有没有已存在的实例,都生成新的实例。
2.singleTop 我们在上面的基础上为指定属性android:launchMode=”singleTop”,系统就会按照singleTop启动模式处理跳转行为。跳转时系统会先在栈结构中寻找是否有一个Activity实例正位于栈顶,如果有则不再生成新的,而是直接使用。如果系统发现存在有Activity实例,但不是位于栈顶,重新生成一个实例。 这就是singleTop启动模式,如果发现有对应的Activity实例正位于栈顶,则重复利用,不再生成新的实例。
3.singleTask 如果发现有对应的Activity实例,则使此Activity实例之上的其他Activity实例统统出栈,使此Activity实例成为栈顶对象,显示到幕前。
4.singleInstance 这种启动模式比较特殊,因为它会启用一个新的栈结构,将Acitvity放置于这个新的栈结构中,并保证不再有其他Activity实例进入。
- Android启动Service的两种方式是什么? 它们的适用情况是什么
- startService:生命周期与调用者不同。启动后若调用者未调用stopService而直接退出,Service仍会运行
- bindService:生命周期与调用者绑定,调用者一旦退出,Service就会调用unBind->onDestroy
- 谈谈你对Android中Context的理解
- Java中反射的作用是什么?什么时候会用到
JAVA反射机制是在#运行时#,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。 Java反射机制主要提供了以下功能: a)在运行时判断任意一个对象所属的类; b)在运行时构造任意一个类的对象; c)在运行时判断任意一个类所具有的成员变量和方法; d)在运行时调用任意一个对象的方法;生成动态代理。
- 注册广播有几种方式,这些方式有何优缺点?请谈谈Android引入广播机制的用意
1.在清单文件中注册, 常见的有监听设备启动,常驻注册不会随程序生命周期改变 2.在代码中注册,随着程序的结束,也就停止接受广播了
Android引入广播机制的用意:
a:从MVC的角度考虑(应用程序内) 其实回答这个问题的时候还可以这样问,android为什么要有那4大组件,现在的移动开发模型基本上也是照搬的web那一套MVC架构,只不过是改了点嫁妆而已。android的四大组件本质上就是为了实现移动或者说嵌入式设备上的MVC架构,它们之间有时候是一种相互依存的关系,有时候又是一种补充关系,引入广播机制可以方便几大组件的信息和数据交互。
b:程序间互通消息(例如在自己的应用程序内监听系统来电)
c:效率上(参考UDP的广播协议在局域网的方便性)
d:设计模式上(反转控制的一种应用,类似监听者模式)
- Java中有内存泄露吗?举一些例子?JNI中呢
1.查询数据库没有关闭游标 2. 构造Adapter时,没有使用缓存的 convertView 3. Bitmap对象不再使用时调用recycle()释放内存 4. 无用时没有释放对象的引用 5. 在Activity中使用非静态的内部类,并开启一个长时间运行的线程,因为内部类持有Activity的引用,会导致Activity本来可以被gc时却长期得不到回收 6.使用Handler处理消息前,Activity通过例如finish()退出,导致内存泄漏 7.动态注册广播在Activity销毁前没有unregisterReceiver
- 请介绍下Android中常用的五种布局
我常用的: linearlayout
, RelativeLayout
, FrameLayout
, TableLayout
很少用到, GridLayout
用过一次。
- 请介绍下Android的数据存储方式
google官方的数据存储方式的定义共有五种:
- sharedPreference
- 内存存储
- 外部存储(其实就是文件存储)
- SQlite
- 网络存储
- Service的onCreate回调在UI线程中吗
Service生命周期的各个回调和其他的应用组件一样,是跑在主线程中,会影响到你的UI操作或者阻塞主线程中的其他事情
- 请介绍下ContentProvider是如何实现数据共享的
当一个应用程序需要把自己的数据暴露给其他程序使用时,该就用程序就可通过提供ContentProvider来实现;其他应用程序就可通过 ContentResolver
来操作ContentProvider暴露的数据。 一旦某个应用程序通过ContentProvider暴露了自己的数据操作接口,那么不管该应用程序是否启动,其他应用程序都可以通过该接口来操作该应用程序的内部数据,包括增加数据、删除数据、修改数据、查询数据等。 ContentProvider 以某种Uri的形式对外提供数据
,允许其他应用访问或修改数据;其他应用程序使用ContentResolver根据Uri去访问操作指定数据。 步骤: 1、定义自己的ContentProvider类,该类需要继承Android提供的ContentProvider基类。 2、在AndroidManifest.xml文件中注册个ContentProvider,注册ContenProvider时需要为它绑定一个URL。 例: android:authorities=”com.myit.providers.MyProvider” /> 说明:authorities就相当于为该ContentProvider指定URL。 注册后,其他应用程序就可以通过该Uri来访问MyProvider所暴露的数据了。
接下来,使用ContentResolver操作数据,Context提供了如下方法来获取ContentResolver对象。 一般来说,ContentProvider是单例模式,当多个应用程序通过ContentResolver来操作 ContentProvider提供的数据时,ContentResolver调用的数据操作将会委托给同一个ContentProvider处理。 使用ContentResolver操作数据只需两步: 1、调用Activity的ContentResolver获取ContentResolver对象。 2、根据需要调用ContentResolver的insert()、delete()、update()和query()方法操作数据即可.
- 请介绍下AsyncTask的内部实现,适用的场景是
Android AsyncTask完全解析,带你从源码的角度彻底理解
AsyncTask内部也是Handler机制来完成的,只不过Android提供了执行框架来提供线程池来执行相应地任务,因为线程池的大小问题,所以AsyncTask只应该用来执行耗时时间较短的任务,比如HTTP请求,大规模的下载和数据库的更改不适用于AsyncTask,因为会导致线程池堵塞,没有线程来执行其他的任务,导致的情形是会发生AsyncTask根本执行不了的问题。
- 谈谈你对binder机制的理解
Android进程间通信(IPC)机制Binder简要介绍和学习计划 bind service
binder是一种IPC机制,进程间通讯的一种工具.
Java层可以利用aidl工具来实现相应的接口.
- Android中进程间通信有哪些实现方式?原理是什么
Intent,Binder(AIDL),Messenger,BroadcastReceiver
1.明确需求,确定你想实现的效果 2.确定是使用组合控件的形式还是全新自定义的形式,组合控件即使用多个系统控件来合成一个新控件,你比如titilebar,这种形式相对简单, 参考3.如果是完全自定义一个view的话,你首先需要考虑继承哪个类,是View呢,还是ImageView等子类。 4.根据需要去复写View#onDraw、View#onMeasure、View#onLayout方法 5.根据需要去复写dispatchTouchEvent、onTouchEvent方法 6.根据需要为你的自定义view提供自定义属性,即编写attr.xml,然后在代码中通过TypedArray等类获取到自定义属性值 7.需要处理滑动冲突、像素转换等问题
另外一个回答
- 编写attr.xml文件
- 在layout布局文件中引用,同时引用命名空间
- 在自定义控件中进行读取(构造方法拿到attr.xml文件值)
- 覆写onMeasure()方法
- 覆写onLayout()方法
- Android中touch事件的传递机制是怎样的?
事件传递:
基础知识
(1) 所有Touch事件都被封装成了MotionEvent对象,包括Touch的位置、时间、历史记录以及第几个手指(多指触摸)等。
(2) 事件类型分为ACTION_DOWN, ACTION_UP, ACTION_MOVE, ACTION_POINTER_DOWN, ACTION_POINTER_UP, ACTION_CANCEL,每个事件都是以ACTION_DOWN开始ACTION_UP结束。
(3) 对事件的处理包括三类,分别为传递——dispatchTouchEvent()函数、拦截——onInterceptTouchEvent()函数、消费——onTouchEvent()函数和OnTouchListener
传递流程
(1) 事件从Activity.dispatchTouchEvent()开始传递,只要没有被停止或拦截,从最上层的View(ViewGroup)开始一直往下(子View)传递。子View可以通过onTouchEvent()对事件进行处理。
(2) 事件由父View(ViewGroup)传递给子View,ViewGroup可以通过onInterceptTouchEvent()对事件做拦截,停止其往下传递。
(3) 如果事件从上往下传递过程中一直没有被停止,且最底层子View没有消费事件,事件会反向往上传递,这时父View(ViewGroup)可以进行消费,如果还是没有被消费的话,最后会到Activity的onTouchEvent()函数。
(4) 如果View没有对ACTION_DOWN进行消费,之后的其他事件不会传递过来。
(5) OnTouchListener优先于onTouchEvent()对事件进行消费。 上面的消费即表示相应函数返回值为true。
PRE_andevcon_mastering-the-android-touch-system Touch 事件的分发和消费机制
- ANR是什么?怎样避免和解决ANR
ANR:Application Not Responding,即应用无响应
ANR一般有三种类型:
1: KeyDispatchTimeout(5 seconds)
–主要类型
按键或触摸事件在特定时间内无响应
2: BroadcastTimeout(10 seconds)
BroadcastReceiver在特定时间内无法处理完成
3: ServiceTimeout(20 seconds)
–小概率类型
Service在特定的时间内无法处理完成
超时的原因一般有两种:
(1)当前的事件没有机会得到处理(UI线程正在处理前一个事件没有及时完成或者looper被某种原因阻塞住)
(2)当前的事件正在处理,但没有及时完成
UI线程尽量只做跟UI相关的工作,耗时的工作(数据库操作,I/O,连接网络或者其他可能阻碍UI线程的操作)放入单独的线程处理,尽量用Handler来处理UI thread和thread之间的交互。
UI线程主要包括如下:
-
Activity:onCreate(), onResume(), onDestroy(), onKeyDown(), onClick()
-
AsyncTask: onPreExecute(), onProgressUpdate(), onPostExecute(), onCancel()
-
Mainthread handler: handleMessage(), post(runnable r)
查找ANR的方式: 1. 导出/data/data/anr/traces.txt,找出函数和调用过程,分析代码 2. 通过性能LOG人肉查找
- 值得阅读的android技术文章
- Android多线程的实现方式有哪些?它们的优缺点和适用场景是什么
Thread & AsyncTask
Thread 可以与Loop 和 Handler 共用建立消息处理队列 AsyncTask 可以作为线程池并行处理多任务
- Android下解决滑动冲突的常见思路是什么
相关的滑动组件 重写 onInterceptTouchEvent
,然后判断根据xy值,来决定是否要拦截当前操作
Android Touch事件传递机制 Android 事件分发机制详解
- 如何把一个应用设置为系统应用
成为系统应用,首先要在 对应设备的 Android 源码SDK下编译,编译好之后:
- 此 Android 设备是 Debug 版本,并且已经 root,直接将此 apk 用 adb 工具 push 到 system/app 或 system/priv-app 下即可。
- 如果非 root 设备,需要编译后重新烧写设备镜像即可。
- 有些权限(如 WRITE_SECURE_SETTINGS ),是不开放给第三方应用的,只能在对应设备源码中编译然后作为系统 app 使用。
- Android注册广播有几种方式? 它们的适用情况是什么?
Android中有两种广播的注册方式: 1、静态注册:AndroidManifest.xml配置文件中; 2、动态注册:Java代码; 静态注册适用于全局广播;动态注册适用于局部广播;
补充一点:有些广播只能通过动态方式注册,比如时间变化事件、屏幕亮灭事件、电量变更事件,因为这些事件触发频率通常很高,如果允许后台监听,会导致进程频繁创建和销毁,从而影响系统整体性能。
- 你看过Android Framework的代码吗?介绍一下某一个或几个模块?
我觉得这个问题 最好从app相关系统模块讲一下,例如inputmanager(输入事件),activitymanager,windowmanager等. 或者从类似asyctask,hander,等基础工具来讲.
- 如何调试Android应用程序
- log
- 断点调试
- 请用任意语言实现数据结构中的栈