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

Android面试记录

2016-04-05 19:34 239 查看

自定义控件

原生控件:

文本控件:TextView和EditView

按钮控件:Button和ImageButton

状态开关按钮:ToogleButton

单选按钮或复选按钮:CheckBox

图片控件:ImageView

时钟控件:AnalogClock 和 DigitalClock

进度条 ProgressBar 和日期与时间选择控件 DatePicker 和 TimePicker 等

自定义控件:

自定义控件可以分为两种自定义组合控件和自定义 view。

一:自定义组合控件

解释:自定义组合控件就是把多个控件做为一个整体看待、处理。这样的好处不仅可以减轻 xml 的代码量,也提高了代码的复用性。

1. 声明一个 View 对象,继承相对布局,或者线性布局或者其他的 ViewGroup。

2. 在自定义的 View 对象里面重写它的构造方法,在构造方法里面就把布局都初始化完毕。

3. 根据业务需求添加一些 api 方法,扩展自定义的组合控件;

4. 希望在布局文件里面可以自定义一些属性。

5. 声明自定义属性的命名空间。

xmlns:itheima=”http://schemas.android.com/apk/res/com.itheima.mobilesafe”

6. 在 res 目录下的 values 目录下创建 attrs.xml 的文件声明我们写的属性。

7. 在布局文件中写自定义的属性。

8. 使用这些定义的属性。自定义 View 对象的构造方法里面有一个带两个参数的构造方法布局文件里面定义的属性都放在 AttributeSet attrs,获取那些定义的属性。

二:自定义 view

自定义 View 首先要实现一个继承自 View 的类。添加类的构造方法,通常是三个构造方法,不过从 Android5.0开始构造方法已经添加到 4 个了。override 父类的方法,如 onDraw,(onMeasure)等。如果自定义的 View 有自己的属性,需要在 values 下建立 attrs.xml 文件,在其中定义属性,同时代码也要做修改。

Android布局:

RelativeLayout(相对布局):相对其它组件的布局方式。这个最常用哦。

LinearLayout(线性布局):按照垂直或者水平方向布局的组件。

AbsoluteLayout(绝对布局):按照绝对坐标来布局组件。现在用的比较少

TabLayout(表单布局):按照行列方式布局组件。

FrameLayout(帧布局):组件从屏幕左上方布局组件。

GrideLayout(android4.0推出)

事件分发

主要

dispatchTouchEvent

onTouchEvent

ACTION_DOWN

ACTION_MOVE

ACTION_UP

1、整个View的事件转发流程是:

View.dispatchEvent->View.setOnTouchListener->View.onTouchEvent

在dispatchTouchEvent中会进行OnTouchListener的判断,如果OnTouchListener不为null且返回true,则表示事件被消费,onTouchEvent不会被执行;否则执行onTouchEvent

2、onTouchEvent中的DOWN,MOVE,UP

DOWN时:

a、首先设置标志为PREPRESSED,设置mHasPerformedLongPress=false ;然后发出一个115ms后的mPendingCheckForTap;

b、如果115ms内没有触发UP,则将标志置为PRESSED,清除PREPRESSED标志,同时发出一个延时为500-115ms的,检测长按任务消息;

c、如果500ms内(从DOWN触发开始算),则会触发LongClickListener:

此时如果LongClickListener不为null,则会执行回调,同时如果LongClickListener.onClick返回true,才把mHasPerformedLongPress设置为true;否则mHasPerformedLongPress依然为false;

MOVE时:

主要就是检测用户是否划出控件,如果划出了:

115ms内,直接移除mPendingCheckForTap;

115ms后,则将标志中的PRESSED去除,同时移除长按的检查:removeLongPressCallback();

UP时:

a、如果115ms内,触发UP,此时标志为PREPRESSED,则执行UnsetPressedState,setPressed(false);会把setPress转发下去,可以在View中复写dispatchSetPressed方法接收;

b、如果是115ms-500ms间,即长按还未发生,则首先移除长按检测,执行onClick回调;

c、如果是500ms以后,那么有两种情况:

i.设置了onLongClickListener,且onLongClickListener.onClick返回true,则点击事件OnClick事件无法触发;

ii.没有设置onLongClickListener或者onLongClickListener.onClick返回false,则点击事件OnC
f346
lick事件依然可以触发;

