您的位置:首页 > 职场人生

[Android面试题]--2015-2016高发面试题基础版(你一定会遇到)

2016-06-16 22:56 627 查看
本文集锦自面试过程中常遇到的问题,都是大家实际遇到的,都是平常收集的,如果你正在求职看一看肯定会帮助很大,如果在工作中也可以读一读巩固基础以查漏补缺. 辛苦整理希望只对大家有帮助!
某公司高级面试题(2015-03-14)【感谢helder分享】
1、详述Android系统架构,包括层与层之间调用、binder、jni、底层文件读写方法
2、描述自己的一个项目,要求画出结构图,UML图,详细描述项目种的技术点,技术难点以及解决方案
3、一道算法
4、谈谈自己项目管理的方法、对敏捷软件开发的理解

基础面试题(2014-04-18)
1、请解释下在单线程模型中Message,Handler,Message Queue,Looper之间的关系。
拿主线程来说,主线程启动时会调用Looper.prepare()方法,会初始化一个Looper,放入Threadlocal中,接着调用Looper.loop()不断遍历Message Queue,
Handler的创建依赖与当前线程中的Looper,如果当前线程没有Looper则必须调用Looper.prepare()。Handler , sendMessage到MessageQueue,Looper不断
从MessageQueue中取出消息,回调handleMessage方法。

2、如果有个100M大的文件,需要上传至服务器中,而服务器form表单最大只能上传2M,可以用什么方法。
这个问题不是很明确我觉得,首先来说使用http协议上传数据,特别在android下,跟form没什么关系。传统的在web中,在form中写文件上传,其实浏览器所做
的就是将我们的数据进行解析组拼成字符串,以流的方式发送到服务器,且上传文件用的都是POST方式,POST方式对大小没什么限制。
回到题目,可以说假设每次真的只能上传2M,那么可能我们只能把文件截断,然后分别上传了。

3、内存溢出和内存泄漏有什么区别?何时会产生内存泄漏?内存优化有哪些方法?
内存溢出通俗理解就是软件(应用)运行需要的内存,超出了它可用的最大内存。
内存泄漏就是我们对某一内存空间的使用,使用完成后没有释放。
内存优化:Android中容易内存溢出的部分,就是图片的加载,我们可以使用图片的压缩加上使用LruCache缓存的目的来控制图片所能够使用的内存。
还有对于比较耗资源的对象及时的关闭,例如Database Conn , 各种传感器 , Service 等等。

4、AsyncTask使用在哪些场景?它的缺陷是什么?如何解决?
AsyncTask 运用的场景就是我们需要进行一些耗时的操作,耗时操作完成后更新主线程,或者在操作过程中对主线程的UI进行更新。
缺陷:AsyncTask中维护着一个长度为128的线程池,同时可以执行5个工作线程,还有一个缓冲队列,当线程池中已有128个线程,缓冲队列已满时,如果
此时向线程提交任务,将会抛出RejectedExecutionException。

解决:由一个控制线程来处理AsyncTask的调用判断线程池是否满了,如果满了则线程睡眠否则请求AsyncTask继续处理。

5、Activity用SharedPreferences保存数据,大小有木有限制?
这个真心查不到。。。

6、Activity间通过Intent传递数据大小有没有限制?
貌似是40K。

7、assest文件夹里放文件,对于文件的大小有没有限制?22
assets目录更像一个附录类型的目录,Android不会为这个目录中的文件生成ID并保存在R类当中,因此它与Android中的一些类和方法兼容度更低。
同时,由于你需要一个字符串路径来获取这个目录下的文件描述符,访问的速度会更慢。但是把一些文件放在这个目录下会使一些操作更加方便,
比方说拷贝一个数据库文件到系统内存中。要注意的是,你无法在Android XML文件中引用到assets目录下的文件,只能通过AssetManager来访问
这些文件。数据库文件和游戏数据等放在这个目录下是比较合适的。另外,网上关于assets和raw的资料都千篇一律了,因此关于这两者中单个文件
大小不能超过1M的**错误**描述也在传播,即如果读取超过1M的文件会报"Data exceeds UNCOMPRESS_DATA_MAX (1314625 vs 1048576)"的
IOException,还引申出种种解决方案。个人认为不应该有这样的限制,为了验证这个说法写了个Demo,发现将近5M的压缩包在assets和raw中
都能正常访问,因此在这里纠正一下,理论上只要打包不超过Android APK 50M大小的限制都是没有问题的。当然了,不排除是Android很早期的
时候因为设备硬件原因aapt在编译的时候对这两个文件夹大小做出了限制,如果是这样,较新版的ADT应该不会出现这种情况。
来自:http://my.eoe.cn/futurexiong/archive/5350.html

8、 启动一个程序,可以主界面点击图标进入,也可以从一个程序中跳转过去,二者有什么区别?
是因为启动程序(主界面也是一个app),发现了在这个程序中存在一个设置为<category android:name="android.intent.category.LAUNCHER" />的activity,
所以这个launcher会把icon提出来,放在主界面上。当用户点击icon的时候,发出一个Intent:
Intent intent = mActivity.getPackageManager().getLaunchIntentForPackage(packageName);
mActivity.startActivity(intent);
跳过去可以跳到任意允许的页面,如一个程序可以下载,那么真正下载的页面可能不是首页(也有可能是首页),这时还是构造一个Intent,startActivity.
这个intent中的action可能有多种view,download都有可能。系统会根据第三方程序向系统注册的功能,为你的Intent选择可以打开的程序或者页面。所以唯一的一点
不同的是从icon的点击启动的intent的action是相对单一的,从程序中跳转或者启动可能样式更多一些。本质是相同的。

9、程序之间的亲和性的理解。
1、默认情况下一个应用的所有Activity都是具有相同的affinity,都是从application中继承,application的affinity默认就是manifest的包名。
2、affinity对Activity来说,就像是身份证一样,可以告诉所在的Task,自己属于其中的一员。
3、应用场合:
a:根据affinity重新为Activity选择合适的宿主Task;
b:与allowTaskReparenting属性配合;
c:启动Activity使用Intent设置了FLAG_ACTIVITY_NEW_TASK标记。

10、同一个程序,但不同的Activity是否可以放在不同的Task任务栈中?
可以放在不同的Task中。需要为不同的activity设置不同的affinity属性,启动activity的Intent需要包含FLAG_ACTIVITY_NEW_TASK标记。

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

12、AIDL的全称是什么?如何工作?
全称是:Android Interface Define Language

