Android 面试题汇总

来源:互联网 发布:斗鱼抢票软件多少钱 编辑:程序博客网 时间:2024/06/04 18:06

1、描述你Android开发中常用设计模式;

2、Context ,Activity ,ApplicationContext 区别;

3、android 多线程Thread,Runnable,Handler,AsyncTask等之间的关系

4、内存溢出和内存泄漏的区别,如何避免内存溢出,如何进行内存优化;

内存溢出 out of memory,是指程序在申请内存时,没有足够的内存空间供其使用,出现out of memory;

内存泄露 memory leak,是指程序在申请内存后,无法释放已申请的内存空间,一次内存泄露危害可以忽略,但内存泄露堆积后果很严重,无论多少内存,迟早会被占光。

memory leak会最终会导致out of memory!

5、画出Android 消息循环机制;

6、简单描述,Activity LaunchMode ,Android 启动浏览器的方式,在Android LaunchMode 中,此浏览器属于那种?

7、Android 弹性滑动是怎么实现的,怎么避免事件冲突;

8、Handler 为什么会内存泄露,怎么避免?在非UI线程中使用Handler需要注意哪些问题?

1、handler 对象在activity 内部会持有 activity 对象,它会隐式的持有外部类的引用;

如果子线程使用handler将message消息发送到messageQueue中并等待执行的过程过长;

这时候activity已经执行finish方法,activity被执行onDestory方法,然后activity相关的各种资源,组件都被销毁掉,但是由于handler隐式的持有activity的引用,那么activity就无法被回收,activity相关的资源与组件也无法被回收–即内存已经泄露。

2、解决办法:

1)、使用静态变量定义handler,handler对象由于是静态类型无法持有外部activity的引用;

2)、申明静态类,持有activity 弱引用;

static class MyHandler extends Handler {      WeakReference<Activity > mActivityReference;      MyHandler(Activity activity) {          mActivityReference= new WeakReference<Activity>(activity);      }      @Override      public void handleMessage(Message msg) {          final Activity activity = mActivityReference.get();          if (activity != null) {              mImageView.setImageBitmap(mBitmap);          }      }  }  

3)、在关闭Activity的时候停掉你的后台线程。线程停掉了,就相当于切断了Handler和外部连接的线,Activity自然会在合适的时候被回收。
4)、如果你的Handler是被delay的Message持有了引用,那么使用相应的Handler的removeCallbacks()方法,把消息对象从消息队列移除就行了。

@Override    protected void onDestroy() {        super.onDestroy();        if (mHandler != null)   {          mHandler.removeCallbacksAndMessages(null);        }                  }

9、65535方法数,怎么处理这个问题;

10、360 的悬浮窗是怎么实现的;

11、描述一下android 布局二叉树,树的顶段是什么?

activityManager—>>activity—>> window—>>DecorView

Activity是Android应用程序的载体,允许用户在其上创建一个用户界面,并提供用户处理事件的API,如onKeyEvent, onTouchEvent等。 并维护应用程序的生命周期;

Acivity的实例对象由系统维护。系统服务ActivityManager负责维护Activity的实例对象,并根据运行状态维护其状态信息。

Activity的内部实现,实际上是聚了一个Window对象。

当我们调用Acitivity的 setContentView方法的时候实际上是调用的Window对象的setContentView方法;

setContentView 中,首先创建一个DecorView,DecorView是一个扩张FrameLayout的类,是所有窗口的根View;

Activity创建后系统会调用其attach方法,将其添加到ActivityThread当中,在attach方法中创建了一个window对象。

结论:

Activity在onCreate之前调用attach方法,在attach方法中会创建window对象。window对象创建时并木有创建Decor对象对象。用户在Activity中调用setContentView,然后调用window的setContentView,这时会检查DecorView是否存在,如果不存在则创建DecorView对象,然后把用户自己的View 添加到DecorView中。

12、android 事件怎么传递的

Alt text

13、你使用过的网络请求框架,简单描述其内部实现;

Volley在Android 2.3及以上版本,使用的是HttpURLConnection,

而在Android 2.2及以下版本,使用的是HttpClient。

请求头的处理,缓存机制的支持等。并支持重试及优先级定义

HttpClient 已经废弃了