d、最后执行mUnsetPressedState.run(),将setPressed传递下去,然后将PRESSED标识去除;

setOnLongClickListener和setOnClickListener是否只能执行一个

不是的,只要setOnLongClickListener中的onClick返回false,则两个都会执行;返回true则会屏幕setOnClickListener

APP的启动流程

Activity启动过程详解

从桌面点击到activity启动的过程

1、Launcher线程捕获onclick的点击事件,调用Launcher.startActivitySafely,进一步调用Launcher.startActivity,最后调用父类Activity的startActivity。

2、Activity和ActivityManagerService交互,引入Instrumentation,将启动请求交给Instrumentation,调用Instrumentation.execStartActivity。

3、调用ActivityManagerService的startActivity方法,这里做了进程切换(具体过程请查看源码)。

4、开启Activity,调用onCreate方法

Handler机制

消息机制首先要了解 Handler,Looper,Message,MessageQueue

Handler:主要用来处理消息和更新UI,如果想Handler正常工作,在当前线程中要有一个Lopoer对象

Looper:Handler接受和处理消息的对象

Message:消息队列先进先出的管理Message,在初始化Looper时会创建一个与之关联的MessageQueue

MessageQuene:每个线程只能有一个Looper管理MessageQueun,不断从中取出Message分发给对应的Handler

简单点说:

当我们的子线程想修改Activity中的UI组件时,我们可以新建一个Handler对象,通过这个对象向主线程发送信息;而我们发送的信息会先到主线程的MessageQueue进行等待,由Looper按先入先出顺序取出,再根据message对象的what属性分发给对应的Handler进行处理!

Handler的相关方法:

sendEmptyMessage(int what):发送空消息

sendEmptyMessageDelayed(int what,long delayMillis):指定延时多少毫秒后发送空信息sendMessage(Message msg):立即发送信息

sendMessageDelayed(Message msg):指定延时多少毫秒后发送信息

final boolean hasMessage(int what):检查消息队列中是否包含what属性为指定值的消息 如果是参数为(int what,Object object):除了判断what属性,还需要判断Object属性是否为指定对象的消息

Handler的使用实例(写在子线程,写在主线程)

1 )直接调用Looper.prepare()方法即可为当前线程创建Looper对象,而它的构造器会创建配套的MessageQueue;

2 )创建Handler对象,重写handleMessage( )方法就可以处理来自于其他线程的信息了!

3 )调用Looper.loop()方法启动Looper

一个应用中有哪些线程?

首先,我们都知道的UI线程即用户交互线程,用来处理用户消息和界面绘制;

其次,每个Binder对象对应一个线程;在ActivityThread中会创建ApplicationThread,他们都是继承Binder,这里会启动两个线程;

所以最少应该是3个线程…..然后开发人员自定义的子线程…..。

View的绘制

View的绘制主要涉及三个方法:onMeasure()、onLayout()、onDraw()

onMeasure主要用于计算view的大小,onLayout主要用于确定view在ContentView中的位置,onDraw主要是绘制View。

在执行onMeasure()、onLayout()方法时都会通过相应的标志位或者对应的坐标点来判断是否需要执行对应的函数,如我们经常调用的invalidate方法就只会执行onDraw方法,因为此时的视图大小和位置均未发生变化,除非调用requestLayout方法完整强制进行view的绘制,从而执行上面三个方法。

进度条组件:ProgressView AnnotationView

都使用过哪些自定义控件

1.pull2RefreshListView

2.LazyViewPager

3.SlidingMenu

4.SmoothProgressBar

5.自定义组合控件

6.ToggleButton

7.自定义吐司(Toast)

图片加载框架的优劣对比(Picasso, ImageLoader, Fresco, Glide)

安卓几种图片加载框架的比较:http://blog.csdn.net/u013134722/article/details/56676078

开发中都使用过哪些框架,平台

框架

EventBus(事件处理)

事件总线机制:

xUtils(网络、图片、ORM)

Gson(解析 json 数据框架)

使用方法:

imageLoader (图片处理框架)

源码:

zxing (二维码扫描)

怎么使用

平台

JPush(推送平台)

友盟(统计平台)

有米(优米)(广告平台)

百度地图