在Android中, 每个应用程序都可以有自己的进程. 在写UI应用的时候, 经常要用到Service. 在不同的进程中, 怎样传递对象呢? 显然, Java中不允许跨进程内存共享.
因此传递对象, 只能把对象拆分成操作系统能理解的简单形式, 以达到跨界对象访问的目的. 在J2EE中,采用RMI的方式, 可以通过序列化传递对象. 在Android中, 则
采用AIDL的方式. 理论上AIDL可以传递Bundle,实际上做起来却比较麻烦。
AIDL(AndRoid接口描述语言)是一种借口描述语言; 编译器可以通过aidl文件生成一段代码,通过预先定义的接口达到两个进程内部通信进程的目的. 如果需要
在一个Activity中, 访问另一个Service中的某个对象, 需要先将对象转化成AIDL可识别的参数(可能是多个参数), 然后使用AIDL来传递这些参数, 在消息的接收端, 使用
这些参数组装成自己需要的对象.AIDL的IPC的机制和COM或CORBA类似, 是基于接口的,但它是轻量级的。它使用代理类在客户端和实现层间传递值. 如果要使用AIDL,
需要完成2件事情: 1. 引入AIDL的相关类.; 2. 调用aidl产生的class.
AIDL的创建方法:
AIDL语法很简单,可以用来声明一个带一个或多个方法的接口,也可以传递参数和返回值。 由于远程调用的需要, 这些参数和返回值并不是任何类型.
下面是些AIDL支持的数据类型:
1. 不需要import声明的简单Java编程语言类型(int,boolean等)
2. String, CharSequence不需要特殊声明
3. List, Map和Parcelables类型, 这些类型内所包含的数据成员也只能是简单数据类型, String等其他比支持的类型.
(另外: 我没尝试Parcelables, 在Eclipse+ADT下编译不过, 或许以后会有所支持

13、dvm的进程和Linux的进程, 应用程序的进程是否为同一个概念
Dvm的进程是dalivk虚拟机进程,每个android程序都运行在自己的进程里面,每个android程序系统都会给他分配一个单独的liunx uid(user id),
每个dvm都是linux里面的一个进程.所以说这两个进程是一个进程.

---------------------------------------------------

一、面试技术01: 自定义View知识

1. View是什么?

1). View类是所有用来构建用户界面的组件的基类

2). ViewGroup是View的一个子类, 是各种布局的基类,

它是包含其它View或ViewGroup和定义这些孩子布局参数的容器

3). 一个View(ViewGroup)占用屏幕上的一个矩形区域, 它负责界面的绘制和事件处理

4). 手机屏幕上所有看得见摸得着的都是View(包括ViewGroup)

2. View的分类

1). 不能包含子View的View: 一般的View

TextView: 显示文本(它也可以带图片)

Button: 按钮

ImageView: 显示图片

2). 可以包含子View的View: ViewGroup

FrameLayout

RelativeLayout

LinearLayout

ScrollView

ListView

GridView

3. ViewGroup

1). ViewGroup extends View implements ViewParent, ViewManager

2). ViewManager: 用来添加、删除、更新布局

addView(View v)

removeView(View v)

updateViewLayout(View v)

3). ViewParent: 提供了一系列操作子View的方法

4. 关于View和ViewGroup

1). 整个界面只会有一个根View

a. 得到它: window.getDecorview() PhoneWindow$decorView

b. 本质类型: FrameLayout

c. setContentView()添加的视图不是整个界面的根view FrameLayout(id=content)

2). 一个View只会有一个父View(ViewGroup), 一个ViewGroup可以有多个子View

a. 得到父视图: view.getParent(), 可以将返回的ViewParent强转为指定的ViewGroup

b. 不是所有的View都能添加子view, 只有ViewGroup及其子类才能添加

5. 区别View与Activity?

1). Activity是四大组件中唯一能与用户进行交互的组件

2). Activity只是控制和管理View, 真正显示和处理事件的是View本身来完成

3). Activity内部有一个window对象, window对象(Phonewindow)中包含一个FramLayout类型的decorView

在Activity中setContentView(view)实质上是将view添加到decorView中

手机屏幕中显示的就decorView

6. 显示ContentView的3种方式:

1). setContentView(R.layout.activity_main);

2). View view = View.inflate(this, R.layout.activity_main, null);

setContentView(view);

3). MyTextView tv = new MyTextView(this);

setContentView(tv);

7. View的生命周期过程:

1). 创建View对象

a. 存在2种创建的方式: 加载布局文件创建和直接new构造方法创建

b. 布局文件方式的本质: 解析布局xml, 根据标签名创建对应的View对象, 并将标签属性设置到对象中

c. 布局文件方式: 在所有的View对象都创建好了后, 会调用onFinishInflate()

d. 在视图对象都创建好后, 调用onAttachedToWindow(), 表明view对象关联到window上了

2). 测量(多大?)

a.方法执行: measure()--->onMeasure()--->setMeasuredDimension()

b. measure(): 用来确定当前View的大小, 它是final的方法不能重写, 它内部调用了onMeasure()

c.onMeasure(): 一般重写此方法, 根据我们的实际需求, 对View进行测量

d. setMeasuredDimension(): onMeasure()中必须调用些方法保存当前View测试出的宽度和高度

3). 布局(在哪?)

a. 方法执行: layout()--->onLayout()

b. layout(l, t, r, b):

①. 指定View的左上角点的坐标和右下角点的坐标

②. 比较原有的l,t,r,b与当前的l,t,r,b, 如果有变化了或请求重新layout, 就会调用onLayout(l,t,r,b)

③. 不会重写些方法, 只会调用些方法来指定当前View在父View中的位置

c. onLayout(changed, l, t, r, b)

①. 决定当前view在父ViewGroup中的位置

②. 在View类中只是空实现, 因为一个View的位置是由父View来指定的

③. 在ViewGroup类中用来指定子View的位置, 但是abstract

FrameLayout

LinearLayout

RelativeLayout

④. LinearLayout的实现:

判断自身是横屏还是竖屏?

遍历所有的子View, 为它们准备l,t,r,b

如果是垂直:

A (0,0,width1,height1),

B (0,height1,width2,height1+height2),

C (0,height1+height2,width3,height1+height2+height3)

如果是水平:

(0,0,width1,height1),

(height1,0,height1+width2,height2),

(height1+height2,0,height1+height2+width3,height3)

d. 可以通过requestLayout()的方式来强制重新layout

4). 绘制(啥样?)

a. 方法执行: draw()--->onDraw()

b. draw():

①. 画一些通用的东西(如背景,滚动条等), 一般不会去重写此方法

1>. Draw the background(画背景)

2>. Draw view's content(画内容)

3>. Draw children(画子View)

4>. Draw decorations scrollbars (画滚动条)

②. 如果是View, 使用onDraw(canvas)来画界面

③. 如果是ViewGroup, 使用dispatchDraw(canvas)---分发给子View绘制

c. onDraw(Canvas canvas)

①. 所有特定的View(比如:TextView/ImageView)都重写了此方法来绘制自己的样子

②. 主要使用Paint和Canvas来绘制

d. 可以通过调用inValidate()或postInValidate()来强制重绘

5). 事件处理:

a. 相关方法:

onTouchEvent(MotionEvent): 触摸事件的回调方法

OnTouchListener--->onTouch(View v, MotionEvent event) : 触摸事件的监听器

b. 事件的分发和处理过程

6). 死亡:

b. 相关方法: onDetachedFromWindow()

c. 当Activity退出或当前View被移除触发

8. 总结:

creation

二种方式 : new 构造方法(context) , 定义布局文件再加载(setContentView()/View.inflate()---(context, AttributeSet)) 全类名<TextView> <com.atguigu.MyTextView>

所有View对象都创建好了--->onFinishInflate()[必须是布局文件]--->onAttachToWindow() --->getViewAt(int position)

measure(多大?)

-->measure()--->onMearsure() 产生一个测量的尺寸(宽高) --->getMearsureHeight() getMearsureWidth() -->onResume()

layout(在哪?)

