Android技术知识Android开发Android开发

Android高级开发面试题目,再也不用担心不能升职加薪了。

2019-01-05  本文已影响12人  小小小小怪兽_666

Java基础

1、内部类的作用

2、父类的静态方法能否被子类重写,为什么?

想学习更多Android知识,或者获取相关资料请加入Android技术开发交流2群:862625886。本群可免费获取Gradle、RxJava、小程序、Hybrid、移动架构、NDK、React Native、性能优化等技术教程!

3、哪些情况下的对象会被垃圾回收机制处理掉

4、进程和线程的区别

5、HashMap的实现原理

6、String、StringBuffer、StringBuilder区别

在大部分情况下 StringBuffer > String

在大部分情况下 StringBuilder > StringBuffer

7、什么导致线程阻塞

线程的阻塞

关于 wait() 和 notify() 方法最后再说明两点:

Android基础

1、是否使用过IntentService,作用是什么,AIDL解决了什么问题?

2、Activity、Window、View三者的差别?

3、Fragment 特点

4、Handler、Thread和HandlerThread的差别?

5、Launch mode应用场景

注意:

6、Android事件分发机制

7、view绘制流程

8、post和postDelay

9、线程同步

10、单例模式

public class Singleton {
private volatile static Singleton mSingleton;
private Singleton () {
}
public static Singleton getInstance () {
if (mSingleton == null ){
synchronized (Singleton.class){
if (mSingleton == null )
mSingleton = new Singleton();
}
}
return mSingleton;
}
}

11、什么情况导致内存泄漏

a、资源对象没关闭造成的内存泄漏

描述: 资源性对象比如(Cursor,File文件等)往往都用了一些缓冲,我们在不使用的时候,应该及时关闭它们,以便它们的缓冲及时回收内存。它们的缓冲不仅存在于 java虚拟机内,还存在于java虚拟机外。如果我们仅仅是把它的引用设置为null,而不关闭它们,往往会造成内存泄漏。因为有些资源性对象,比如 SQLiteCursor(在析构函数finalize(),如果我们没有关闭它,它自己会调close()关闭),如果我们没有关闭它,系统在回收它时也会关闭它,但是这样的效率太低了。因此对于资源性对象在不使用的时候,应该调用它的close()函数,将其关闭掉,然后才置为null.在我们的程序退出时一定要确保我们的资源性对象已经关闭。 程序中经常会进行查询数据库的操作,但是经常会有使用完毕Cursor后没有关闭的情况。如果我们的查询结果集比较小,对内存的消耗不容易被发现,只有在常时间大量操作的情况下才会复现内存问题,这样就会给以后的测试和问题排查带来困难和风险。

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

以构造ListView的BaseAdapter为例,在BaseAdapter中提供了方法: public View getView(int position, ViewconvertView, ViewGroup parent) 来向ListView提供每一个item所需要的view对象。初始时ListView会从BaseAdapter中根据当前的屏幕布局实例化一定数量的 view对象,同时ListView会将这些view对象缓存起来。当向上滚动ListView时,原先位于最上面的list item的view对象会被回收,然后被用来构造新出现的最下面的list item。这个构造过程就是由getView()方法完成的,getView()的第二个形参View convertView就是被缓存起来的list item的view对象(初始化时缓存中没有view对象则convertView是null)。由此可以看出,如果我们不去使用 convertView,而是每次都在getView()中重新实例化一个View对象的话,即浪费资源也浪费时间,也会使得内存占用越来越大。 ListView回收list item的view对象的过程可以查看: android.widget.AbsListView.java --> voidaddScrapView(View scrap) 方法。 示例代码:

public View getView ( int position, ViewconvertView, ViewGroup parent) {
View view = new Xxx(...);
... ...
return view;
}
修正示例代码:
public View getView ( int position, ViewconvertView, ViewGroup parent ) {
View view = null ;
if (convertView != null ) {
view = convertView;
populate(view, getItem(position));
...
} else {
view = new Xxx(...);
...
}
return view;
}

c、Bitmap对象不在使用时调用recycle()释放内存

有时我们会手工的操作Bitmap对象,如果一个Bitmap对象比较占内存,当它不在被使用的时候,可以调用Bitmap.recycle()方法回收此对象的像素所占用的内存,但这不是必须的,视情况而定。

d、试着使用关于application的context来替代和activity相关的context

