Android 面试(Android 篇)

Android 面试 安卓篇

一、跨进程通信的几种方式

 1 Intent 比如拨打电话
 2 ContentProvider 数据库存储数据  (底层同样也是Binder,专门用于不同应用间共享数据。支持一对多进程数据         共享)
 3 Broadcast 广播通信
 4 ALDL 通信,通过接口共享数据 (支持一对多通信,支持RPC)

二、多进程应用使用场景

 1 需要向其他应用获取数据
 2 某些应用模块需要单独运行在进程中(WebView优化,后台进程)
 3 加大一个应用可使用的内存(获取多份内存空间)

三、Binder 机制 (进程间的通信)

 Binder 是 Android 为我们提供的 IPC(Inner Process Commnuication进程间通信)的一种方式,Android 中的   
 Activity 、Service、Broadcast、ContentProvider 都是运行在不同的进程中,Binder 是他们之间进行通信的桥梁。

原理:

 首先要定义要传输的对象,并进行序列化,反序列化,然后在相同包名下定义 AIDL 接口、要传输的对象,然后定义   好了以后,
 再 makeProject ,生成对应的类,然后再创建一个 Service 写服务端的代码,然后再客户端使用 bindService 方法进行连接,
 再 ServiceConnection 的回调方法中拿到服务端的接口对象,之后就可以往服务端发送消息。

四、说一说 ANR

在 Android 系统中,如果应用程序有一段时间响应不够灵敏,系统会向用户显示一个对话框,这个对话框称作应用程
序无响应(ANR:ApplicationNotResponding)对话框。即页面无响应, 用户可以选择让程序继续运行,但是,他
们在使用你的应用程序时,并不希望每次都要处理这个对话框。因此 ,在程序里对响应性能的设计很重要,这样系
统就不会显示 ANR 给用户。

触发条件:

Activity:5 秒。应用在 5 秒内未响应用户的输入事件(如按键或者触摸)
BroadCastReceiver :10 秒。BroadcastReceiver 未在 10 秒内完成相关的处理
Service:20 秒(均为前台)。Service 在20 秒内无法处理完成

引起条件:

主线程被 IO 操作(从 4.0 之后网络 IO 不允许在主线程中)阻塞;
主线程中存在耗时的计算;
主线程中错误的操作,比如 Thread.wait 或者 Thread.sleep 等。

查看方式

C盘: /data/anr/traces.txt

避免建议:

将所有耗时操作,比如访问网络,Socket 通信,查询大量 SQL 语句,复杂逻辑计算等都放在子线程中去,然后通过 
handler.sendMessage、runOnUIThread、 AsyncTask、RxJava 等方式更新 UI。无论如何都要确保用户界面的流畅
度。如果耗时操作需要让用户等待,那么可以在界面上显示度条。

五、什么是OOM,如何避免解决

 oom就是我们常说的Out of Memory内存溢出,它是指需要的内存空间大于系统分配的内存空间,oom后果就是项目程
 序crash;

原因

1、加载大图片导致内存溢出
2、大量内存泄露
3  线程数量过多,队列容量设置过大,导致OOM

解决

1 使用软引用,弱引用,当堆内内存不足时,就可以自动释放缓存的Bitmap对象  
2 使用过的图并且不再使用,可以调用Bitmap.recycle()加速回收
3 考虑使用文件缓存
4 使用统一的线程池管理类进行线程管理。

扩展

由于手机设备的限制,一般一个应用使用的内存不能超过默认值 32M(不同设备略有差异,通过adb shell getprop | 
grep dalvik.vm.heapgrowthlimit命令查看),这也就是说,当在DVM上申请的堆内存大于默认阀值的时候,我们的应
用就会抛出OutOfMemoryError

六、内存泄露,内存溢出,内存抖动

内存抖动

原因:大量的对象被创建又在短时间内马上被释放,导致内存使用量上下波动 GC 处理帧率锅过快
解决:避免在循环中创建临时对象
     避免在onDraw方法中创建Paint或Bitmap对象
     避免在onDraw方法中做耗时操作

内存溢出

原因:内存溢出是指当对象的内存占用已经超出分配内存的空间大小,这时未经处理的异常就会抛出。比如常见的内
     存溢出情况有:bitmap过大;引用没释放;资源对象没关闭 
     1 由于我们程序的失误,长期保持某些资源(如Context)的引用,垃圾回收器就无法回收它,当然该对象占用的内
     存就无法被使用,这就造成内存泄露。                         
     2 占用内存较多的对象 保存了多个耗用内存过大的对象(如Bitmap)或加载单个超大的图片,造成内存超出限制。

扩展:

 Android中常见就是Activity被引用,在调用finish之后却没有释放,第二次打开activity又重新创建,这样的内存泄露不
 断的发生,则会导致内存的溢出。

内存泄漏

原因:有些对象只有有限的生命周期。当它们的任务完成之后,它们将被垃圾回收。如果在对象的生命周期本该结束 
     的时候,这个对象还被一系列的引用,这就会导致内存泄漏。随着泄漏的累积,app将消耗完内存。(工具 
     leakcanary)比如当你向系统申请分配内存进行使用(new),可是使用完了以后却不归还(delete),结果你申请到的
     那块内存你自己也不能再访问(也许你把它的地址给弄丢了),而系统也不能再次将它分配给需要的程序

问:常见的内存泄露有哪些?如何解决?

1 资源对象没关闭如Cursor,File等资源。他们会在finalize中关闭,但这样效率太低。容易造成内存泄漏      
  SQLiteCurost,当数据量大的时候容易泄漏
2 使用Adapter时,没有使用系统缓存的converView
3 没有即时调用recycle()释放不再使用的bitmap
4 context引起的内存泄漏
     解决:使用application的context来替代activity相关的context,不要让生命周期长于Activity的对象持有到Activity的
          引用
5 广播注册没取消造成内存泄露
6 Handler引起的内存泄偶
     原因:匿名内部类持有外部类对象,Handler持有当前activity:
     解决:应该申明为静态对象, 并在其内部类中保存一个对外部类的弱引用。
7 单例模式中使用Activity作为Context引起的内存泄漏
     原因:单例模式中应该避免使用Activity作为传入的Context,否则,单例模式会持有这个Activity的引用,导致它无
          法释放,造成内存泄漏。
     解决:应该使用ApplicationContext作为Context传入。如果一定要使用Activity的话,要使用弱引WeakReference
8 webview导致的内存泄漏
     原因:  开启一个webview 也就是开启了一个线程来展示webview,当activity 加载webview的时候,因activity 的生命周期无法控制Webview ,导致webview 一直持有当前的activity引用不能回收。
     解决:1 创建独立的进程
          2 动态添加webview,对传入webview中的context 使用弱引用,动态添加webview的意思就是在布局中创建个
            viewGroup来放置webview