--->layout(l, t, r, b)--->onLayout(boolean change, l, t, r, b)

requestLayout(): 强制重新布局

draw(撒样?)

draw()--->onDraw()

invalidate()/postInvalidate(): 强制重绘

event deal

onTouchEvent()

return true; 消费事件 --->拦截事件

die

onDetachedFromWindow()

二、面试技术02: 自定义View应用

功能一: 快速索引列表

1. 好友列表功能:

1). 对好友List集合按拼音首字母进行排序(需要用到pinyin4j.jar)

2). 显示好友列表时, 显示拼音首字母

2. 列表右侧A到Z列表功能:

1). 从上至下均匀显示A到Z的所有字母

2). 在按下或移动到某个字母时, 字体大小和颜色都有变化

3). 在按下或移动到某个字母时, 正中间区域会显示当前选择的字母, 且过一会自动消失

4). 在按下或移动到某个字母时, 列表会移动到对应的列表项区域

功能二: 滑动删除ListView的某项

功能描述:

水平滑动列表的某一项可以打开或关闭

实现过程

1. 如何得到contentView和deleteView对象?

1). 重写onAttachedToWindow()

2). 调用viewGroup.getChildAt(index)

2. 如何得到contentView和deleteView的宽高?

1). 重写onMeasure()

2). 调用getMeasuredWidth()和getMeasuredHeight()

3. 如何给contentView和deleteView进行初始化布局定位?

1). 重写onLayout()

2). 调用layout()对contentView与deleteView进行布局定位

4. 如何拖动contentView与deleteView?

1). 使用ViewDragHelper这个视图拖拽的帮助类

2). 创建ViewDragHelper对象, 并指定其回调对象, 并重写其中的一些方法

boolean tryCaptureView(View child): 判断child是否是需要拖拽的子View, down时调用

int clampViewPositionHorizontal(): 限制view在水平方向真正移动的距离, move时调用

onViewPositionChanged(View child): 当子view的位置发生改变时回调, 需要在其中去移动其它的子View

onViewReleased(View releasedChild): 当子View被释放时回调, 即up时调用

int getViewHorizontalDragRange(View child): 返回子View在水平方向最大移到的距离, 此方法在用于ListView时才需要重写

3). 重写onTouchEvent(), 在其中让dragHelper对象来处理event对象

5. 如何解决手指滑动时ListView垂直方向滚动和SwipeView水平滑动的冲突问题?

1). 在move事件时, 获取x轴和y轴方向的移动距离distanceX, distanceY

2). 如果distanceX>distanceY, 执行requestDisallowInterceptTouchEvent(true), 使ListView不能拦截event

6. 如何解决SwipeView滑动与ContentView/DeleteView点击事件的冲突问题?

1). 重写onInterceptTouchEvent()

2). 返回dragHelper.shouldInterceptTouchEvent(ev), 由dragHelper来决定是否拦截event

7. 如何只让ListView中只有一个SwipeView能被打开?

1). 为SwipeView定义枚举类型状态类

2). 在SwipeView中定义监听接口,在接口中定义回调方法

3). 定义设置监听接口对象的方法

4). 在Activity的Adapter中为每个SwipeView对象设置监听器对象, 在回调方法中做处理

8. 如何让swipeView的自动打开和关闭是平滑的效果?

1). 调用下面的方法打开/关闭

dragHelper.smoothSlideViewTo(contentView, -deleteWidth, 0);

ViewCompat.postInvalidateOnAnimation(this);

2). 重写computeScroll()

if (dragHelper.continueSettling(true)) {

ViewCompat.postInvalidateOnAnimation(this);

}

9. ListView滑动时, 关闭打开的SwipeView

在ListView的Scroll监听中, 一旦滑动, 关闭打开的swipeView

三、面试技术03: View的触摸事件机制

1. 触摸事件的基本类型

1). down: 按下

2). move: 移动

3). up: 离开

2. 事件对象产生的顺序

1). down-->move-->move-->....-->up

2). 每个事件对象产生后, 都会找到一个消费者来消费处理此事件

3. 事件相关API

1). MotionEvent: 代表对UI的操作单元的类, 它的对象在用户触摸UI时系统自动创建基对象, 并将相关的数据保存在此对象中

ACTION_DOWN=0 : down类型值

ACTION_UP=1 : up类型值

ACTION_MOVE=2 : move类型值

int getAction() : 得到事件类型值

float getX() : 得到事件的X轴坐标(相对于当前View的左顶点)

float getRawX() : 得到事件的X轴坐标(相对于屏幕的左顶点)

float getY() : 得到事件的Y轴坐标(相对于当前View的左顶点)

float getRawY() : 得到事件的Y轴坐标(相对于屏幕的左顶点)

2). Activity

boolean dispatchTouchEvent(MotionEvent event) : 分发事件

boolean onTouchEvent(MotionEvent event) : 处理事件的回调

3). View

boolean dispatchTouchEvent(MotionEvent event): 分发事件

setOnClickListener(OnClickListener l) : 设置触摸事件监听器对象

private OnTouchListener mOnTouchListener; //触摸事件监听器对象变量

public interface OnTouchListener { //事件监听器接口

boolean onTouch(View v, MotionEvent event); // 监听器对象的回调方法

}

boolean onTouchEvent(MotionEvent event) : 事件监听回调方法

setOnclickListener(OnclickListener listener) : 设置点击监听器

setOnLongClickListener(OnLongClickListener listener) : 设置长按事件监听器

4). ViewGroup

boolean dispatchTouchEvent(MotionEvent ev) : 重写View的此方法, 如果当前ViewGroup不拦截, 会分发给对应的子View处理事件

boolean onInterceptTouchEvent(MotionEvent ev) : 拦截触摸事件, 返回值如果为true表示拦截,后面的事件就会交给当前View来处理, 默认为false

requestDisallowInterceptTouchEvent(boolean disallowIntercept) : 如果参数为true, 使当前View及其外层的所有父View不能拦截后面的事件

4. View的事件处理

1). Touch事件的方法执行顺序:

①. dispatchTouchEvent()

②. setOnTouchListener的onTouch()

③. onTouchEvent()

2). 执行的详细过程

①. 在dispatchTouchEvent()会判断是否设置了Touch监听器?

如果没有直接进入②

如果有, 调用监听器的onTouch()方法, 如果onTouch方法返回true到此结束, 如果返回false进入②

②. 调用onTouchEvent()

在down时, send一个延时500ms的消息准备触发长按事件监听回调)

如果0.5s内在产生了up事件, 此时就会移除长按的延时消息, 就会去执行点击事件监听回调

如果0.5内没有产生up事件, 也没有离开, 就会调用长按事件监听回调方法, 如果返回的值是true就不可能再触发点击监听回调了, 否则还会触发.

3). 说明:

①. 如果view的onTouch()(监听器回调)或onTouchEvent(监听回调)在down时返回true, 那第一个move事件就会交给当前View处理,

否则后面的所有事件都不会到达此View了

②. 如是move事件处理返回true, 下一个move/up事件就会交给当前View处理,否则就会找父View或Activity处理

③. 整体原则: 每个Event对象创建后, 最终肯定会有一个消费者: 可能是View, 也可能是ViewGroup, 实在不行就交给Activty消费处理

5. ViewGroup的事件处理