bmob(服务器平台、短信验证、邮箱验证、第三方支付、消息推送、即时通讯)

阿里云 OSS(云存储)

ShareSDK(分享平台、第三方登录)

应用上线后用户使用过程中出现的BUG你们是怎么收集的?

Android 中如何捕获未捕获的异常

一:UncaughtExceptionHandler

1、自 定 义 一 个 Application , 比 如 叫 MyApplication 继 承 Application 实 现

UncaughtExceptionHandler。

2、覆写 UncaughtExceptionHandler 的 onCreate 和 uncaughtException 方法。

@Override
public void onCreate() {
super.onCreate();
Thread.setDefaultUncaughtExceptionHandler(this);
}
@Override
public void uncaughtException(final Thread thread, final Throwable ex) {
new Thread(new Runnable() {
@Override
public void run() {
Looper.prepare();
System.out.println(Thread.currentThread());
Toast.makeText(getApplicationContext(), "thread="+thread.getId()+"
ex="+ex.toString(), 1).show();
Looper.loop();
}
}).start();
SystemClock.sleep(3000);
android.os.Process.killProcess(android.os.Process.myPid());
}
}


注意:上面的代码只是简单的将异常打印出来。

在 onCreate 方法中我们给 Thread 类设置默认异常处理 handler,如果这句代码不执行则一切

都是白搭。

在 uncaughtException 方法中我们必须新开辟个线程进行我们异常的收集工作,然后将系统给

杀死。

3、在 AndroidManifest 中配置该 Application

<application
android:name="com.example.uncatchexception.MyApplication"


二:Bug 收集工具 Crashlytics

Crashlytics 是专门为移动应用开发者提供的保存和分析应用崩溃的工具。国内主要使用的是友

盟做数据统计。

Crashlytics 的好处:

1.Crashlytics 不会漏掉任何应用崩溃信息。

2.Crashlytics 可以象 Bug 管理工具那样,管理这些崩溃日志。

3.Crashlytics 可以每天和每周将崩溃信息汇总发到你的邮箱,所有信息一目了然。

使用步骤:

1.注册需要审核通过才能使用,国内同类产品顶多发个邮箱激活链接;

2.支持 Eclipse、Intellij IDEA 和 Android Studio 等三大 IDE;

3.Eclipse 插件是 iOS 主题风格 UI,跟其他 plugin 在一起简直是鹤立鸡群;

4.只要登录帐号并选择项目,会自动导入 jar 包并生成一个序列号,然后在 AndroidManifest.xml

和启动 Activity 的入口添加初始化代码,可以说是一键式操作,当然要使用除错误统计外的其他功能

还是得自己添加代码;

5.不像友盟等国内同类产品,将固定的序列号直接写入 xml 文件,而是动态自动生成的;当然这个存

放序列号的 xml 文件也是不能修改和提交到版本控制系统的;

6.后台可以设置邮件提醒,当然这个最好不要开启,Android 开发那数量惊人、千奇百怪的错误信息

你懂的。

7.不仅能统计到 UncaughtException 这种未捕获的 Crash 异常信息,只要在 try/catch 代码块的

catch 中添加一行代码就能统计到任何异常;