问:为什么单例模式会持有当前activity的引用,无法释放

   单例模式使用的是 static 修饰的,我们知道,static 修饰的对象会一直存在内存中当持有的activity被销毁的时候,但
   单例一直持有当前的activity ,并不会被销毁    

七、Webview 常见的坑

1	Android api 16 之前存在远程代码执行安全漏洞,源于开发者没有正确使用Webview.addJavaScriptInterface方法
 
2	Webview 在布局文件中使用时,在生命周期结束时先要在布局文件中Webview在调用webview的销毁方法

3	后台耗电问题 在关闭webview 页面时要及时销毁

4	硬件加速导致页面渲染问题 关闭当前页面的硬件加速

八、屏幕旋转后的生命周期

 1 用户首次进入页面后执行的生命周期回调方法
        onCreate – onStart – onResume
 2 屏幕发生旋转后,切换成了横屏,原先的活动被销毁,会重新创建新的活动
        onPause – onStop – onDestroy – onCreate – onStart - onResume
 3 将横屏切回为竖屏,执行的生命周期回调方法为,横屏的活动被销毁,之后重新创建竖屏的活动界面
        onPause – onStop – onDestroy – onCreate – onStart - onResume  

九、Activity 启动流程

 用户从Launcher程序点击应用图标可启动应用的入口Activity,Activity启动时需要多个进程之间的交互,Android系统
 中有一个zygote进程专用于孵化Android框架层和应用层程序的进程。还有一个system_server进程,该进程里运行了
 很多binder service。例如ActivityManagerService,PackageManagerService,WindowManagerService,这些
 binder service分别运行在不同的线程中,其中ActivityManagerService负责管理Activity栈,应用进程,task。

备注:

 用户在Launcher程序里点击应用图标时,会通知ActivityManagerService启动应用的入口
 Activity,ActivityManagerService发现这个应用还未启动,则会通知Zygote进程孵化出应用进程,然后在这个dalvik
 应用进程里执行ActivityThread的main方法。应用进程接下来通知ActivityManagerService应用进程已启
 动,ActivityManagerService保存应用进程的一个代理对象,这样ActivityManagerService可以通过这个代理对象控
 制
 应用进程,然后ActivityManagerService通知应用进程创建入口Activity的实例,并执行它的生命周期方法。

十、Activity 启动模式

standard:标准模式,

默认即标准模式,每启动一个Activity,都会创建一个新的实例 即都会执行onCreate方法

生命周期:

1 先启动 A 

在这里插入图片描述
2 从 A 跳转 B
在这里插入图片描述
3 从 B 跳转 A
在这里插入图片描述
singleTop 栈顶复用模式

 当要启动的目标Activity已经位于栈顶时,不会创建新的实例,会复用栈顶的Activity,并且其onNewIntent()方法会被
 调用,如果目标Activity不在栈顶,则跟standard一样创建新的实例。
 生命周期:
 A B C 三个Activity都设置为singletop启动模式。先启动A,再从A跳转至B,然后从B跳转至C。即A->B->C,先都创
 建出实例。可以看到三个Activity都在同一个栈内,1531为TaskID,可通getTaskId()获得此时C在栈顶,从C->C,栈
 顶复用,没有调用onCreate和onStart,直接调用了onNewIntent、onResume 此时从C->A,A没有在栈顶,会被新
 创建实例

在这里插入图片描述

singleTask 栈内复用模式

在同一个任务栈中,如果要启动的目标Activity已经在栈中,则会复用该Activity,并调用其onNewIntent()方法,并且该
Activity上面的Activity会被清除,如果栈中没有,则创建新的实例
生命周期:
A B C 三个Activity都设置为singletop启动模式。先启动A,再从A跳转至B,然后从B跳转至C。
此时栈内的顺序为A栈底、B栈中、C栈顶。
从C启动C,生命周期的变化和栈顶复用一样,再从C启动A,此时BC均会被弹出,且先销毁B再销毁C,过程如下

在这里插入图片描述

singleInstance 单例模式

 设置了该模式的 Activity 只能位于一个单独的任务栈中,不能在有其他 Activity , 其他任何从该 Activity 启动的其他 
 Activity 都会放到其他的任务栈中,常用于启动壁纸,电话,闹钟等界面实现。

生命周期
A B C 三个Activity都设置为singleInstance启动模式。
分别启动A、B、C,可以看到不同的Activity TaskId不同,即都有独立的栈
可以比较C-C和C->A是生命周期的变化,A不会onCreate,但生命周期是从onRestart开始的,C是先onNewIntent

在这里插入图片描述
扩展:onNewIntent 方法:

 ActivityA已经启动过,处于当前应用的Activity堆栈中; 当ActivityA的LaunchMode为SingleTop时,如果ActivityA在栈   
 顶,且现在要再启动ActivityA,这时会调用onNewIntent()方法 当ActivityA的LaunchMode为  SingleInstance,SingleTask时,如果已经ActivityA已经在堆栈中,那么此时会调用onNewIntent()方法 当ActivityA的
 LaunchMode为Standard时,由于每次启动ActivityA都是启动新的实例,和原来启动的没关系,所以不会调用原来
 ActivityA的onNewIntent方法

问:一个启动模式为 singleTop 的 activity,如果再试图启动会怎样?

当一个 Activity 接收到新 Intent 的时候会处于暂停状态,因此你可以统计到 onResume()方法会被再次执行,当 然这
个执行是在 onNewIntent 之后的,注意:如果我们在 Activity 中调用了 getIntent()方法,那么返回的 Intent 对象还    是老的 Intent(也就是第一 次启动该 Activity 时的传入的 Intent 对象),
但是如果想让 getIntent()返回最新的 Intent,那么我们可以通过 setIntent(Intent)方法设置

问:栈顶活动为A,此时再启动一个活动A,那么活动A会经历那些生命周期的变化?

 那么此时经历的生命周期分两种情况的 对于这题,暂且称已经启动的活动A为“1
 号A活动”,未启动的称为“2号A活动”。
 
 1 A活动的启动模式为默认,也即是“standard” 
   顺序为:1号A活动(onPause)→2号A活动(onCreate)...
 2 A活动的启动模式不为默认,可以是:“singleTask”、“singleTop”、  “singleInstance”
   顺序为:1号A活动(onPause)→1号A活动(onNewIntent)→1号A活动 (onResume)

十一、Activity 生命周期

1 onCreate()     Activtiy正在创建,做初始化,调用setContentView初始化布局资源
2 onRestart()    Activity被重新启动,这种情况一般是用户把Activtiy切回后台,之后又切回来
3 onStart()      Activity正在被启动,这时候Activtiy已经可见,但是还没有显示到前台
4 onResume()     Activity已经可见了,已经显示到前台
5 onPause()      Activtiy正在停止,紧接着会执行onStop,切在此阶段勿做耗时操作
6 onStop()       Activtiy正在被停止,可以做写微重量级的操作
7 onDestroy()    Activtiy已经被销毁,回收工作与资源释放

特殊场景:

 1 当用户打开新的Activity切换到桌面,正常为onPause--onStop,如果新的Activtiy是透明的话,当前Activity不会执
   行onSop
 2 当用户按下back键回退时候,onPause--onStop—onDestroy
 3 系统突然旋转屏幕,当系统配置发生改变的时候, 在默认情况下,比如当前Activity处于竖着的屏幕的时候,突然旋
   转,会导致Activtiy生命周期发生改变。当Activtiy在异常情况下终止的,所以系统会调用onSaveInstanceState来保 
   存  当前数据Activtiy,这个是在OnStop之前,在新建Activtiy的时候,在OnCreate方法会执行   
   onRestoreInStanceState
   恢复数据。当正常情况下,Activity不会调用onSaveInstanceState。

问: 如果是启动一个 Theme 为 Dialog的 Activity , 则生命周期是怎么样的

 A.onPause -> B.onCrete -> B.onStart -> B.onResume
 注意:边没有前一个 Activity 不会回调 onStop,因为只有在 Activity 切到后台不可见才会回调 onStop;而弹出 
      Dialog 主题的 Activity 时前一个页面还是可见的,只是失去了焦点而已所以仅有 onPause 回调。

问:从activityA跳转到activityB的生命周期

在这里插入图片描述

十二、Service 生命周期

onCreate() 首次创建服务时,系统将调用此方法。如果服务已在运行,则不会调用此方法,该方法只调用一次。

onStartCommand() 当另一个组件通过调用startService()请求启动服务时,系统将调用此方法。

onDestroy() 当服务不再使用且将被销毁时,系统将调用此方法。

onBind() 当另一个组件通过调用bindService()与服务绑定时,系统将调用此方法。

onUnbind() 当另一个组件通过调用unbindService()与服务解绑时,系统将调用此方法。

onRebind() 当旧的组件与服务解绑后,另一个新的组件与服务绑定,onUnbind()返回true时,系统将调用此方法。

备注:Android执行Service有两种方法,一种是onstartService,一种是onbindService。

问: 什么情况下既使用onstartService和 onbindService

 如果你只是想要启动一个后台服务长期进行某项任务,那么使用startService便可以了。如果你还想要与正在运行的
 Service取得联系,那么有两种方法:一种是使用broadcast,另一种是使用bindService。  前者的缺点是如果交流较
 为频繁,容易造成性能上的问题,而后者则没有这些问题。因此,这种情况就需要startService和bindService一起使
 用了。

问:onstartService 与 onbindService区别

onstartService只是启动Service,调用者和服务是没有关联的,即使调用者退出了,服务依然在后台运行,
onbindService是将调用者与服务绑定,一旦调用者退出,服务也跟着退出。
onbindService;onCreate()->onStartCommand()->startService()->onDestroy()
onbindService;onbindService生命周期:

举例 ;最常用的Service就是音乐播放,如果你要startService的话,应用退出了,音乐还在播放。用bindService的
      话,程序退出了,音乐也就停了

十三、Service 里面可以弹吐司么?

  可以的。弹吐司有个条件就是得有一个 Context 上下文,而 Service 本身就是 Context 的子类,因此在 Service 里  
  面  弹吐司是完全可以的。比如我们在 Service 中完成下载任务后可以弹一个吐司通知用户。

十四、注册广播的几种方式,优缺点

第一种:在清单文件中声明
第二种:使用代码进行注册如:
两种注册类型的区别是:
 1)第一种不是常驻型广播,也就是说广播跟随程序的生命周期。
 2)第二种是常驻型,也就是说当应用程序关闭后,如果有信息广播来,程序也会被系统调用自动运行。

十五、onActivityResult 在哪两个生命周期之间回调?

onActivityResult 不属于 Activity 的生命周期。所以 onActivityResult() 回调先于该 Activity 的所有生命周期回调,从  
B Activity 返回 A Activity 的生命周期调用为:
B.onPause() -> A.onActivityResult() -> A.onRestart() -> A.onStart() -> A.onResume()

十六、在Activity的 onCreate() 方法里写死循环会 ANR 吗?

 在 Activity 的 onCreate() 方法中写死循环是不会发生ANR的,但是主线程被死循环一直占用了,所以当再有其他事件
 产生时,就不能及时响应了,从而导致ANR发生。

十七、 Context,Activity,Service,Applicatioin 之间的关系

1 Context 上下文对象,为应用运行的环境相关信息、资源的接口(提供了访问应用资源的接口);同时提供了应用级别
  操作的接口。如启动Activity,绑定服务,发送广播等操作。
2 Activity   用户交互载体。
3 Service  一个执行耗时操纵或者给其他应用提供功能的组件。
4 Application 维护整个应用的组件。(单例)

注意:Context定义了操作的接口,真正实现功能的是ContextImpl类。ContextWrapper为包装类。下图中 
     ContextWrapper 类中 mBase 类型为Context,正是通过mBase对象,将所有ContextWrapper中方法的调用委托 
     给了 ContextImpl对象,因此子类Activity,Service,Application中调用Context接口的方法实际上都是调用了
     ContextWrapper对象中的方法。
     应用中Context对象个数=Application(1)+Activity个数+Service个数

在这里插入图片描述

十八、Activity、Intent、Service 关系

 他们都是 Android 开发中使用频率最高的类。其中 Activity 和 Service 都是 Android 四大组件之一。他俩都是   
 Context 类的子类 ContextWrapper 的子类,因此他俩可以算是兄弟关系吧。不过兄弟俩各有各自的本领,Activity 负
 责用户界面的显示和交互,Service 负责后台任务的处理。Activity 和 Service 之间可以通过 Intent 传递数据,因此 
 可以把 Intent 看作是通信使者

十九、Activity 与 Fragment 通信

 接口方式回调、Bundle通信 、 eventbus、广播、 数据库、文件、SharedPreferences,ContentProvider

二十、Activity 向 Fragment 传值

 Activity向Fragment传值,要传的值放到bundle对象里; 在Activity中创建该Fragment的对象fragment,通过调用 
 setArguments()传递到fragment中; 在该Fragment中通过调用getArguments()得到bundle对象,就能得到里面的
 值。

二十一、Fragment 向 Activity 传值

 1) 在Activity中调用getFragmentManager()得到fragmentManager调用findFragmentByTag(tag)或者通过
     findFragmentById(id),例如:
     FragmentManager fragmentManager = getFragmentManager();
     Fragment fragment=fragmentManager.findFragmentByTag(tag);

 2) 通过回调的方式,定义一个接口(可以在Fragment类中定义),接口中有一个空的方法,在fragment中需要的
     时候调用接口的方法,值可以作为参数放在这个方法中,然后让Activity实现这个接口,必然会重写这个方法,这
     样值就传到了Activity中

二十二、Fragment 与 Fragment 通信

 1 通过findFragmentByTag得到另一个的Fragment的对象,这样就可以调用另一个的方法了。
 2 通过接口回调的方式。
 3 通过setArguments,getArguments的方式。

二十三、系统内存不足如何保存activity的状态?

  扩展:是当系统内存不足时, 调用onPause()和onStop()方法后的 activity可能会被系统摧毁, 此时内存中就不会存有 
       该 activity 的实例对象了。如果之后这个 activity 重新回到前台, 之前所作的改变就会消失。
  解答:我们可以覆写 onSaveInstanceState()方法。onSaveInstanceState()方法接受一个 Bundle 类型的参数, 开
       发者可以 将状态数据存储到这个 Bundle 对象中, 这样即使 activity 被系统摧毁, 当用户重新启动这个 activity 而调
       用它的 onCreate()方法时, 上述的 Bundle 对象会作为实参传递给 onCreate()方法, 开发者可以从 Bundle 对象中
       取 出保存的 数据, 然后利用这些数据将 activity 恢复到被摧毁之前的状态。 需要注意的是, 
       onSaveInstanceState()方
       法并不是一定会被调用的, 因为有些场景是不需要保存状态数据的. 比 如用户按下 BACK 键退出 activity 时, 用户
       显 然想要关闭这个 activity, 此时是没有必要保存数据以供下次恢复的, onSaveInstanceState()方法不会被调用. 
       如果  调 用 onSaveInstanceState()方法, 调用将发生在 onPause()或 onStop()方法之前

二十四、如何安全退出已调用多个activity?

1  每打开一个 Activity,就记录下来。在需要退出时,关闭每一个 Activity 即可

在这里插入图片描述

2 发送特定广播
  在需要结束应用时,发送一个特定的广播,每个 Activity 收到广播后,关闭即可。 给某个 activity 注册接受接受广播
  的意图 registerReceiver(receiver, filter) //如果过接受到的是 关闭 activity 的广播 就调用 finish()方法 把当前的 
  activity finish()掉

二十五、ViewHolder 为什么要声明为静态类?

非静态内部类拥有外部类对象的强引用,因此为了避免对外部类(外部类很可能是 Activity)对象的引用,那么最 好将
内部类声明为 static 的。

二十六、ListView 可以显示多种类型的条目吗?

ListView 显示的每个条目都是通过 baseAdapter 的 getView(int position, View convertView, ViewGroup parent)来
展 示的,理论上我们完全可以让每个条目都是不同类型的 view,除此之外 adapter 还提供了 getViewTypeCount()
和 getItemViewType(int position)两个方法。在 getView 方法中我们可以根据不同的 viewtype 加载不同的布局文件

二十七、Android 启动优化

Android启动应用, 按官方说法为冷启动, 温启动和热启动.
       冷:系统需要从零开始启动应用, 一般是首次启动或者应用被系统终止后启动
       热:进程跟activity都在 典型场景是Home键退出应用后又进入应用.
优化方案  1 获取启动时间,使用adb命令和代码打点这两种方式
         2 找到程序中耗时较长的代码
         3 异步加载:耗时多的加载放到子线程中异步执行
           延迟加载: 非必须的数据延迟加载
            提前加载:利用ContentProvider提前进行初始化
         4  应用中,增加启动默认图或者自定义一个Theme,在Activity首 先使用一个默认的界面解决部分启动短暂黑白
            屏问题。如 android:theme="@style/Theme.AppStartLoad"

二十八、Android 布局优化

1.	尽可能减少布局的嵌套层级 使用<include>标签复用相同的布局代码
2.	通过实现<ViewStub>实现View的延时加载
   ![在这里插入图片描述](https://img-blog.csdnimg.cn/8e665207b3d84564befbaf9e8b69e6b9.png)
3.	使用<mereg>标签减少视图层次结构
    备注:因为所有的activity视图的根节点都是FragmentLayout,因此我们的自定义布局也是FragmentLayout时候
    可    以用merge替换,当使用Include或者ViewStub标签从外部导入xml结构时,可以将导入的xml用merge作为根节
    点表  示,这样当被嵌入父级结构中后可以很好的将它所包含的子集融合到父级结构中,而不会出现冗余的节点。 
    只能作为 xml 布局的根元素
4.	减少不必要的背景设置,避免过度绘制, 比如父控件设置了背景色,子控件完全将父控件给覆盖的情况下,那么父
    控件就没有必要设置背景。

二十九、Android 列表优化

1.	使用RecyclerView替代传统的ListView和GridView
2.	复用getView中的相关View,避免重复获取实例导致卡顿
3.	列表滑动过程中不进行UI绘制,图片加载

扩展:RecyclerView 源码,缓存分析

 RecyclerView使用了强大的分工操作,显示、排版由LayoutManager处理,数据显示由adapter处理,item上下左右
 动态加入绘制由ItemDecoration处理,item的动画由ItemAnimator处理。   recyclerView缓存是由内部类Recycler维
 护,其中一级缓存有mAttachedScrap,里面放的都是当前屏幕正在显示的viewHolder的缓存,二级缓存是
 mCachedViews,里面放的都是移出到屏幕外的viewHolder缓存,mRecyclerPool是recyclerView的三级缓存,一般
 用在RecyclerView嵌套RecyclerView的时候用得到,比如外层的RecyclerView的item中有RecyclerView,那么里面
 的 RecyclerView通过共用外层的RecyclerView的RecyclerPool来减少里面RecyclerView的ViewHolder创建。

三十、Android 网络优化

1 Gzip压缩:HTTP协议上的Gzip编码是一种用来改进WEB应用程序性能的技术,用来减少传输数据量大小。即可以 
  减少流量消耗、减少传输时间 
2 IP直连与HttpDns:
    ① DNS解析的失败率占联网失败中很大一种,而且首次域名解析一般需要几百毫秒。针对此,我们可以不用域名,
    才 用IP直连省去 DNS 解析过程,节省这部分时间。
    ② HttpDns:HttpDNS基于Http协议的域名解析,替代了基于DNS协议向运营商Local DNS发起解析请求的传统方
    式,可以避免Local DNS造成的域名劫持和跨网访问问题,解决域名解析异常带来的困扰。 
3 图片处理:
    ① 通过webP格式可以使图片大小减少
    ② 使用缩略图
    ③ 图片上传时使用分片传输,并设置重传机制 
4 协议层的优化:Http1.1版本引入了“持久连接”,多个请求被复用,无需重建TCP连接,而TCP连接在移动互联网的 
  场景下成本很高,节省了时间与资源; 
5 合并多个请求:合并网络请求,减少请求次数。对于一些接口类如统计,无需实时上报,将统计信息保存在本地,然
  后根据策略统一上传。这样头信息仅需上传一次,减少了流量也节省了资源。 
6 网络缓存:对服务端返回数据进行缓存,设定有效时间,有效时间之内不走网络请求,减少流量消耗。

三十一、Android 卡顿优化

1.	字符串拼接尽量使用StringBuffer和StringBuilder代替String 
2.	onCreate中减少不必要元素的初始化以及耗时操作,加快Activity启动速度 
3.	避免在View的draw,measure,layout执行耗时以及耗内存操作,尤其draw方法中 
4.	严格遵守ANR规避原则,避免在UI线程中做耗时操作,譬如多次数据库操作,HTTP请求等 
5.	必要的耗时操作放到子线程执行,执行结束后抛到主线程更新UI,子线程使用线程池管理,减少线程创建,内存消
     耗

三十二、Android 包体积优化

1.	资源图片采用Webp格式 
2.	较大的资源图片可以使用AS自带能力压缩,也可以借助tingPng压缩 
3.	不同颜色的多个相同图标,只添加一个纯色图片资源,实际使用时用tint着色 
4.	打包时加入混淆 
5.	远程库依赖时尽量有限compileOnly、

三十三、View 和 SurfaceView 的区别

1.	View需要在UI线程对画面进行刷新,而SurfaceView可在子线程进行页面的刷新
2.	View适用于主动更新的情况,而SurfaceView适用于被动更新,如频繁刷新,这是因为如果使用View频繁刷新会阻
    塞主线程,导致界面卡顿
3.	SurfaceView在底层已实现双缓冲机制,而View没有,因此SurfaceView更适用于需要频繁刷新、刷新时数据处理
    量很大的页面(如视频播放界面)

三十四、View 的绘制流程以及分发机制

绘制过程;
        1 measure 过程
            作用;测量view的宽高
        2 layout 过程
            作用;通过确定view 四个顶点坐标 从而确定view位置
        3 draw 过程
            作用;将view 绘制到屏幕上

   分发机制;本质就是对MotionEvent 事件的分发过程,即当一个MotionEvent
             产生后,系统需要将这个点击事件传递到一个具体的view上
   点击顺序;Activity(Window) – ViewGroup – Vew 
   主要方法;dispatchTouchEvent 事件的分发传递,返回值boolean 类型 受当前
             的onTouchEvent 和下级的 dispatchTouchEvent 影响
             onInterceptTouchEvent 对事件进行拦截,只在viewGroup 中有,一旦
             拦截,则执行viewGroup中的OnTouchEvent ,在viewGroup中处理事件
             onTouchEvent 事件处理

三十五、OnCreate 中获取view宽高的几种方式

 当Activity创建时,需要获取某个View的宽高,然后进行相应的操作,但是我们在onCreate,onStart中获取View的大
 小,获取到的值都是0,只是由于View的绘制工程还未完成,和在onCreate中弹出Dialog或者PopupWindow会报一
 个 Activity not running原理类似。 重写Activity中的onWindowFocusChanged,当Activity获取到焦点的时候View已
 经绘制完成,也能获取到View的准确宽高了。同样的Dialog和PopupWindow也可以在这里弹出,需要注意的是这个
 方 法会调用多次,当hasFocus为true时,才可进行相应的操作
 第一种:

在这里插入图片描述
第二种:
在这里插入图片描述
第三种:
在这里插入图片描述
第四种:
在这里插入图片描述
第五种:
在这里插入图片描述

三十六、如何保证线程的安全

(1)	使用Synchronized关键字修饰
(2)	使用Object类的wait和notify方法协作。
(3)	使用ThreadLocal实现,其是一种线程安全的数据容器,实现原理就是会在不同的线程保持单独存储变量
private ThreadLocal<String> sName = new ThreadLocal<>();
public  void testThreadLocal(){
    new Thread(new Runnable() {
       @Override
       public void run() {
          sName.set("name1");
       }
     }).start();
     new Thread(new Runnable() {
       @Override
       public void run() {
            sName.set("name2");
          }
      }).start();
}

三十七、属性动画原理

  android动画除了补间动画还有帧动画,现在又多了一种选择就是属性动画。

   即 ValueAnimator 跟 ObjectAnnimator

   原理:在一定时间间隔内,通过不断对值进行改变,并不断将该值赋给对象的属性,从而实现该对象在该属性上的动
        画效果。

补间动画还有帧动画缺点

1.	作用对象局限:即补间动画 只能够作用在视图View上,


2.	没有改变View的属性,补间动画只是改变了View的视觉效果,而不会真正去改变View的属性。如,将屏幕左上角的按钮 通过补间动画移动到屏幕的右下角,点击当前按钮位置(屏幕右下角)是没有效果的,因为实际上按钮还是停留在屏幕左上角,补间动画只是将这个按钮绘制到屏幕右下角,改变了视觉效果而已。

3.	动画效果单一 ,补间动画只能实现平移、旋转、缩放 & 透明度这些简单的动画需求,一旦遇到相对复杂的动画效果,即超出了上述4种动画效果,那么补间动画则 无法实现。

三十八、Glide原理与Picasso

Glide 原理的核心是为 bitmap 维护一个对象池。对象池的主要目的是通过减少大对象的分配以重用 来提高性能
Glide 的总体设计图。整个库分为 RequestManager(请求管理器),Engine(数据获取引擎)、 Fetcher(数据获取器)、
MemoryCache(内存缓存)、DiskLRUCache、Transformation(图片处理)、 Encoder(本 地缓存存储)、Registry(图片
类型及解析器配置)、Target(目标) 等模块。 简单的讲就是 Glide 收到加载及显示资源的任务,创建 Request 并将它
交给 RequestManager, Request 启动 Engine 去数据源获取资源(通过 Fetcher ),获取到后 Transformation 处理
后交给 Target。 

问;Glide 内存设计以及优点

  ① Glide 的内存缓存有个 active 的设计 从内存缓存中取数据时,不像一般的实现用 get,而是用 remove,再将这
    个缓存数据放到一个 value 为软引用的 activeResources map 中,并计数引用数,在图片加载完成后进行判断,
    如果引用计数为空 则回收掉。
  ② 内存缓存更小图片 Glide 以 url、view_width、view_height、屏幕的分辨率等做为联合 key,将处理后的图片缓存
    在内 存缓存中,而不是原始图片以节省大小
  ③ 与 Activity/Fragment 生命周期一致,支持 trimMemory
  ④ 图片默认使用默认 RGB_565 而不是 ARGB_888,虽然清晰度差些,但图片更小,也可配置到 ARGB_888。 其
    他:Glide 可以通过 signature 或不使用本地缓存支持 url 过

问: Glide与Picasso 区别

(1)Glide比Picasso加载速度快,但Glide比Picasso需要更大的空间来缓存;

(2)Glide加载图像及磁盘缓存的方式都优于Picasso,且Glide更有利于减少OutOfMemoryError的发生;

(3)Glide可以加载Gif动图,Picasso不可以加载动图

(4)Picasso加载的图片比Glide加载的图片平滑(可忽略不计)

(5) Picasso所能实现的功能,Glide都能做,只是所需的设置不同。但是Picasso体积比起Glide小太多如果项目中网络
    请求本身用的就是okhttp或者retrofit(本质还是okhttp),那么建议用Picasso,体积会小很多。Glide的好处是大型的
    图  片流,比如gif、Video,如果做美拍这种视频类应用,建议使用。

三十九、Okhttp , Retrofit 原理

Okhttp原理:

 主要是通过 Diapatcher 不断从 RequestQueue 中取出请求(Call),根据是否已缓存调用 Cache 或 Network 这两 
 类数据获取接口之一,
 从内存缓存或是服务器取得请求的数据。 该引擎有同步和异步请求,同步请求通过 Call.execute()直接返 回当前的 
 Response,
 而异步请求会把当前的请求 Call.enqueue 添加(AsyncCall)到请求队列中,并通过回调(Callback) 的方式来获取
 最后结果

Retrofit 原理:

App应用程序通过Retrofit请求网络,实际上是使用Retrofit接口层封装请求参数,Header、URL等信息,之后由
OKHttp完成后续的请求,在服务器返回数据之后,OKHttp将原始的结果交给Retrofit,最后根据用户的需求对结果进
行解析。

Retrofit 动态代理原理:

1.首先,通过method把它转换成ServiceMethod。
2.然后,通过serviceMethod,args获取到okHttpCall对象。
3.最后,再把okHttpCall进一步封装并返回Call对象。

Okhttp:负责网络请求

支持Http1、Http2、Quic以及WebSocket;
连接池复用底层TCP(Socket),减少请求延时;
无缝的支持GZIP减少数据流量;
缓存响应数据减少重复的网络请求;
请求失败自动重试主机的其他ip,自动重定向;
利用响应缓存来避免重复的网络请求.即便是网络出现问题时,okhttp依然起作用.它将从常见的链接问题当中回复.如果
你的服务器有多个IP地址,当地一个失败时,okhttp会自动尝试连接其他的地址

Retrofit:负责接口的封装

Retrofit其实就是一个基于okhttp网络请求框架的封装。比如配置网络,处理数据
其目的就是为了解耦,注解方式简化接口的定义 
网上一般都推荐RxJava+Retrofit+OkHttp框架,Retrofit负责请求的数据和请求的结果,使用接口的方式呈现,OkHttp
负责请求的过程,RxJava负责异步,各种线程之间的切换,用起来非常便利。

扩展:RxJava 常用方法:

    just:将同种数据源组合放到被观察者上面
    from:将类似数组、集合的数据源放到被观察者上面
    map:将一种数据源,转化成另外一种
    flatmap:将一种数据源,转化成另外一种数据,并且被转化的数据是乱序排列的
    concat:合并相同类型的被观察者到一个被观察者身上,有点类似集合、数组拼接数据。

四十、LeakCanary的原理分析(内存泄漏工具)

LeakCanary是Square开源的,用于检测活动的内存泄漏。
众所周知LeakCanary的使用时在application中调用LeakCanary.install(this)即可
即注册了application的生命周期的回调,用于监听activity的生命周期的回调在activity

调用onDestroy的时候,将该activity的引用进行watch。 this.retainedKeys.add(key);retainedKeys是一个Set集合。
在一个活动传给RefWatcher时会创建一个唯一的对应这个活动,该密钥存入一个集合retainedKeys中。也就是说,所
有我们想要观测的activity对应的retainedKeys唯一键都会被放入集合中。(如果为null,表示回收了;如果不为null,
表示该activity出现了内存泄漏)然后调用ensureGoneAsync。

在调用onDestroy时,会将activity放入ReferenceQueue中;经removeWeaklyReachableReferences方法会将gc后依
旧不为null的引用从retainedKeys中remove掉(此时retainedKeys中全是经过gc后为null的)。最后将
ReferenceQueue中的value值对应retainedKeys找出不为null的value,这些即为内存泄漏的引用。

利用HeapAnalyzer对dump的内存情况进行分析并进一步确认,若确定发生泄漏,则利用DisplayLeakService发送通知。

四十一、EventBus 原理

 EventBus是一款在android开发中使用的发布/订阅事件的总线框架,基于观察者模式,将事件的接收者和发送者分  
  开,基本包括了如下几个步骤:

1  注册事件的订阅方法:该步骤主要是找到订阅者下面有哪些方法需要被订阅

2  订阅操作:将需要被订阅的方法放到类似HashMap的数据结构中存储起来,方便后面发送事件和取消注册等资源的释
   放的时候使用

3  发送事件:该步骤首先遍历事件队列,然后从队列中取出事件,并且将事件从队列中移除,拿到事件后,判断事件处
   于的什么线程,如果是非UI线程,则需要Handler去处理,如果是的话,则直接通过反射调用被观察的方法。

4  反注册:该步骤就没什么好说的,主要是上面存储到HashMap中的被订阅的方法的移除,释放在内存中的资源。

四十二、广播内部实现机制

1 自定义广播接受者BroadcastReceiver,并重写onReciver()方法
2 通过binder机制像AMS进行注册
3 广播发送者通过binder机制像AMS发送广播
4 AMS 查找符合相应条件(IntentFilter/Permission等)的BroadcastRecevice,将
  广播发送到BroadcastRecevice相应的循环队列中
5 消息循环执行拿到此广播,回调BroadcastRecevice 的onReceive()方法

注:Activity Manager Service 贯穿四大组件的核心服务,负责四大组件的启动,切换,调度,以及应用程序的管理调度

四十三、GreenDao 与 Room 对比

使用GreenDao,使用GreenDao时会自动生成DaoMaster,DaoSession,XXXEntityDao三个类。
Room定义实体类需要注意必须手动编写Getter和Setter。主键值必须为非空,如果主键设置为String等,需要添加注
解@NonNull 常用注解 @Insert,@Delete,@Update,@Query, @RawQuery 等等

GreenDao 和Room 在基本操作方面,Room提供的接口比较少,对SQL命令的依赖度高,有点是可以在编译的时候
检查SQL命令,但是在项目中有多个实体类的时候,会出现很多重复性代码。GreenDao提供的接口丰富,支持SQL
操作,但是无法检测SQL命令,通过泛型话操作,可以减少重复性代码。
   
Room支持RxJava,LiveData两个方式的响应式编程。Room 作为Jetpack的组件之一,与Jetpack的其他
组件如LiveData,paging有着密切的关系。
GreenDao支持Rxjava

四十四、加密算法

1 MD5加密

场景:1.验证密码:只要算法不变,就能和服务器上的MD5匹配;
      2 文件完整性的校验:当下载一个文件时,服务器返回的信息包括这个文件的md5,在本地下载完毕时进行md5加
        密,将两个md5值进行比较,如果一致则说明文件完整没有丢包现象
        
压缩性:任意长度的数据,算出的MD5值长度都是固定的;
容易计算:从原数据计算出MD5值很容易;
抗修改性:对原数据进行任何改动,哪怕只修改1个字节,所得到的MD5值都有很大的区别;
强抗碰撞:已知原数据和其MD5值,想找到一个具有相同MD5值的数据(及伪造数据)是非常困难的;不可
         逆:MD5   理论上是不可逆的(但是现在已经可以暴力破解了)。
         
2 RSA加密

说明: RSA加密算法是一种非对称加密算法,非对称加密算法需要两个密钥:公共密钥和私有密钥。公钥和私钥是配
      对的,  用公钥加密的数据只有配对的私钥才能解密。RSA对加密数据的长度有限制,一般为密钥的长度值-11,
      要加密较长的数据,可以采用数据截取的方法,分段加密。
场景:
     文件或数据在本地使用公钥或私钥加密,加密后的数据传送到服务器,服务器使用同一套密钥中的私钥或者公钥进行解密。
3 AES加密

说明:AES加密是一种高级加密标准,是一种区块加密标准。它是一个对称密码,就是说加密和解密用相同的密钥。
     WPA/WPA2经常用的加密方式就是AES加密算法。

四十五、MVC与MVP以及MVVM 区别

 MVP:为了解决MVC耦合过重的问题,MVP的核心思想就是提供一个Presenter将视图逻辑I和业务逻辑相分离,达到
      解耦的目的。 作为一种新的模式,MVP与MVC有着一个重大的区别:在MVP中View并不直接使用Model,它们之
      间的通信是通过Presenter (MVC中的Controller)来进行的,所有的交互都发生在Presenter内部,而在MVC中
      View会直接从Model中读取数据而不是通过 Controller。在MVC里,View是可以直接访问Model的!从而,View里
      会包含Model信息,不可避免的还要包括一些业务逻辑。 在MVC模型里,更关注的Model的改变,而同时有多个对
      Model的不同显示,即View。所以,在MVC模型里,Model不依赖于View,但是View是依赖于Model的。不仅如
      此,因为有一些业务逻辑在View里实现了,导致要更改View也是比较困难的,至少那些业务逻辑是无法重用的。
      虽然 MVC 中的 View 的确“可以”访问 Model,但是我们不建议在 View 中依赖 Model,而是要求尽可能把所有业
      务逻辑都放在 Controller 中处理,而 View 只和 Controller 交互。
      
MVVM:使用ViewModel代替Presenter,实现数据与View的双向绑定,这套框架最早使用的data-binding将数据绑定
      到xml里,这么做在大规模应用的时候是不行的,不过数据绑定是  一个很有用的概念,后续Google又推出了
      ViewModel组件与LiveData组件。ViewModel组件规范了ViewModel所处的地位、生命周期、生产方式以及一个
      Activity下多个Fragment共享View  Model数据的问题。LiveData组件则提供了在Java层面View订阅ViewModel数
      据源的实现方案。
      
       MVVM : Model + View + ViewModel。解耦更彻底,如果说之前是藕断丝连的话,现在就是一刀两断。

       ViewModel:关联层,将Model和View进行绑定,只做和业务逻辑相关的工作,不涉及任何和UI相关的操作,不持
       有控件引用,不更新UI。

       ViewModel 类旨在以注重生命周期的方式存储和管理界面相关的数据。ViewModel 类让数据可在发生屏幕旋转等
       配置更改后继续留存。DataBinding数据绑定库是一种支持库,借助该库,您可以使用声明性格式(而非程序化
       地)将布局中的界面组件绑定到应用中的数据源。
        
       ViewModel的优势在于生命周期和数据持久化,那么它就适用于Activity和Fragment,其次就是异步回调,不会
       造成内存泄漏,再次就是对View层和Model层进行隔离,是两者不存在耦合性,因此你可以知道ViewModel在整
       个MVVM框架中的重要性了。

       View只做和UI相关的工作,不涉及任何业务逻辑,不涉及操作数据,不处理数据。UI和数据严格的分开。

问:LiveData 作用

数据变化感知,也就是说如果我一个页面中对一个TextView进行多次赋值的话,可以通过LiveData来操作,只需要在
值改变的时候进行设置就好了,可以简化页面上的代码。

问:MVP 引起的内存泄漏原因以及解决办法

  当用户按返回键时,页面Activity退出,如果Model在子线程上执行耗时任务,还没有结束,Model持有Presenter的
  引用,Presenter持有Activity的引用。那么这个Activity对象就没有办法被回收。
  在Activity的onDestroy方法中,通过Presenter间接将Model中的耗时任务取消,然后将Presenter和Model置空。
  因为onDestroy方法不一定立即执行,有可能主线程有大量的任务要处理,来不及执行onDestroy()方法。在此期
  间,如果GC触发,Activity对象还是无法被回收。而通过弱引用,将Activity对象转换为弱可达对象,GC一旦运行,
  不 管内存  是否充足,都会回收弱可达对象。从而解决内存泄漏。

四十六、Android 组件化概念

  是将一个APP分成多个module,每个module都是一个组件,也可以是一个基础库供组件依赖,开发中可以单独调试部分组件,组件中不需要相互依赖但是可以相互调用,最终发布的时候所有组件以lib的形式被主APP工程依赖打包成一个apk。
  
  优势:  1 组件化将通用模块独立出来,统一管理,以提高复用,将页面拆分为粒度更小的组件,组件内部出了包含UI实现,还可以包含数据层和逻辑层
         2 每个组件度可以独立编译、加快编译速度、独立打包。
         3 每个工程内部的修改,不会影响其他工程。
         4 业务库工程可以快速拆分出来,集成到其他App中。
         5 迭代频繁的业务模块采用组件方式,业务线研发可以互不干扰、提升协作效率,并控制产品质量,加强稳定性。
         6 并行开发,团队成员只关注自己的开发的小模块,降低耦合性,后期维护方便等。

四十七、Android 与 JS 交互

   Android 与 JS 通 过WebView 互相调用方法

  一  Android 调用JS 代码
      1 Android与JS通过WebView互相调用方法
      2 通过WebView的evaluateJavascript()
  二  JS 调用 Android 代码
      1 通过WebView的addJavascriptInterface()进行对象映射
      2 通过 WebViewClient 的shouldOverrideUrlLoading ()方法回调拦截 url
      3 通过 WebChromeClient 的onJsAlert()、onJsConfirm()、onJsPrompt()方法回调拦截JS对话框alert()、confirm()、prompt() 消息 

四十八、SharedPreference能跨进程数据共享吗?

SharedPreference无法跨进程,虽然打开sp时 有跨进程模式,但是由于没有提供通知另一个进程的更新内存数据的
方法会导致两边数  据不一致,官方建议还是使用contentProvider。

四十九、SharedPreference的commit和apply的区别

    1 apply无返回值,而commit会返回一个boolean类型值来表示数据是否被成功持久化存储。
    2 apply立刻将更改提交到内存中SharedPreferences,但是会启动对磁盘的异步提交;commit是同步的提交到磁
      盘。这样一来,在有多个Editor需要提交时,它们会等待正在处理的commit完成后再操作,效率较低。

五十、Intent 传递对象 序列化

有两种方式 :

   1 Serializable 方式 要传递的类实现 Serializable 接口(JAVA 自带)(sei瑞来斯薄)Serializable是序列化的意思,表
     示将一个对象转换成可存储或者可传输的状态。序列化后的对象可以在网络上进行传输,也可以存储到本地。序列
     化 方法很简单,只需要让一个类去实现Serializable这个接口就可以了 接收: 这里调用了getSerializableExtra()
     方法 获取通过参数传递过来的序列化对象, 

  2 Parcelable 方式 要传递的类实现 Parcelable 接口 (Android 专用)
    Parcelable方式的实现原理是将一个完整的对象进行分解,而分解后的每一部分都是Intent所支持的数据类型,这样
    就实现传递对象的功能了

两者区别:

   两者最大的区别在于存储媒介的不同 ,Serializable 使用 I/O 读写存储在硬盘上。而 Parcelable 是直接 在内存中读
   写。很明显,内存的读写速度通常大于 IO 读写,所以在 Android 中传递数据优先选择 Parcelable。 Serializable 会
   使用反射,序列化和反序列化过程需要大量 I/O 操作,序列化过程中会创建很多临时对象,容易触发垃圾回
   收;Parcelable 自已实现封送和解封(marshalled &unmarshalled)操作,不需要用反射,数据也存放在内存中,
   效率要快很多。

意义;

   序列化机制允许将实现了序列化接口的 Java 对象转换成字节序列,这些字节序列可以保存在磁盘中,或通过网络
   传输,以达到以后恢复成原来的java对象。序列化机制使得对象可以脱离程序的运行而独立存在。

五十一、Intent 传输数据的大小有限制么?

Intent 中的 Bundle 是使用 Binder 机制进行数据传送的, 数据会写到内核空间, Binder 缓冲区域;
Binder 的缓冲区是有大小限制的, 有些 ROM 是 1M, 有些 ROM 是 2M;
这个限制定义在 frameworks/native/libs/binder/processState.cpp 类中, 如果超过这个限制, 系统就会报错;

因为 Binder 本身就是为了进程间频繁-灵活的通信所设计的, 并不是为了拷贝大量数据;
如果非 ipc 就很简单了, static 变量, eventBus 之类的都可以;
如果是 ipc, 一定要一次性传大文件, 可以用 file 或者 socket;

五十二、ContentProvider如何实现数据共享

当一个应用程序要把自己的数据暴露给其他程序时,可以通过ContentProvider来实现。
其他应用可以通过ContenrResolver来操作ContentProvider暴露的数据。

定义自己的ContentProvider类,该类需要继承Android系统提供的ContentProvider基类。

在Manifest.xml 文件中注册ContentProvider,(四大组件的使用都需要在Manifest文件中注册) 注册时需要绑定一个
URL

调用Activity的ContentResolver获取ContentResolver对象
调用ContentResolver的insert(),delete(),update(),query()进行增删改查。
一般来说,ContentProvider是单例模式,也就是说,当多个应用程序通过ContentResolver来操作ContentProvider
提供的数据时,ContentResolver调用的数据操作将会委托给同一个ContentResolver。

总结

未完待续  如有不足的地方,欢迎指教,
  • 16
    点赞
  • 85
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
面试是评估一个人技能和能力的重要环节。在Android面试中,除了基础知识的掌握外,还需要注意交流和语言组织能力。基础知识的牢固掌握是面试的基础,但有些人可能在实际表达中存在困难。因此,在准备面试时,可以使用思维导图等工具来梳理知识点,帮助自己更好地组织语言。从简到繁、从外到内的方式可以帮助我们更好地展开回答。生成思维导图后,可以按照这个体系一条条地进行讲解,并在每个点上进行延伸,这样可以延长自己的说话时间,提高通过面试的概率。\[1\]\[2\] 在Android中,进程之间是不能互相访问的,因此需要使用多进程通信技术。Android中特有的多进程通信技术是Binder。通常情况下,一个应用是一个进程,但是Android中一个应用也可以有多个进程,可以通过指定android:process属性来给四大组件指定进程。其中以“:”开头的为私有进程,不以“:”开头的为共有进程。\[3\] 在Android面试中,除了基础知识和多进程通信,还有其他重要的话题,如Android架构、UI设计、性能优化等。准备面试时,建议全面了解这些话题,并能够清晰地表达自己的观点和经验。 #### 引用[.reference_title] - *1* *2* *3* [android面试实用](https://blog.csdn.net/wang_yong_hui_1234/article/details/105579401)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值