1). 相关方法执行顺序:

①. dispatchTouchEvent()

②.onInterceptTouchEvent()

③. 对应子View的dispatchTouchEvent()

2). 执行的详细过程:

①. 在dispatchTouchEvent()中, ACTION_DOWN时, 判断是否拦截,如果没有拦截,则找到包含当前x,y坐标的子View,赋值给mMotionTarget,

然后调用mMotionTarget.dispatchTouchEvent()处理down事件

②. 在dispatchTouchEvent()中, ACTION_MOVE时, 判断是否拦截,如果没有拦截,则直接调用mMotionTarget.dispatchTouchEvent(ev)

③. 在dispatchTouchEvent()中, ACTION_UP时, 判断是否拦截,如果没有拦截,则直接调用mMotionTarget.dispatchTouchEvent(ev)

④. 如果没有找到合适的子View来消费当前event, 则将自己当成View来处理event

3). 关于拦截:

①. 如何拦截?: ViewGroup中onInterceptTouchEvent()默认返回false, 也就是不拦截, 如果想拦截就重写此方法, 并返回true, 这样事件就不会分发给子View处理

②. 如何不被拦截?: 如果子View不希望父View(也就是当前ViewGroup)拦截event, 子View可以执行: getParent().requestDisallowInterceptTouchEvent(true)

6. 扩展blog:

Android View 事件分发机制 源码解析

Android ViewGroup事件分发机制

Android事件分发机制完全解析,带你从源码的角度彻底理解(上)

Android事件分发机制完全解析,带你从源码的角度彻底理解(下)

四、面试技术04: Android中的消息机制与异步任务

1. 相关基础知识:

1). 在Android中, 运行的线程有两种类型: UIThread(主线程, 一个)和WorkerThread(分线程, 多个)

2). 在Android中,只有在UIThread中才能直接更新界面, 如果在分线程直接更新界面, 会抛出如下异常:

android.view.ViewRoot$CalledFromWrongThreadException: Only the original thread

that created a view hierarchy can touch its views.

3). 在Android中, 很多长时间处理数据的工作(联网)都需要在workerThread中执行, 否则会抛出异常/操作反应慢

4). 在分线程得到数据后, 需要去更新界面, 但在分线程中直接更新界面是不允许的, 如何解决此矛盾?

5). 联网相关功能的三步:

①. 显示提示视图: 可能是ProgressBar, 也可能是ProgressDialog. ----在主线程执行

②. 请求服务器, 得到服务器返回的数据. ----在分线程执行

③. 更新界面: 移除提示视图, 显示得到的数据. ----在主线程执行

2. 消息机制:

1). Android中设计的一套API和完善的运行工作体系, 它能解决如何情况

①. 分线程与主线程之间的多线程间通信

②. 在一个线程内, 工作的统一处理

③. 轻松实现延迟工作, 循环工作, 定时工作

2). 相关API:

①. Message: 消息类

Message.obtain(what) : 创建消息对象

public int what : 标识值

public int arg1 : 携带Int类型数据

public int arg2 : 携带Int类型数据

public Object obj : 携带任意对象类型数据

public long when : 标识当前Message什么时刻应该被处理

public Handler target : 当前message由哪个handler来分发处理

②. Handler: 处理器类

sendMessage(Message msg) : 发送即时消息

sendMessageDelayed(Message msg, long delayMillis) : 发送延时消息

sendEmptyMessage(int what): 发送即时空消息

sendEmptyMessageDelayed(int what, long delayMillis) : 发送延时空消息

boolean post(Runnable r) : 发送即时带回调的空消息

boolean postDelayed(Runnable r, long delayMillis): 发送延时带回调的空消息

handleMessage(Message msg) : 处理消息的回调方法

removeMessages(int what) : 根据what删除还未处理的对应消息

removeCallbacksAndMessages(null) : 删除所有未处理的消息

dispatchMessage(Message msg) : 分发消息

message的回调

handler的callback监听器的回调方法

handler的回调方法

③. MessageQueue: 消息队列类(我们不需要操作)

enqueueMessage(Message msg, long when): 将消息添加到消息队列

无论发送的是即时消息还是延时消息, 都是立即将message对象保存到了MessageQueue对象中

Message next() : 取出一个需要处理的消息, 如果没有就会进入等待状态, 但不会导致UIThread阻塞 thread.wait()

④. Looper: 循环器类(我们不需要操作)

loop() : 使用无限for循环获取message, 并调用对应的handler分发处理此消息

3). 原理

3. 异步任务: AsyncTask

1). 在使用AsyncTask之前, 我们可以使用Handler+Thread的方式实现异步任务的功能

2). AsyncTask的优势:

编码上: 更简洁, 使用更方便

效率上: 由于AsyncTask内部使用的是线程池, 能反复使用Thread对象进行分线程的处理工作, 而原生的方式每次都是新建Thread对象启动分线程

3). 相关API:

class AsyncTask<Params, Progress, Result>

Params 启动任务执行的输入参数,比如HTTP请求的URL。

Progress 后台任务执行的百分比。

Result 后台执行任务最终返回的结果,比如String。

execute(Params... params) :

启动任务, 开始任务的执行流程

void onPreExecute() :

在分线程工作开始之前在UIThread中执行,一般用来显示提示视图

Result doInBackground(Params... params) :

在workerThread中执行, 完成任务的主要工作,通常需要较长的时间

void onPostExecute(Result result)

在doInBackground()执行完后在UIThread中执行,一般用来更新界面

publishProgress(Progress... values) :

在分线程中, 发布当前进度

void onProgressUpdate(Progress... values) :

在主线程中更新进度

4). 原理:

execute()

五、面试技术05:ListView

0. 第0层: 不优化:

每次执行getView(), 都会执行: converterView = View.inflate(R.layout.xxx);

问题: 效率太低, 在快速滑动时会有卡顿, 在数据很多时甚至会内存溢出

1. 第一层: 复用converterView

if(converterView==null) {

converterView = View.inflate(R.layout.xxx); 10-->11

}

问题: 每次执行getView()都需要执行converterView.findViewById()得到子View

2. 第二层: 使用ViewHolder, 减少findViewById()的次数

Viewholder holder = null;

if(converterView==null) {

converterView = View.inflate(R.layout.xxx);

holder = new ViewHolder();

holder.imageView = (ImageView)converterView.findViewById(xxx);

holder.textView = (TextView)converterView.findViewById(yyy);

converterView.setTag(holder);

} else {

holder = (Viewholder )converterView.getTag();

}

static class ViewHolder {

ImageView imageView;

TextView textView;

}

问题1: 对于联网获取列表数据, 如果数据量太大(比如超过100条甚至更多), 一次获取出来显示, 太慢太耗流量

问题2: 对于联网获取列表数据, 如果包含图片数据, 每次都请求获取显示, 太慢太耗流量

3. 第三层: 对数据列表进行分页加载显示

1). 自己做: 通过Scroll监听listView.setonScrollListener(scrollListener), 当到达底部时加载下一页列表数据并显示

2). 使用第三方开源框架: Android-PullToRefresh或其它

4. 第四层优化: 图片三级缓存处理

参见图片三级缓存机制

六、面试技术06: 图片的三级缓存机制

1. 什么是三级缓存?

一级: 内存中的缓存图片对象(Bitmap), 用Map<url, Bitmap>

二级: 手机sd卡的files或手机内部的files中缓存图片文件(xxx.jpg/png)

三级: 服务器端保存图片文件

2. 如何应用三级缓存?

例如: 如何根据url根据图片显示?

1). 根据url从一级缓存(Map<url, Bitmap>)中取图片对象, 如果取到了, 直接显示

注意: 真实项目中使用LruCache<String, Bitmap>来缓存图片(查看<<面试技术11. 图片处理优化>>)

2). 如果没有, 根据url中包含图片名称(文件名), 手机的sd卡或内部找对就图片文件加载成bitmap

如果找到了, 显示并保存到一级缓存

3). 如果没有, 显示一个默认的图片, 根据url联网请求获取bitmap

如果没有, 显示一张代表错误的图片

如果有:

a. 保存到一级缓存

b. 保存到二级缓存

c. 显示图片

3. 在ListView中应用图片三级缓存的问题?

问题:

1). 在快速滑动时, 会出现显示错误图片

2). 图片显示后, 过一会又会变为另一张图片(图片闪动)

原因:

在分线程加载图片的过程中, converterView已经被复用

解决:

1). 将url字符串保存到imageView对象的tag中

2. 在加载图片的线程开始干活前, 查看imageView的tag中的url是否变化, 如果变化不加载图片

3). 在加载到图片准备显示前, 再次查看imageView的tag中的url是否变化, 如果变化不显示图片

七、面试技术07: Android的四大应用组件

1. Android的四大应用组件是哪些?

1). Activity

2). Service

3). BroadcastReceiver

4). ContentProvider

2. 对应用组件的理解

1). Java是面向对象的, 而Android是面向组件的(包括应用组件与视图组件), 我们在写项目时, 都是从写各种组件类开始的

2). 作为应用组件都会有一些特点:

①. 都需要继承系统定义好的某个组件类

②. 需要进行注册(配置文件/代码)

③. 对象的创建和管理都是由系统帮我们完成

④. 都有一定的生命周期方法, 我们要去实现或重写它们来做一些我们的工作

3. 对各个应用组件的理解

1). Activity: 活动

描述: 提供能与用户进行交互的用户界面

主要工作: 加载布局, 为视图设置监听, 在监听回调中完成工作,

利用Activity的生命周期回调方法做一些特定的工作

重要知识点:命周期方生法, launchMode, BackStack, Activity的启动与停止

2). Service: 服务

描述: 后台为应用做一些时间跨度比较大的任务 长时间的任务

区别: Service与Activity, Service与Thread

重要知识点: Service的生命周期

3). BroadcastReceiver: 广播接收器

描述: 广播机制是Android中实现不同应用间(进程间)通信的一种手段(应用级的事件机制)

重要知识点: 区别注册接收器的两种方式

区别一般广播与有序广播

常见的系统广播

4). ContentProvider: 内容提供者

描述: 用来将当前应用表数据的操作暴露给其它应用

重要知识点: 为什么要用ContentProvider?

ContentResolver, ContentProvider与ContentObsolver的关系

注意: 每个都可以说一个项目中的例子来说明

优秀Blog: /article/7552461.html
八、面试技术08: Android中的数据存储

- 2. SharedPrefrence存储

1). 位置
data/data/应用的包名/shared-prefs/xxx.xml中
2). 特点

* 1.存储的都是一些小的变量。
* 类型为:boolean float int long String
* 2. 存储的是键值对特点的数据。而且key都为String型,value即为以上的五种类型。
* 要求存储的数据的key是不相同的。
* 3.随着应用的卸载而被删除
4.数据可以设置为私有的,只能被当前应用访问。

3). 相关API

- 3. 手机内部文件存储

1). 位置
data/data/应用的包名/files/xxx
2). 特点

* 1.存储的文件没有大小的限制。(不能超出存储空间大小)
* 2.可以存储任何格式的文件.(. png .doc .txt .mp3)
* 3.会随着应用的卸载被删除
* 4.可以将此目录下的文件设置为私有的。

3). 相关API

- 4. 手机外部文件存储(sd卡的存储)

1). 位置
路径1:storage/sdcard/Android/data/应用的包名/files/xxx
路径2:storage/sdcard/xxx
2). 特点

1.路径一中保存的数据会随着应用的卸载被删除
路径二中保存的数据不会随着应用的卸载被删除
2.存储在此路径下的文件是公共的
3.可以存储任意类型的文件
4.文件的大小没有限制,只要不超过sd卡的存储空间即可
5.权限:android.permission.WRITE_EXTERNAL_STORAGE

3). 相关API

比较内部文件与外部文件存储?

>文件不大,访问较为频繁,比较重要=>手机内部存储
>数据如果是私有的,不希望其它应用访问,考虑使用手机内部存储
>是否需要随着应用的卸载而被删除。不需要,使用手机外部存储的路径2的方式

6. 远程服务器存储

1). 存储的位置
>存储在远程的服务器端

2). 特点
>相较于前面的4种存储方式,远程服务器的存储不保存在本地
>不会随着应用的卸载,而被删除

3). 实现联网请求的技术

1) 使用的是Java提供的API:HttpURLConnection
1.要访问资源的路径: GET请求: http://192.168.10.165:8080/Web_server/index.jsp?username=Tom&age=10 POST请求:http://192.168.10.165:8080/Web_server/index.jsp
2. URL url = new URL(path)
3.获取连接对象: HttpURLConnection conn = url.openConnection();
4.设置参数: conn.setConnectionTimeout(); conn.setReadTimeout(); 请求方法:setRequestMethod(); setDoInput();setDoOutput()
如果是POST请求,需要填充请求参数:
conn.getOutputStream().write(byte[]);
5.连接: conn.connect();
6.获取响应码: conn.getResponseCode() == 200 404 500
7.获取服务器端发送过来的数据: conn.getInputStream() BitmapFactory.decode(InputStream is)
8.资源的关闭:流的关闭,连接的关闭:conn.disconnect();

2) android内置的API:HttpClient
1.创建了一个客户端的对象: DefaultHttpClient
2.设置请求参数: HttpConnectionParams
3.提供一个GET请求的对象/ POST请求的对象: (包含请求路径)
GET请求: http://192.168.10.165:8080/Web_server/index.jsp?username=Tom&age=10 POST请求:http://192.168.10.165:8080/Web_server/index.jsp
GET请求: new HttpGet(path)
POST请求: new HttpPost(path); 设置请求体: httpPost.setEntity();
4. 得到HttpResponse : client.execute(httpGet/ httpPost)
5. 获取响应状态行中的响应码:httpResponse.getStatusLine() .getStatusCode()
6. 获取包含响应数据的entity : httpResponse.getEntity()
7. 解析数据: EntityUtils.toString(entity,charset)
8. 使用响应数据
9.资源的关闭: client.getConnectionManager.shutDown();

3 ) 第三方框架:Volley / XUtils
1. 创建一个RequestQueue (先进先出的特点)
2. 创建请求对象: StringRequest/JsonRequest/ImageRequest (重写 onResponse(String result ) / onErrorResponse())
如果是一个POST请求,还需要重写getParams(),返回一个包含请求数据的map即可。

3.将请求对象添加到队列里: queue.add(request);