Volley :通过两种Dispatch Thread不断从RequestQueue中取出请求,根据是否已缓存调用CacheNetwork这两类数据获取接口之一,从内存缓存或是服务器取得请求的数据,然后交由ResponseDelivery去做结果分发及回调处理。

Volley 核心:通过 new RequestQueue(…)函数新建并启动一个请求队列RequestQueue后,只需要往这个RequestQueue不断 add Request即可。

核心类:RequestQueue 表示请求队列,里面包含一个CacheDispatcher(用于处理走缓存请求的调度线程)、NetworkDispatcher数组(用于处理走网络请求的调度线程),一个ResponseDelivery(返回结果分发接口),通过 start() 函数启动时会启动CacheDispatcherNetworkDispatchers

HttpStack:处理 Http 请求,返回请求结果。目前 Volley 中有基于 HttpURLConnection 的HurlStack和 基于 Apache HttpClient 的HttpClientStack

Network:调用HttpStack处理请求,并将结果转换为可被ResponseDelivery处理的NetworkResponse

Cache:缓存请求结果,Volley 默认使用的是基于 sdcard 的DiskBasedCacheNetworkDispatcher得到请求结果后判断是否需要存储在 Cache,CacheDispatcher会从 Cache 中取缓存结果。

CacheDispatcher:一个线程,用于调度处理走缓存的请求。启动后会不断从缓存请求队列中取请求处理,队列为空则等待,请求处理结束则将结果传递给ResponseDelivery去执行后续处理。当结果未缓存过、缓存失效或缓存需要刷新的情况下,该请求都需要重新进入NetworkDispatcher去调度处理。

NetworkDispatcher:一个线程,用于调度处理走网络的请求。启动后会不断从网络请求队列中取请求处理,队列为空则等待,请求处理结束则将结果传递给ResponseDelivery去执行后续处理,并判断结果是否要进行缓存。

Retrofit 直接使用OKHttp进行网络请求并不影响对OkHttp进行配置;

14、你使用过的图片加载框架,及其内部实现,fresco 与UIL之间的区别?

15、Handler,Looper,MessageQueue,Message,内部实现原理,消息队列是什么数据结构?

1、首先Looper.prepare()在本线程中保存一个Looper实例,然后该实例中保存一个MessageQueue对象;
因为Looper.prepare()在一个线程中只能调用一次,所以MessageQueue在一个线程中只会存在一个。

2、Looper.loop()会让当前线程进入一个无限循环,不端从MessageQueue的实例中读取消息,然后回调msg.target.dispatchMessage(msg)方法。

3、Handler的构造方法,会首先得到当前线程中保存的Looper实例,进而与Looper实例中的MessageQueue想关联。

4、Handler的sendMessage方法,会给msg的target赋值为handler自身,然后加入MessageQueue中。

5、在构造Handler实例时,我们会重写handleMessage方法,也就是msg.target.dispatchMessage(msg)最终调用的方法。

6、在Activity的启动代码中,已经在当前UI线程调用了Looper.prepare()和Looper.loop()方法。

16、数据库事物是用于干什么的?有什么局限?

17、守护进程

18 Android中图片占用内存的计算

Android中一张图片(BitMap)占用的内存主要和以下几个因数有关:图片长度,图片宽度,单位像素占用的字节数。
一张图片(BitMap)占用的内存=图片长度图片宽度单位像素占用的字节数
Bitmap.Config

ALPHA_8
此时图片只有alpha值,没有RGB值,一个像素占用一个字节
ARGB_4444
这种格式的图片,看起来质量太差,已经不推荐使用。
一个像素占用2个字节,alpha(A)值,Red(R)值,Green(G)值,Blue(B)值各占4个bites,共16bites,即2个字节
ARGB_8888
一个像素占用4个字节,alpha(A)值,Red(R)值,Green(G)值,Blue(B)值各占8个bites,共32bites,即4个字节
这是一种高质量的图片格式,电脑上普通采用的格式。它也是Android手机上一个BitMap的默认格式。
RGB_565
一个像素占用2个字节,没有alpha(A)值,即不支持透明和半透明,
Red(R)值占5个bites ,Green(G)值占6个bites ,Blue(B)值占5个bites,共16bites,即2个字节.
对于没有透明和半透明颜色的图片来说,该格式的图片能够达到比较的呈现效果,
相对于ARGB_8888来说也能减少一半的内存开销。因此它是一个不错的选择。
另外我们通过android.content.res.Resources来取得一个张图片时,它也是以该格式来构建BitMap的
从Android4.0开始,该选项无效。即使设置为该值,系统任然会采用 ARGB_8888来构造图片