这是一个很隐晦的内存泄漏的情况。有一种简单的方法来避免context相关的内存泄漏。最显著地一个是避免context逃出他自己的范围之外。使用Application context。这个context的生存周期和你的应用的生存周期一样长,而不是取决于activity的生存周期。如果你想保持一个长期生存的对象,并且这个对象需要一个context,记得使用application对象。你可以通过调用 Context.getApplicationContext() or Activity.getApplication()来获得。更多的请看这篇文章如何避免 Android内存泄漏。

e、注册没反注册造成的内存泄漏

一些Android程序可能引用我们的Anroid程序的对象(比如注册机制)。即使我们的Android程序已经结束了,但是别的引用程序仍然还有对我们的Android程序的某个对象的引用,泄漏的内存依然不能被垃圾回收。调用registerReceiver后未调用unregisterReceiver。 比如:假设我们希望在锁屏界面(LockScreen)中,监听系统中的电话服务以获取一些信息(如信号强度等),则可以在LockScreen中定义一个 PhoneStateListener的对象,同时将它注册到TelephonyManager服务中。对于LockScreen对象,当需要显示锁屏界面的时候就会创建一个LockScreen对象,而当锁屏界面消失的时候LockScreen对象就会被释放掉。 但是如果在释放 LockScreen对象的时候忘记取消我们之前注册的PhoneStateListener对象,则会导致LockScreen无法被垃圾回收。如果不断的使锁屏界面显示和消失,则最终会由于大量的LockScreen对象没有办法被回收而引起OutOfMemory,使得system_process 进程挂掉。 虽然有些系统程序,它本身好像是可以自动取消注册的(当然不及时),但是我们还是应该在我们的程序中明确的取消注册,程序结束时应该把所有的注册都取消掉。

f、集合中对象没清理造成的内存泄漏

我们通常把一些对象的引用加入到了集合中,当我们不需要该对象时,并没有把它的引用从集合中清理掉,这样这个集合就会越来越大。如果这个集合是static的话,那情况就更严重了

12、ANR定位和如何避免?

1.如果开发机器上出现问题,我们可以通过查看/data/anr/traces.txt即可,最新的ANR信息在最开始部分。

2.主线程被IO操作(从4.0之后网络IO不允许在主线程中)阻塞。

3.主线程中存在耗时的计算

4.主线程中错误的操作,比如Thread.wait或者Thread.sleep等 Android系统会监控程序的响应状况,一旦出现下面两种情况,则弹出ANR对话框

5.应用在5秒内未响应用户的输入事件(如按键或者触摸)

6.BroadcastReceiver未在10秒内完成相关的处理

7.Service在特定的时间内无法处理完成 20秒

避免

1.使用AsyncTask处理耗时IO操作。

2.使用Thread或者HandlerThread时,调用Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND)设置优先级,否则仍然会降低程序响应,因为默认Thread的优先级和主线程相同。

3.使用Handler处理工作线程结果,而不是使用Thread.wait()或者Thread.sleep()来阻塞主线程。

4.Activity的onCreate和onResume回调中尽量避免耗时的代码

5.BroadcastReceiver中onReceive代码也要尽量减少耗时,建议使用IntentService处理。

13、什么情况导致OOM以及如何避免?

http://blog.csdn.net/yangxuehui1990/article/details/44994763

http://blog.csdn.net/ljx19900116/article/details/50037627

14、Android Service与Activity之间通信的几种方式?

通过Binder对象

通过Broadcast(广播)的形式

15、如何保证service在后台尽量不被kill

onStartCommand方法,返回START_STICKY

1.START_STICKY 在运行onStartCommand后service进程被kill后,那将保留在开始状态,但是不保留那些传入的intent。不久后service就会再次尝试重新创建,因为保留在开始状态,在创建 service后将保证调用onstartCommand。如果没有传递任何开始命令给service,那将获取到null的intent。

2.START_NOT_STICKY 在运行onStartCommand后service进程被kill后,并且没有新的intent传递给它。Service将移出开始状态,并且直到新的明显的方法(startService)调用才重新创建。因为如果没有传递任何未决定的intent那么service是不会启动,也就是期间onstartCommand不会接收到任何null的intent。

3.START_REDELIVER_INTENT 在运行onStartCommand后service进程被kill后,系统将会再次启动service,并传入最后一个intent给onstartCommand。直到调用stopSelf(int)才停止传递intent。如果在被kill后还有未处理好的intent,那被kill后服务还是会自动启动。因此onstartCommand不会接收到任何null的intent。

提升service优先级
在AndroidManifest.xml文件中对于intent-filter可以通过android:priority="1000"这个属性设置最高优先级,1000是最高值,如果数字越小则优先级越低,同时适用于广播。

提升service进程优先级
Android中的进程是托管的,当系统进程空间紧张的时候,会依照优先级自动进行进程的回收。Android将进程分为6个等级,它们按优先级顺序由高到低依次是:

前台进程( FOREGROUND_APP)
可视进程(VISIBLE_APP )
次要服务进程(SECONDARY_SERVER )
后台进程 (HIDDEN_APP)
内容供应节点(CONTENT_PROVIDER)
空进程(EMPTY_APP)
当service运行在低内存的环境时,将会kill掉一些存在的进程。因此进程的优先级将会很重要,可以使用startForeground 将service放到前台状态。这样在低内存时被kill的几率会低一些。

onDestroy方法里重启service
service+broadcast方式,就是当service走ondestory的时候,发送一个自定义的广播,当收到广播的时候,重新启动service;
Application加上Persistent属性
监听系统广播判断Service状态

16、RequestLayout,onLayout,onDraw,DrawChild区别与联系

1.requestLayout()方法 :会导致调用measure()过程 和 layout()过程 。说明:只是对View树重新布局layout过程包括measure()和layout()过程,不会调用draw()过程,但不会重新绘制 任何视图包括该调用者本身。

2.onLayout()方法(如果该View是ViewGroup对象,需要实现该方法,对每个子视图进行布局)

3.调用onDraw()方法绘制视图本身(每个View都需要重载该方法,ViewGroup不需要实现该方法)

4.drawChild()去重新回调每个子视图的draw()方法

17、invalidate()和postInvalidate() 的区别及使用

http://blog.csdn.net/mars2639/article/details/6650876

18、LinearLayout对比RelativeLayout

RelativeLayout会让子View调用2次onMeasure,LinearLayout 在有weight时,也会调用子View2次onMeasure

RelativeLayout的子View如果高度和RelativeLayout不同,则会引发效率问题,当子View很复杂时,这个问题会更加严重。如果可以,尽量使用padding代替margin。

在不影响层级深度的情况下,使用LinearLayout和FrameLayout而不是RelativeLayout。

19、优化自定义view

为了加速你的view,对于频繁调用的方法,需要尽量减少不必要的代码。先从onDraw开始,需要特别注意不应该在这里做内存分配的事情,因为它会导致GC,从而导致卡顿。在初始化或者动画间隙期间做分配内存的动作。不要在动画正在执行的时候做内存分配的事情。

你还需要尽可能的减少onDraw被调用的次数,大多数时候导致onDraw都是因为调用了invalidate().因此请尽量减少调用invaildate()的次数。如果可能的话,尽量调用含有4个参数的invalidate()方法而不是没有参数的invalidate()。没有参数的invalidate会强制重绘整个view。

另外一个非常耗时的操作是请求layout。任何时候执行requestLayout(),会使得Android UI系统去遍历整个View的层级来计算出每一个view的大小。如果找到有冲突的值,它会需要重新计算好几次。另外需要尽量保持View的层级是扁平化的,这样对提高效率很有帮助。

如果你有一个复杂的UI,你应该考虑写一个自定义的ViewGroup来执行他的layout操作。与内置的view不同,自定义的view可以使得程序仅仅测量这一部分,这避免了遍历整个view的层级结构来计算大小。这个PieChart 例子展示了如何继承ViewGroup作为自定义view的一部分。PieChart 有子views,但是它从来不测量它们。而是根据他自身的layout法则,直接设置它们的大小。

20、ContentProvider

https://www.jianshu.com/p/ea8bc4aaf057

21、Android 设计模式

http://blog.csdn.net/bboyfeiyu/article/details/44563871

22、MVC、MVP、MVM区别?

https://www.cnblogs.com/guwei4037/p/5591183.html

想学习更多Android知识,或者获取相关资料请加入Android技术开发交流2群:862625886。本群可免费获取Gradle、RxJava、小程序、Hybrid、移动架构、NDK、React Native、性能优化等技术教程!

上一篇 下一篇

猜你喜欢

热点阅读