九、面试技术09: 性能优化

1. 性能相关的两个概念

1). 响应时间

指从用户操作开始到系统给用户以正确反馈的时间

系统处理时间 + 网络传输时间(可能没有) + 展现时间

2). TPS(Transactions Per Second)

每秒处理的事务数, 是系统吞吐量的一个指标

2. 什么是性能问题?

响应时间过长, 系统吞吐量过低, 高并发下内存泄漏 (ANR)

3. 性能调优的方式:

1). 降低执行时间

缓存(对象缓存,IO缓存, 网络缓存, DB缓存)

数据存储类型优化

算法优化

逻辑优化

JNI

需求优化

2). 同步改异步

利用多线程提高TPS

3). 提前或延迟操作

错开时间段提高TPS

4. 调优点:

1). Java代码部分优化

2). 布局优化、

3). 数据库优化

5. Java代码优化之: 缓存优化:

1). 线程池

2). 图片缓存

3). Message缓存

4). ListView缓存

5). layout缓存

6). 文件IO缓存

6. Java代码优化之: 数据存储优化

1). 数据类型选择:

StringBuilder/StringBuffer代替String

SoftRefrence代替强引用

LocalBroadcastManager代替普通BroadcastReceiver,效率和安全性都更高

2). 数据结构选择

ArrayList与LinkedList的选择

List与Map的选择

Android中推荐用SparseArray代替Map<Integer,Object>, SparseArray内部使用二分法查找数据, 效率更高

7. Java代码优化之: 算法优化

查询考虑hash和二分,尽量不用递归

必要时可以考虑: 使用空间换时间

8. 逻辑优化

主要是理清程序逻辑,减少不必要的操作。

9. 异步,利用多线程提高TPS

充分利用多核Cpu优势,利用线程解决密集型计算、IO、网络等操作, 分线程处理完成后可以通过Handler与主线程交互

10. 提前或延迟操作,错开时间段提高TPS

1) 延迟操作: 不在Activity、Service、BroadcastReceiver的生命周期等对响应时间敏感函数中执行耗时操作,可适当delay

2). 提前操作: 对于第一次调用较耗时操作,可统一放到初始化中,将耗时提前

11. 网络优化

a. 图片必须缓存,最好根据机型做图片做图片适配

b. 所有http请求必须添加httptimeout

c. 开启gzip压缩

d. api接口数据以json格式返回,而不是xml或html

e. 根据http头信息中的Cache-Control及expires域确定是否缓存请求结果。

f. 确定网络请求的connection是否keep-alive

g. 减少网络请求次数,服务器端适当做请求合并。

h. 减少重定向次数

i. api接口服务器端响应时间不超过100ms

12. 布局优化:

1). 对于布局的选择: FrameLayout>RelativeLayout>LinearLayout

2). <include>标签

3). <viewstub>标签

4). <merge>标签

5). 去除不必要的嵌套和View节点

6). 减少不必要的infalte, infalte布局后缓存起来

7). 多使用布局调优工具来查看布局情况并做出合理的优化

十、面试技术10. 内存溢出与内存泄露

1. 定义:

1). 内存溢出: 即为out of memory, 当你要求分配的内存超过了系统给你的内存时,

系统就会抛出out of memory的异常(每个Android能用的内存是有限的)

比如: 当前应用只剩下4M的空间可用, 但你却加载得到一个需要占用5M空间的图片Bitmap对象, 就会抛出溢出的异常

2). 内存泄露: 即为memory leak, 一个对象被创建后, 你不再使用它了, 但因为某种原因它又没有成为垃圾对象, 这块内存不能再被分配置使用

比如: 查询数据库得到的cursor对象在使用完后没有关闭, Activity中使用Handler发延迟消息, 但退出前不移除未处理的消息

3). 内存泄露不多时没有太大影响, 但积累得多了就会导致应用运动缓慢, 到最后就会内存溢出

2. 内存泄漏的分类:

1). 常发性内存泄漏: 发生内存泄漏的代码会被多次执行到,每次被执行的时候都会导致一块内存泄漏

2). 偶发性内存泄漏: 发生内存泄漏的代码只有在某些特定环境或操作过程下才会发生。常发性和偶发性是相对的。

对于特定的环境,偶发性的也许就变成了常发性的

3). 一次性内存泄漏: 发生内存泄漏的代码只会被执行一次,或者由于算法上的缺陷,导致总会有一块仅且一块内存发生泄漏

说明: 危害性大小顺序为: 1)>2)>3)

3. 造成内存泄露的几种场景

1). 长生命周期的对象持有短生命周期对象的引用: Activity中使用Handler

2). 资源数据连接相关对象不关闭: cusor, stream, connection

3). HashSet中的对象或HashMap中的Key对象, 基内部与hash值相关的属性被修改

4). 一些对象产生后不会自动释放或需要完全执行完了才释放. 比如: Bitmap, Thread, AsyncTask

4. 避免内存泄露

1). 尽早释放无用对象的引用

2). 使用字符串处理,避免使用String,应大量使用StringBuffer,每一个String对象都得独立占用内存一块区域

3). 尽量少用静态变量,因为静态变量存放在永久代(方法区),永久代基本不参与垃圾回收

4). 避免在循环中创建对象

5. 造成内存溢出的的场景:

1). 申请了太多的对象. 比如: 使用ListView时, 不复用convertView, 当数据项多时就会出现内存溢出

2). 创建的对象内存太大. 比如: 不经过压缩直接加载大图片文件

3). 内存泄露积累一定的时间后就可能出现

6. 避免内存溢出:

1). 通过复用对象的方式, 减少产生的对象

2). 大对象需要先压缩后创建

3). 避免或减少内存泄露的情况

注意:

双击全屏查看

自己也多百度一下看看多积累

十一、面试技术11. 图片处理优化

1. 大图片的加载显示(避免OOM问题):

1). 问题: 如果将大图片加载到内存中来显示, 可能会导致内存溢出(OOM)

2). 解决思路: 对图片进行压缩加载(本质上只是读取了图片文件的部分数据)

3). 具体办法:

①. 得到图片的宽高的方式:

BitmapFactory.Options options = new BitmapFactory.Options();

options.inJustDecodeBounds = true; //设置只读取图片文件的边框,这样就不会加载整个图片文件

BitmapFactory.decodeResource(getResources(), R.id.myimage, options);

int imageHeight = options.outHeight; //图片的高

int imageWidth = options.outWidth; //图片的宽

String imageType = options.outMimeType;

注意: 为了避免OOM异常,最好在解析每张图片的时候都先检查一下图片的大小,

除非你非常信任图片的来源,保证这些图片都不会超出你程序的可用内存

②. 计算取样比例的方式:

public static int calculateInSampleSize(BitmapFactory.Options options,

int reqWidth, int reqHeight) {

// 源图片的高度和宽度

final int height = options.outHeight;

final int width = options.outWidth;

int inSampleSize = 1;

if (height > reqHeight || width > reqWidth) {

// 计算出实际宽高和目标宽高的比率

final int heightRatio = Math.round((float) height / (float) reqHeight);

final int widthRatio = Math.round((float) width / (float) reqWidth);

// 选择宽和高中最小的比率作为inSampleSize的值,这样可以保证最终图片的宽和高

// 一定都会大于等于目标的宽和高。

inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;

}

return inSampleSize;

}