try{ myMethodThatThrows(); }catch(Exception

e){ Crashlytics.logException(e); //handle your exception here! }

8.相当详细的错误信息,不仅仅是简单的打印 StackTrace 信息;并且能看到最近一次 crash 的机器

可用内存等信息,而不仅仅是简单统计机型和版本号。

使用连接:http://blog.csdn.net/smking/article/details/39320695

屏幕适配问题

适配方式之 dp

适配方式之 dimens

适配方式之 layout

适配方式之 java 代码适配

适配方式之 weight 权重适配

屏幕适配有哪些处理技巧

跨进程通信AIDL

1、什么是 AIDL 以及如何使用

①aidl 是 Android interface definition Language 的英文缩写,意思 Android 接口定义语言。

②使用 aidl 可以帮助我们发布以及调用远程服务,实现跨进程通信。

③将服务的 aidl 放到对应的 src 目录,工程的 gen 目录会生成相应的接口类

我们通过 bindService(Intent,ServiceConnect,int)方法绑定远程服务,在 bindService

中 有 一 个 ServiceConnec 接 口 , 我 们 需 要 覆 写 该 类 的

onServiceConnected(ComponentName,IBinder)方法,这个方法的第二个参数 IBinder 对象其实

就是已经在 aidl 中定义的接口,因此我们可以将 IBinder 对象强制转换为 aidl 中的接口类。

我们通过 IBinder 获取到的对象(也就是 aidl 文件生成的接口)其实是系统产生的代理对象,该

代理对象既可以跟我们的进程通信, 又可以跟远程进程通信, 作为一个中间的角色实现了进程间通信。

2、AIDL 的全称是什么?如何工作?能处理哪些类型的数据?

AIDL 全称 Android Interface Definition Language(AndRoid 接口描述语言) 是一种接口描述

语言; 编译器可以通过 aidl 文件生成一段代码,通过预先定义的接口达到两个进程内部通信进程跨界

对象访问的目的。需要完成 2 件事情: 1. 引入 AIDL 的相关类.; 2. 调用 aidl 产生的 class.理论上, 参

数可以传递基本数据类型和 String, 还有就是 Bundle 的派生类, 不过在 Eclipse 中,目前的 ADT 不支

持 Bundle 做为参数。

说一说一个你熟悉的图片框架

一:imageload

多线程下载图片,图片可以来源于网络,文件系统,项目文件夹assets中以及drawable中等

支持随意的配置ImageLoader,例如线程池,图片下载器,内存缓存策略,硬盘缓存策略,图片显示选项以及其他的一些配置

支持图片的内存缓存,文件系统缓存或者SD卡缓存

支持图片下载过程的监听

根据控件(ImageView)的大小对Bitmap进行裁剪,减少Bitmap占用过多的内存

较好的控制图片的加载过程,例如暂停图片加载,重新开始加载图片,一般使用在ListView,GridView中,滑动过程中暂停加载图片,停止滑动的时候去加载图片

提供在较慢的网络下对图片进行加载

说一说一个你熟悉的网络框架

说一说数据结构和算法

讲一讲你们做项目的流程

View的绘制

首先,我们都知道的UI线程即用户交互线程,用来处理用户消息和界面绘制;

其次,每个Binder对象对应一个线程;在ActivityThread中会创建ApplicationThread,他们都是继承Binder,这里会启动两个线程;

所以最少应该是3个线程…..然后开发人员自定义的子线程…..。

Android中怎么保证运行的流畅性

把耗时操作写入子线程中(如网络请求,SQL数据查询语句)

MVC 、MVP

MVC耦合性低,减少了模块代码之间的相互影响,可扩展性好,模块指责划分明确,降低BUG的出现率,利于代码的维护

VIEW相当于XML

MVP使MODEL跟VIEW达到完全解耦,并且这里的VIEW相当于Fragment和Activity,MODEL跟VIEW分别提供接口,让Presenter把VIEW跟MODEL连接起来,所有的交互都发生在Presenter内部,而在MVC中View会直接从Model中读取数据而不是通过 Controller。

WebView和JS互调

版本适配 兼容jar包

怎么在一个程序中启动其他的程序

APP的性能优化

1、如何对 Android 应用进行性能分析

一款 App 流畅与否安装在自己的真机里,玩几天就能有个大概的感性认识。不过通过专业的分析工

具可以使我们更好的分析我们的应用。而在实际开发中,我们解决完当前应用所有 bug 后,就会开

始考虑到新能的优化。

如果不考虑使用其他第三方性能分析工具的话,我们可以直接使用 ddms 中的工具,其实 ddms 工

具已经非常的强大了。ddms 中有 traceview、heap、allocation tracker 等工具都可以帮助我们分

析应用的方法执行时间效率和内存使用情况。

一:traceview

二:heap

三:allocation tracker

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

OOM 内存溢出,想要避免 OOM 异常首先我们要知道什么情况下会导致 OOM 异常。
1、图片过大导致 OOM

Android 中用 bitmap 时很容易内存溢出,比如报如下错误:Java.lang.OutOfMemoryError :
bitmap size exceeds VM budget。
解决方法:方法 1: 等比例缩小图片


BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 2;
//Options 只保存图片尺寸大小,不保存图片到内存
BitmapFactory.Options opts = new BitmapFactory.Options();
opts.inSampleSize = 2;
Bitmap bmp = null;
bmp = BitmapFactory.decodeResource(getResources(),
mImageIds[position],opts);
//回收
bmp.recycle();//


以上代码可以优化内存溢出,但它只是改变图片大小,并不能彻底解决内存溢出。


方法 2:对图片采用软引用,及时地进行 recyle()操作

SoftReference<Bitmap> bitmap = new SoftReference<Bitmap>(pBitmap);
if(bitmap != null){
if(bitmap.get() != null && !bitmap.get().isRecycled()){
bitmap.get().recycle();
bitmap = null;
}
}


方法 3:使用加载图片框架处理图片,如专业处理加载图片的 ImageLoader 图片加载框架。还有我

们学的 XUtils 的 BitMapUtils 来做处理。

2、界面切换导致 OOM

一般情况下,开发中都会禁止横屏的。因为如果是来回切换话,activity 的生命周期会重新销毁
然后创建。
有时候我们会发现这样的问题,横竖屏切换 N 次后 OOM 了。
这种问题没有固定的解决方法,但是我们可以从以下几个方面下手分析。


1、看看页面布局当中有没有大的图片,比如背景图之类的。

去除 xml 中相关设置,改在程序中设置背景图(放在 onCreate()方法中):

Drawable drawable = getResources().getDrawable(R.drawable.id);
ImageView imageView = new ImageView(this);
imageView.setBackgroundDrawable(drawable);


在 Activity destory 时注意,drawable.setCallback(null); 防止 Activity 得不到及时的释放。


2、跟上面方法相似,直接把 xml 配置文件加载成 view 再放到一个容器里,然后直接调用

this.setContentView(View view);方法,避免 xml 的重复加载。

3、 在页面切换时尽可能少地重复使用一些代码

比如:重复调用数据库,反复使用某些对象等等……

4、查询数据库没有关闭游标

程序中经常会进行查询数据库的操作,但是经常会有使用完毕 Cursor 后没有关闭的情况。如果
我们的查询结果集比较小,对内存的消耗不容易被发现,只有在常时间大量操作的情况下才会出现内
存问题,这样就会给以后的测试和问题排查带来困难和风险。


5、构造 Adapter 时,没有使用缓存的 convertView

在使用 ListView 的时候通常会使用 Adapter,那么我们应该尽可能的使用 ConvertView。
为什么要使用 convertView?
当 convertView 为空时,用 setTag()方法为每个 View 绑定一个存放控件的 ViewHolder 对象。
当 convertView 不为空,重复利用已经创建的 view 的时候,使用 getTag()方法获取绑定的
ViewHolder 对象,这样就避免了 findViewById 对控件的层层查询,而是快速定位到控件。
5、Bitmap 对象不再使用时调用 recycle()释放内存
有时我们会手工的操作 Bitmap 对象,如果一个 Bitmap 对象比较占内存,当它不再被使用的时
候,可以调用 Bitmap.recycle()方法回收此对象的像素所占用的内存,但这不是必须的,视情况而定。
6、其他
Android 应用程序中最典型的需要注意释放资源的情况是在 Activity 的生命周期中,在
onPause()、onStop()、 onDestroy()方法中需要适当的释放资源的情况。使用广播没有注销也会产
生 OOM。


如何避免 OOM 异常

OOM 内存溢出,想要避免 OOM 异常首先我们要知道什么情况下会导致 OOM 异常。


一:图片过大导致内存溢出

二:界面切换导致 OOM

三:查询数据库没有关闭游标

四:构造 Adapter 时,没有使用缓存的 convertView

五:Bitmap 对象不再使用时调用 recycle()释放内存

六:其他

Android 应用程序中最典型的需要注意释放资源的情况是在 Activity 的生命周期中,在

onPause()、onStop()、 onDestroy()方法中需要适当的释放资源的情况。使用广播没有注销也会产

生 OOM。

线程间的通信(有几种方式)

一:共享内存(变量);
二:文件,数据库;
三:Handler;
四:Java 里的 wait(),notify(),notifyAll()


JNI怎么调用,原理

============================

Android基础

四大组件:activity server broadcast contentprovider

Android高级

Android新技术

网络请求:RxJava + Retrofit RxAndroid RxEventBus

图片框架:Glide

JNI和NDK

Android架构

Android第三方框架

性能优化

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: