今天是码仔给大家带来《每日一道面试题》的第十七期啦~
01
BroadcastReceiver与LocalBR的区别
Android中BroadcastReceiver与LocalBroadcastReceiver的区别 即本地广播和全局广播的区别
1)通信范围的比较1:LocalBroadcastReceiver即本地广播,而BroadcastReceiver是全局广播. 2:LocalBroadcastReceiver只能接收来自本App发送的广播,并且它只能用于应用内的通信. 所以它的安全性更好,但是通信范围比较小,仅局限于App应用内. 而BroadcastReceiver它不仅针对App内的广播有效,而且对App应用之间的广播通信、App应用和系统间的广播通信也有效,它的通信范围更大.
2)通信效率的比较1:LocalBroadcastManager的核心实现是Handler,因此它是应用内的通信,自然安全性更好,运行效率更高. 2:BroadcastReceiver的核心实现是Binder,是全局广播,可以跨进程通信,范围更广,从而导致它的运行效率没有本地广播高效,毕竟一个是本地的通信,一个是跨进程的通信方式,效率肯定相对较低点,但对于实时性不高的应用场景我们可以忽略不计.
3)注册方式的比较1:本地广播不能用静态注册的方式,只能采用动态注册的方式. 2:全局广播可以用静态注册的方式,也可以采用动态注册的方式.
4)注册代码的比较1:本地广播注册代码 IntentFilter filter = new IntentFilter(); filter.addAction(ACTION_LOCAL_SEND); LocalBroadcastManager.getInstance(this).registerReceiver(mLocalBroadcastReceiver, filter); 2:全局广播注册代码 IntentFilter filter = new IntentFilter(); filter.addAction(ACTION_ALL_SEND); getBaseContext().registerReceiver(mBroadcastReceiver, filter);
5)取消注册代码的比较1:本地广播取消注册代码 if (mLocalBroadcastReceiver != null) { LocalBroadcastManager.getInstance(this).unregisterReceiver(mLocalBroadcastReceiver); } 2:全局广播取消注册代码 if (mBroadcastReceiver != null) { getBaseContext().unregisterReceiver(mBroadcastReceiver); }
6)发送广播代码的比较1:本地广播发送代码 Intent intent = new Intent(ACTION_LOCAL_SEND); Bundle extras = new Bundle(); extras.putString(KEY_MSG, "local"); intent.putExtras(extras); LocalBroadcastManager.getInstance(this).sendBroadcast(intent); 2:全局广播发送代码 Intent intent = new Intent(ACTION_ALL_SEND); Bundle extras = new Bundle(); extras.putString(KEY_MSG, "all"); intent.putExtras(extras); getBaseContext().sendBroadcast(intent);
02
并行和并发有什么区别
并行:多个处理器或多核处理器同时处理多个任务。
并发:多个任务在同一个 CPU 核上,按细分的时间片轮流(交替)执行,从逻辑上来看那些任务是同时执行。
举例:并发 = 两个队列和一台咖啡机。并行 = 两个队列和两台咖啡机。
03
LinearLayout和RelativeLayout对比
-
RelativeLayout会让子View调用2次onMeasure,LinearLayout 在有weight时,也会调用子View2次onMeasure
-
RelativeLayout的子View如果高度和RelativeLayout不同,则会引发效率问题,当子View很复杂时,这个问题会更加严重。如果可以,尽量使用padding代替margin。
-
在不影响层级深度的情况下,使用LinearLayout和FrameLayout而不是RelativeLayout。
最后再思考一下为什么Google给开发者默认新建了个RelativeLayout,而自己却在DecorView中用了个LinearLayout。因为DecorView的层级深度是已知而且固定的,上面一个标题栏,下面一个内容栏。采用RelativeLayout并不会降低层级深度,所以此时在根节点上用LinearLayout是效率最高的。而之所以给开发者默认新建了个RelativeLayout是希望开发者能采用尽量少的View层级来表达布局以实现性能最优,因为复杂的View嵌套对性能的影响会更大一些。
04
JVM加载class文件的原理机制
JVM加载class文件的原理机制 JVM中类的装载是由类加载器(ClassLoader)和它的子类来实现的,Java中的类加载器是一个重要的Java运行时系统组件,它负责在运行时查找和装入类文件中的类。由于Java的跨平台性,经过编译的Java源程序并不是一个可执行程序,而是一个或多个类文件。当Java程序需要使用某个类时,JVM会确保这个类已经被加载、连接(验证、准备和解析)和初始化。 类的加载是指把类的.class文件中的数据读入到内存中,通常是创建一个字节数组读入.class文件,然后产生与所加载类对应的Class对象。加载完成后,Class对象还不完整,所以此时的类还不可用。当类被加载后就进入连接阶段,这一阶段包括验证、准备(为静态变量分配内存并设置默认的初始值)和解析(将符号引用替换为直接引用)三个步骤。 最后JVM对类进行初始化,包括:
-
如果类存在直接的父类并且这个类还没有被初始化,那么就先初始化父类。
-
如果类中存在初始化语句,就依次执行这些初始化语句。
-
类的加载是由类加载器完成的,类加载器包括:根加载器(BootStrap)、扩展加载器(Extension)、系统加载器(System)和用户自定义类加载器(java.lang.ClassLoader的子类)。
从Java 2(JDK 1.2)开始,类加载过程采取了父亲委托机制(PDM)。PDM更好的保证了Java平台的安全性,在该机制中,JVM自带的Bootstrap是根加载器,其他的加载器都有且仅有一个父类加载器。类的加载首先请求父类加载器加载,父类加载器无能为力时才由其子类加载器自行加载。 JVM不会向Java程序提供对Bootstrap的引用。下面是关于几个类加载器的说明:
-
Bootstrap:一般用本地代码实现,负责加载JVM基础核心类库(rt.jar)。
-
Extension:从java.ext.dirs系统属性所指定的目录中加载类库,它的父加载器是Bootstrap。
-
System:又叫应用类加载器,其父类是Extension。它是应用最广泛的类加载器。它从环境变量classpath或者系统属性 java.class.path所指定的目录中记载类,是用户自定义加载器的默认父加载器。
05
Android主线程怎么给子线程发message
一言不合!上代码!
/** * 演示主线程给子线程发送Message */public class MainActivity extends AppCompatActivity { private Handler mHandler; private Looper mLooper; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //Activity启动的时候创建一个子线程,并启动 MyThread thread = new MyThread(); thread.start(); } /** * 绑定布局中的点击按钮,点击后给子线程发送消息 */ public void click(View view) { Message message = new Message(); message.obj = "来自主线程"; mHandler.sendMessage(message); } /** * 绑定布局文件中的按钮2,点击后让子线程退出,关闭子线程 * 其实这里只需要让子线程的Looper对象退出即可,因为Looper.loop();是线程阻塞的. */ public void click2(View view) { if (mLooper != null) { mLooper.quit(); } } @Override protected void onDestroy() { super.onDestroy(); //在退出的时候,将子线程释放掉,不然可能会导致内存泄露 if (mLooper != null) { mLooper.quit(); } } private class MyThread extends Thread { @SuppressLint("HandlerLeak") @Override public void run() { //1. 创建一个Looper对象(内部创建了MessageQueue, // 并将MessageQueue作为Looper对象的成员,然后将Looper对象绑定到ThreadLocal中 // Looper.prepare(); // 创建一个Handler mHandler = new Handler() { @Override public void handleMessage(Message msg) { //处理主线程发送的消息 Log.e("tag", "接收到信息" + msg); } }; //2.获取当前Looper对象 mLooper = Looper.myLooper(); //3.让消息循环起来 Looper.loop(); Log.e("tag-", "子线程退出"); } }}
06
结束语
如果你有好的答案可以提交至:
https://github.com/codeegginterviewgroup/CodeEggDailyInterview
往期文章:
今日问题:
大家有什么好的面试题要分享吗?![]()
专属升级社区: 《这件事情,我终于想明白了》