注意: 如果inSampleSize=3, 表示 宽和高上只读取原来数据的1/3, 这样整体大小压缩为原来的1/9

③. 整体处理:

public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId,

int reqWidth, int reqHeight) {

// 第一次解析将inJustDecodeBounds设置为true,只获取图片宽,高大小

final BitmapFactory.Options options = new BitmapFactory.Options();

options.inJustDecodeBounds = true; //不会加载整个图片文件

BitmapFactory.decodeResource(res, resId, options);

// 调用上面定义的方法计算inSampleSize值

options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);

// 使用获取到的inSampleSize值再次解析图片

options.inJustDecodeBounds = false; //会根据inSampleSize加载图片的部分数据到内存

return BitmapFactory.decodeResource(res, resId, options);

}

调用代码如下:

mImageView.setImageBitmap(decodeSampledBitmapFromResource(getResources(), R.id.myimage, 100, 100));

//将任意一张图片压缩成100*100的缩略图,并在ImageView上展示

2. 缓存图片对象

1). 在内存中缓存图片对象(Bitmap), 不要直接用Map<String, Bitmap>类型的容器, 因为这样会导致bitmap对象太多太大时而没有去释放, 最终导致OOM

2). 在Android2.3之前, 一般都用Map<String, SoftReference<Bitmap>>结构容器来缓存Bitmap对象, 这样在内存不太充足时, 垃圾回收器会将软引用对象释放.

但从2.3开始, 垃圾回收器可能在正常情况下就回收软引用对象, 这样会降低缓存的效果

3). Android的v4兼容包中提供了LruCache来做缓存容器, 它的基本原理为:

把最近使用的对象用强引用存储在 LinkedHashMap 中,并且把最近最少使用的对象在缓存值达到预设定值之前从内存中移除

private LruCache<String, Bitmap> mMemoryCache; //缓存Bitmap的容器

@Override

protected void onCreate(Bundle savedInstanceState) {

// 获取到可用内存的最大值,使用内存超出这个值会引起OutOfMemory异常。

// LruCache通过构造函数传入缓存值,以KB为单位。

int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);

// 使用最大可用内存值的1/8作为缓存的大小。

int cacheSize = maxMemory / 8;

mMemoryCache = new LruCache<String, Bitmap>(cacheSize) {

@Override

protected int sizeOf(String key, Bitmap bitmap) {

// 重写此方法来衡量每张图片的大小,默认返回图片数量。

return bitmap.getByteCount() / 1024;

}

};

}

public void addBitmapToMemoryCache(String key, Bitmap bitmap) {

if (getBitmapFromMemCache(key) == null) {

mMemoryCache.put(key, bitmap);

}

}

public Bitmap getBitmapFromMemCache(String key) {

return mMemoryCache.get(key);

}

3. 主动释放bitmap对象

if(!bmp.isRecycle() ){ bmp.recycle() // 回收图片所占的内存 system.gc() // 提醒系统及时回收}

4. 设置加载图片的色彩模式:

Android中有四种,分别是:

ALPHA_8:每个像素占用1byte内存

ARGB_4444:每个像素占用2byte内存

ARGB_8888:每个像素占用4byte内存(默认)

RGB_565:每个像素占用2byte内存

默认的模式显示的图片质量是最高的, 但也是占用内存最大的, 而如果使用ARGB_4444模式, 占用的内存就会减少为1/2, 但显示效果差别不明显

BitmapFactory.Options options = new BitmapFactory.Options();

options.inPreferredConfig = Bitmap.Config.ARGB_4444;

Bitmap img = BitmapFactory.decodeFile("/sdcard/1.png", options);

5. 相关优秀Blog

[align=left] 1. Android高效加载大图、多图解决方案,有效避免程序OOM[/align]
2.

Android 编程下图片的内存优化
3.
Android图片内存优化的几点心得
4.
图片优化实例
:Android照片墙应用实现,再多的图片也不怕崩溃

十二、面试技术12. 单例模式与工厂模式

[align=left]1. 单例模式[/align]
1).
懒汉式

2).
饿汉式

[align=left]2. 工厂模式[/align]
1).
简单工厂

2).
工厂方法模式与抽象工厂模式: 可以在网上找找了解一下就可以了
[align=left] [/align]

[align=left] [/align]

十三、面试技术13. 常用的三种排序算法

1. 冒泡排序

1)基本思想:

在要排序的一组数中,对当前还未排好序的范围内的全部数,自上而下对相邻的两个数依次进行比较和调整,

让较大的数往下沉,较小的往上冒。即:每当两相邻的数比较后发现它们的排序与排序要求相反时,就将它们互换。

2). 实例:

3). 代码实现:

2. 选择排序

1). 基本思想:

在要排序的一组数中,选出最小的一个数与第一个位置的数交换;

然后在剩下的数当中再找最小的与第二个位置的数交换,如此循环到倒数第二个数和最后一个数比较为止。

2). 实例:

3). 代码实现:

3. 插入排序

1). 基本思想:

在要排序的一组数中,假设前面(n-1) [n>=2] 个数已经是排好顺序的,现在要把第n个数插到前面的有序数中,

使得这n个数也是排好顺序的。如此反复循环,直到全部排好顺序。

2). 实例:

3). 代码实现:

十四、面试技术14. 常用的几种数据结构

1. 数组(Array)与链表(Link)的区别:

1). 都是内存真实的数据存储结构

2). 数据结构特点:

数组是一块连续的内存, 通过下标来索引数组中的某个元素数据

链表并不是一块连续的内存黄区域, 它是通过链表中的一个元素对象保持着下一个元素对象的引用来关联的

3). 创建结构对象:

数组必须指定初始化大小,而且不能自动扩容

链表不用指定大小, 它的大小是操作元素对象时动态产生的

4). 添加/删除数据

数组在添加/删除时, 很可能导致移动复制拷贝的问题, 效率不太高

链表在添加/删除时, 只需要修改引用就可以, 效率很高

5). 查询

数组是通过下标来得到对应位置的数据的

链表只能通过从一端开始查找的方式获取数据

2. 队列(Queue)与栈(Stack)的区别:

1). 都是根据数组或链表来定义出的抽象数据结构

2). 队列先进先出,栈先进后出

3). 对插入和删除操作的"限定"

栈是限定只能在表的一端进行插入和删除操作的线性表。

队列是限定只能在表的一端进行插入和在另一端进行删除操作的线性表。

面试官:队列和栈有什么区别?

程序员:吃多了拉就是队列, 吃多了吐就是栈.

十五、面试技术15. RAM与ROM

1). RAM: Random Access Memory : 随机存取存储器, 即"运行时内存"

可以在RAM中对数据进行直接的读写操作(CRUD)

存取速度较快

停止运行后内存中的数据就会被清理

Android应用程序就是在RAM中运行的

2). ROM: Read Only Memory: 只读存储器

可以在ROM中保存和读取数据, 但不能直接更新, 如果需要更新, 得先将数据加载到RAM中进行更新后写入ROM中

存取速度较慢

停止运行/断电后信息不丢失

Android的系统文件, APK安装文件等文件都是保存在ROM中(SD卡不是ROM)

3). 例子: Moto X的ROM与RAM数据