Alt text

19、View 的绘制过程

系统在window中提供一个Canvas对象,DocerView通过调用draw方法来将自己绘制到canvas上。draw方法实际上是一个递归方法,他会循环调用孩子View的draw方法来完成整棵树的绘制。所以实际上一个界面的绘制所用的Cavans是同一个对象。Canvas内部聚合了Matrix对象来实现坐标系的变换。

Activity通过Context来获取WindowManager对象,然后把Window对象的DocerView添加到了WindowManager 服务中,所以android的窗口的创建和显示并不是在同一个进程中,而是把窗口的绘制和管理交给了专门的WindowManager服务,这也是android framework给我提供的基础服务。

20、Android Binder 机制

binder通信是一种client-server的通信结构;

1.从表面上来看,是client通过获得一个server的代理接口,对server进行直接调用;
2.实际上,代理接口中定义的方法与server中定义的方法是一一对应的;
3.client调用某个代理接口中的方法时,代理接口的方法会将client传递的参数打包成为Parcel对象;
4.代理接口将该Parcel发送给内核中的binder driver.
5.server会读取binder driver中的请求数据,如果是发送给自己的,解包Parcel对象,处理并将结果返回;
6.整个的调用过程是一个同步过程,在server处理的时候,client会block住。

21、描述进程间通信AIDL以及其机制;

22、APP内存优化之图片优化

1、不要将Button的背景设置为selector;
(如果是将Button的背景设置为selector,在初始化Button的时候会将正反选图片都加载在内存中,一个按钮占用了两张相同大小图片所使用的内存)
解决:
1)、代码设置

public static void setClickState(View view, final int normalResId, final int pressResId){            view.setOnTouchListener(new OnTouchListener() {                @Override                public boolean onTouch(View v, MotionEvent event) {                    switch(event.getAction()){                    case MotionEvent.ACTION_DOWN:{                        v.setBackgroundResource(pressResId);                    }                    break;                    case MotionEvent.ACTION_MOVE:{                        v.setBackgroundResource(pressResId);                    }                    break;                    case MotionEvent.ACTION_UP:{                        v.setBackgroundResource(normalResId);                    }                    break;                    default:{                    }                    break;                    }                    // 为了不影响监听按钮的onClick回调,返回值应为false                    return false;                }            });        }

2)、代码

ImageButton personalInfoBtn = (ImageButton)findViewById(R.id.personalBtnId);    personalInfoBtn.setOnTouchListener(new OnTouchListener() {        @SuppressLint("ClickableViewAccessibility")        @Override        public boolean onTouch(View v, MotionEvent event) {            int action = event.getAction();            if(action == MotionEvent.ACTION_DOWN){                ((ImageButton)v).setColorFilter(getResources().getColor(0X50000000));            }else if(action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL){                ((ImageButton)v).clearColorFilter();            }            // 为了不影响监听按钮的onClick回调,返回值应为false            return false;        }    });

2、将背景图片放在非UI线程绘制,提升APP的效率;

将背景图片通过SurfaceView来绘制,这样相当于是在非UI线程绘制,不会影响到UI线程做其它事情

3、关掉硬件加速;

如果使用到WebView、视频播放、手写、动画等功能时,关掉硬件加速会严重音效程序的运行效率,
这种情况可以只关闭掉Activity中某些view的硬件加速,整个Activity的硬件加速不关闭。

4、不要在Activity的主题中为Activity设置默认的背景图片,这样会导致Activity占用的内存翻倍

5、ViewStub的使用

6、尽量少用AnimationDrawable

自定义一个ImageView来实现AnimationDrawable的功能

23、布局优化

1、去掉window的默认背景

当我们使用了Android自带的一些主题时,window会被默认添加一个纯色的背景,
这个背景是被DecorView持有的。当我们的自定义布局时又添加了一张背景图或者设置背景色,
那么DecorView的background此时对我们来说是无用的,但是它会产生一次Overdraw,带来绘制性能损耗。

android:windowbackground="null"

2、ViewStub
3、Merge
4、.9图

原创粉丝点击