Android面试题(window、进程、线程篇),在一家公司干多长时间跳槽才合适

ServiceManager是整个Binder IPC通信过程中的守护进程,本身也是一个Binder服务,但并没有采用libbinder中的多线程模型来与Binder驱动通信,而是自行编写了binder.c直接和Binder驱动来通信,并且只有一个循环binder_loop来进行读取和处理事务,这样的好处是简单而高效。

ServiceManager本身工作相对并不复杂,主要就两个工作:查询和注册服务。

Q:Android中有哪些基于Binder的IPC方式?简单对比下?

Q:是否了解AIDL?原理是什么?如何优化多模块都使用AIDL的情况?

AIDL是Android Interface Define Language 安卓接口语言缩写。实现了服务端和客户端的通信。

服务端:创建一个Service用来监听客户端的链接需求,然后创建一个AIDL文件,将暴露给客户端的接口在这个AIDL文件中声明,最后在Service中实现这个接口

客户端:绑定服务端的Service,将服务端返回的Binder对象转成AIDL接口所属的类型,接着就可以调用AIDL中的方法了。

对于多模块,可用Binder连接池的思想:

每个业务模块创建自己的AIDL接口并实现此接口,但是不同模块之间不能耦合,所有实现单独开来,然后向服务端提供自己的唯一标识和其相对应的Binder对象,对于服务端来说,只需要一个Service就可以了,服务端提供一个queryBinder接口,这个接口根据业务模块特征返回相应打的Binder对象给客户端,不同业务模块拿到所需的Binder对象后就可以进行远程方法的调用了。由此可见,Binder连接池的作用就是将每个业务模块的Binder请求统一转发到远程Service中去执行,从而避免了重复创建Service的过程

Handler

=======

Q:谈谈消息机制Hander?作用?有哪些要素?流程是怎样的?

Message:主要功能是进行消息的封装,同时可以指定消息的操作形式;

Looper:消息循环泵,用来为一个线程跑一个消息循环。每一个线程最多只可以拥有一个。

MessageQueue:就是一个消息队列,存放消息的地方。每一个线程最多只可以拥有一个。

Handler:消息的处理者,handler 负责将需要传递的信息封装成Message,发送给Looper,继而由Looper将Message放入MessageQueue中。当Looper对象看到MessageQueue中含有Message,就将其广播出去。该handler 对象收到该消息后,调用相应的handler 对象的handleMessage()方法对其进行处理。

Q:为什么系统不建议在子线程访问UI?

可能在非UI线程中刷新界面的时候,UI线程(或者其他非UI线程)也在刷新界面,这样就导致多个界面刷新的操作不能同步,导致线程不安全。

Q:一个Thread可以有几个Looper?几个Handler?

①一个线程中只能有一个Looper,只能有一个MessageQueue,可以有多个Handler,多个Messge;

②一个Looper只能维护唯一一个MessageQueue,可以接受多个Handler发来的消息;

③一个Message只能属于唯一一个Handler;

④同一个Handler只能处理自己发送给Looper的那些Message;

Q:如何将一个Thread线程变成Looper线程?Looper线程有哪些特点?

新建一个Looper,添加looper.prepare和looper.loop即可

特点:可以创建handler,可以拥有自己的消息队列

Q:可以在子线程直接new一个Handler吗?那该怎么做?

不可以,会报错线程中不存在Looper,新建一个Looper,添加looper.prepare和looper.loop即可

Q:Message可以如何创建?哪种效果更好,为什么?

public class MainActivity extends Activity {

private Handler handler = new Handler() {

@Override

public void handleMessage(Message msg) {

Toast.makeText(MainActivity.this, “hanlder”, Toast.LENGTH_SHORT).show();

super.handleMessage(msg);

}

};

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

new Thread(new Runnable() {

@Override

public void run() {

// Message msg = new Message(); //直接初始化一个Message对象,很普通的方法

// Message msg = Message.obtain();

Message msg = handler.obtainMessage();

//后面两个是从整个Messge池中返回一个新的Message实例,通过obtainMessage能避免重复Message创建对象。

//一般在用到线程池的时候就会用到这2种。

msg.arg = 1;

handler1.sendMessage(msg);

}

}).start();

}

}

Q:ThreadLocal有什么作用?

ThreadLocal采用了类似于哈希表的形式轻松实现Looper在线程中的存取,可以在多个线程中互不干扰地存储和修改数据。

Q:主线程中Looper的轮询死循环为何没有阻塞主线程?

卡死主线程的操作是在回调方法onCreate/onStart/onResume等操作时间过长,会导致掉帧,甚至发生ANR,looper.loop本身不会导致应用卡死。

Q:使用Hanlder的postDealy()后消息队列会发生什么变化?

https://blog.csdn.net/qingtiantianqing/article/details/72783952

线程

==

Q:Android中还了解哪些方便线程切换的类?

AsyncTask:底层采用了线程池

HandlerThread:底层使用了线程

IntentService:底层使用了线程

Q:AsyncTask相比Handler有什么优点?不足呢?

AsyncTask是一种轻量级的异步任务类,它可以在线程池中执行后台任务,然后把执行的进度和最终结果传递给主线程并在主线程中更新UI。从实现上来说,AsyncTask封装了Thread和Handler。但是AsyncTask并不适合进行特别耗时的后台任务,对于特别耗时的任务来说,建议使用线程池

Q:使用AsyncTask需要注意什么?

https://blog.csdn.net/qq_30379689/article/details/53203556

AsyncTask的类必须在主线程中加载,这就意味着第一次访问AsyncTask必须发生在主线程中

AsyncTask的对象必须在主线程中创建

execute方法必须在UI线程中调用

不能直接在程序中调用着四个方法:

onPreExecute():异步任务开启之前回调,在主线程中执行

doInBackground():执行异步任务,在线程池中执行

onProgressUpdate():当doInBackground中调用publishProgress时回调,在主线程中执行

onPostExecute():在异步任务执行之后回调,在主线程中执行

onCancelled():在异步任务被取消时回调

一个AsyncTask对象只能执行一次,即只能调用一次excute方法,否则会报运行时异常。

Q:AsyncTask中使用的线程池大小?

https://www.cnblogs.com/Doing-what-I-love/p/5532984.html

1.corePoolSize=CPU核心数+1;

2.maximumPoolSize=2倍的CPU核心数+1;

3.核心线程无超时机制,非核心线程在闲置时间的超时时间为1s;

4.任务队列的容量为128。

处理任务的优先级为:

核心线程corePoolSize、任务队列workQueue、最大线程maximumPoolSize,如果三者都满了,使用handler处理被拒绝的任务(一般为抛出java.util.concurrent.RejectedExecutionException异常)。

Q:HandlerThread有什么特点?

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

https://blog.csdn.net/lsmfeixiang/article/details/42213119

HandlerThread本质上就是一个普通Thread,只不过内部建立了Looper。

HandlerThread将loop转到子线程中处理,说白了就是将分担MainLooper的工作量,降低了主线程的压力,使主界面更流畅。

开启一个线程起到多个线程的作用。处理任务是串行执行,按消息发送顺序进行处理。

相比多次使用new Thread(){…}.start()这样的方式节省系统资源。

但是由于每一个任务都将以队列的方式逐个被执行到,一旦队列中有某个任务执行时间过长,那么就会导致后续的任务都会被延迟处理。

HandlerThread拥有自己的消息队列,它不会干扰或阻塞UI线程。

通过设置优先级就可以同步工作顺序的执行,而又不影响UI的初始化;

Q:快速实现子线程使用Handler

https://www.cnblogs.com/lang-yu/p/6228832.html

使用HandlerThread即可,如果单独在子线程中创建Looper,有可能程序执行到Handler时,Looper还没初始化完成,造成程序崩溃。所以最好用HandlerThread,因为其内部确保了Looper的初始化完成。

public Looper getLooper() {

if (!isAlive()) {

return null;

}

// If the thread has been started, wait until the looper has been created.

synchronized (this) {

while (isAlive() && mLooper == null) {

try {

wait();

} catch (InterruptedException e) {

}

}

}

return mLooper;

}

Q:IntentService的特点?

IntentService是Service的子类,比普通的Service增加了额外的功能。优先级比普通的线程高。

先看Service本身存在两个问题:Service不会专门启动一条单独的进程,Service与他所在应用位于同一个进程中。 Service也不是专门一条新进程,因此不应该在Service中直接处理耗时的任务。

特点: IntentService会创建独立的worker线程来处理所有的Intent请求; 会创建独立的worker线程来处理onHandleIntent()方法实现的代码,无需处理多线程的问题;其内部也是封装了Handler。 所有请求处理完成后,IntentService会自动停止,无需调用stopSelf()方法停止Service; 为Service的onBind()提供默认实现,返回null; 为Service的onStartCommand提供默认实现,将请求Intent添加到队列中;

Q:为何不用bindService方式创建IntentService?

IntentService本身设计就不支持bind操作。查看IntentService源码,其中的onBind()函数被实现,而且返回null。这从侧面就证明了以上结论。再者,IntentService本身就是异步的,本身就不能确定是否在activity销毁后还是否执行,如果用bind的话,activity销毁的时候,IntentService还在执行任务的话就很矛盾了。

Q:线程池的好处、原理、类型?

https://blog.csdn.net/mine_song/article/details/70948223

管理重复线程,避免创建大量的线程增加开销。

除了降低开销以外,线程池也可以提高响应速度。

Q:ThreadPoolExecutor的工作策略?

(1)如果线程池中的线程数量未达到核心线程的数量,那么会直接启动一个核心线程来执行任务。

(2)如果线程池中的线程数量已经达到或超过了核心线程的数量,那么任务会进入任务队列中排队等待。

(3)如果在步骤(2)中无法将任务插入到任务队列,这往往是因为任务队列已满,这时候如果线程数量未达到线程池规定的最大值,那么会立即启动一个非核心线程来执行任务。

(4)如果步骤(3)中线程的数量已经达到了线程池规定的最大值,那么就拒绝执行此任务。

Q:什么是ANR?什么情况会出现ANR?如何避免?在不看代码的情况下如何快速定位出现ANR问题所在?

应用程序无响应,即应用程序5秒内没有反应就会提示应用程序无响应,应避免在主线程中进行耗时操作。

性能优化

====

Q:项目中如何做性能优化的?

https://blog.csdn.net/gs12software/article/details/51173392

Q:了解哪些性能优化的工具?

https://www.jianshu.com/p/31485a3cf5ca

Q:布局上如何优化?列表呢?

布局采用include,merge,viewstub

Q:内存泄漏是什么?为什么会发生?常见哪些内存泄漏的例子?都是怎么解决的?

多见于无限循环的动画和handler中没有及时清空message队列,在Activity的destroy()方法中关闭动画或清空队列即可

Q:内存泄漏和内存溢出的区别?

https://blog.csdn.net/ruiruihahaha/article/details/70270574

1、内存泄漏memory leak :是指程序在申请内存后,无法释放已申请的内存空间,一次内存泄漏似乎不会有大的影响,但内存泄漏堆积后的后果就是内存溢出。

2、内存溢出 out of memory :指程序申请内存时,没有足够的内存供申请者使用,或者说,给了你一块存储int类型数据的存储空间,但是你却存储long类型的数据,那么结果就是内存不够用,此时就会报错OOM,即所谓的内存溢出。 
3、二者的关系
内存泄漏的堆积最终会导致内存溢出
内存溢出就是你要的内存空间超过了系统实际分配给你的空间,此时系统相当于没法满足你的需求,就会报内存溢出的错误。
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则近万的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

img

img

img

img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:Android)

新的开始

改变人生,没有什么捷径可言,这条路需要自己亲自去走一走,只有深入思考,不断反思总结,保持学习的热情,一步一步构建自己完整的知识体系,才是最终的制胜之道,也是程序员应该承担的使命。

《系列学习视频》

《系列学习文档》

《我的大厂面试之旅》

《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!

新!**

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:Android)

新的开始

改变人生,没有什么捷径可言,这条路需要自己亲自去走一走,只有深入思考,不断反思总结,保持学习的热情,一步一步构建自己完整的知识体系,才是最终的制胜之道,也是程序员应该承担的使命。

《系列学习视频》
[外链图片转存中…(img-qwUnQ3ds-1712447183642)]

《系列学习文档》

[外链图片转存中…(img-gu7PEekV-1712447183643)]

《我的大厂面试之旅》

[外链图片转存中…(img-8xBPCOeB-1712447183643)]

《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!

  • 18
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值