十六、面试技术16: Android中的进程与线程

1. 基本知识:

如果某个应用程序组件是第一次被启动,且这时应用程序也没有其他组件在运行,则Android系统会为应用程序创建一个包含单个线程的linux进程。默认情况下,同一个应用程序的所有组件都运行在同一个进程和线程里(叫做“main”主线程)。如果组件启动时,已经存在应用程序的进程了(因为应用程序的其它组件已经在运行了),则此组件会在已有的进程和线程中启动运行。不过,可以指定组件运行在其他进程里,也可以为任何进程创建额外的线程。

2. 进程的分类(根据进程的重要性, 从高到低)和生命周期

1). 前台进程

用户当前操作所必须的进程。满足以下任一条件时,进程被视作处于前台:

o其中运行着正与用户交互的Activity(Activity对象的 onResume() 方法已被调用)。

o其中运行着被正与用户交互的activity绑定的服务Service。

o 其中运行着“前台”服务Service——服务以startForeground()方式被调用。

o其中运行着正在执行生命周期回调方法(onCreate()、onStart()或onDestroy())的服务Service。

o其中运行着正在执行onReceive()方法的BroadcastReceiver。

绝大情况下不会终止此类进程, 当内存不足以维持它们同时运行时——才会被终止

2). 可见进程

没有前台组件、但仍会影响用户在屏幕上所见内容的进程

o 其中运行着不在前台的Activity,但用户仍然可见到此activity(onPause()方法被调用了)

o 其中运行着被可见(或前台)activity绑定的服务Service。

可见进程被认为是非常重要的进程,除非无法维持所有前台进程同时运行了,它们是不会被终止的。

3). 服务进程

此进程运行着由startService()方法启动的服务

除非内存不足以维持所有前台、可见进程同时运行,系统会保持服务进程的运行。

4). 后台进程

包含目前用户不可见activity(Activity对象的onStop()方法已被调用)的进程

这些进程对用户体验没有直接的影响,系统可能在任意时间终止它们,以回收内存供前台进程、可见进程及服务进程使用

5). 空进程

不含任何活动应用程序组件的进程

保留这种进程的唯一目的就是用作缓存,以改善下次在此进程中运行组件的启动时间。

为了在进程缓存和内核缓存间平衡系统整体资源,系统经常会终止这种进程

3. 关于线程

1). 应用程序启动时,系统会为它创建一个名为“main”的主线程, 也称为"UI Thread"

2). UI Thread特点重要, 组件的回调方法, 事件的分发和回调, UI的更新都是在线程执行的

3). 一些长时间的工作(如联网)不能在UI Thread中执行, 只能在分线程(worker Thread)中执行

十七、面试技术17:JSON

1. 什么是JSON?

1. JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式

2. 本质就是具有特定格式的字符串

3. JSON数据已经是客户端与服务器端交互的最常用的选择, 已经很少使用xml来进行数据交互了

2. 格式

①. 整体结构:

Json数组 : [ ]

Json对象: { }

②. Json数组的结构: [value1, value2, value3]

③. Json对象的结构: {key1:value1, key2:value2, key3:value3}

④. key的数据类型: 字符串

⑤. value的数据类型:

数值

字符串

null

json数组

json对象

⑥. 例子:

[{"name":"tom"}]: 对

["name":"tom"]: 不对

{"name":"Tom", "age":12}: 对

{"name":"Tom", "age":12, 23}: 不对

3. 解析:

①. 解析技术:

1). Android原生API: 编码麻烦

2). Gson框架: 解析更方便, 更高效

③. 解析方向:

1). 将java对象(包含集合)转换为json格式字符串) [一般在服务器端用]

2). 将json格式字符串转换为java对象(包含集合) [一般在客户端用]

4. 比较json相对于xml的优势

①. 同一数据量, 使用json表达更小, 这样能省流量, 响应速度更快

②. 解析json数据, 编码更方便, 效率更高

十八、面试技术18: ANR

理解:

Application Not Responding(应用没有响应)

原因:

程序在UI线程中对用户的操作响应执行的时间过长

具体原因分类:

按键或触摸事件在特定时间内无响应(大概5S在上)

BroadcastReceiver在特定时间内无法处理完成(大概10S以上)

Service在特定的时间内无法处理完成(大概20S以上)

解决

不要在UI线程中做长时间的事

耗时的操作放入单独的线程中处理

服务和广播接收器的生命周期回调方法都是UI线程中执行

十九、面试技术20_Android开发中的MVC模式

1. 什么是MVC?

1). 软件工程中的一种软件架构, 全称为"Mode--View--Controller", 即为"模型--视图--控制器"

2). MVC将交互式的应用程序分为3个组件:

①. Mode(模型) : 模型层, 包括实体模型与业务模型, 主要作用是完成业务逻辑处理和数据封装

在Android中, 对应实体类/业务类/DAO类

②. View(视图) : 显示层(表示层), 向用户显示信息

在Android中, 对应布局和自定义控件类

③. Controller(控制器) : 控制层, 处理用户输入, 并实现View层与Mode层的协同处理

在Android中, 对应Activity

2. 理解MVC

1). 基本结构图

2). Android中的MVC结构:

①. M模型层:

com.atguigu.ms.bean: 实体类包

com.atguigu.ms.utils: 工具包(简单的业务逻辑处理)

com.atgiugu.ms.dao: 数据库操作

com.atguigu.ms.net: 网络请求

②. V视图层:

res下的layout, drawable, values等

自定义View类

③. C控制层:

Activity

其它应用组件

3. 使用MVC模式的好处 /如果不用MVC会有什么问题?

1). 如果不用View层(布局)?

问题: 每个Activity都需要创建整个布局视图对象, 一个是代码量更大,

另一个不易实现复用(布局是可以轻松实现复用的), 还有就是修改更麻烦

2). 如果不用Mode层(实体Mode)?

问题: 当应用一个界面需要展示或处理很多数据时, 对应的实体类是必不可少的

3). 如果不用Mode层(非实体Mode)?

问题: 那需要将所有的逻辑处理的代码都写到Activity中, 一个使Activity变得太臃肿,

另一个无法复用业务逻辑功能代码

二十、面试技术01_技术站点

1. 需要关注的技术网站

https://github.com/ : 开源项目托管中心, 开源项目集中营

https://github.com/xfzhang : 张晓飞老师的github

https://github.com/zxfjd3g/android-open-project : 开源项目分类列表

http://stackoverflow.com/ : 国外知名分类问答网站

http://www.csdn.net/ : CSDN(汇集众多牛人博客)

http://www.eoeandroid.com/ : eoe安卓社区

http://www.apkbus.com/ : 安卓巴士

http://www.oschina.net/ : 开源中国社区

http://www.23code.com/ : Android经典开源项目收集站点

2. 不错的个人博客站点

http://www.trinea.cn/

http://stormzhang.com/

http://blog.csdn.net/xiaanming

http://blog.csdn.net/guolin_blog

http://blog.csdn.net/lmj623565791/article/list/1

http://blog.csdn.net/singwhatiwanna

http://blog.csdn.net/bboyfeiyu

http://blog.csdn.net/aigestudio

http://blog.csdn.net/hellogv

http://blog.csdn.net/xyz_lmn

http://blog.csdn.net/androiddevelop?viewmode=contents
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: