1、Android系统构架:
android的系统架构和其操作系统一样,采用了分层的架构,共分为四层:
- Android应用层
- Android应用框架层
- Android系统运行库层
- Linux内核层
######1.应用层 Android会同一系列核心应用程序包一起发布,该应用程序包包括email客户端,SMS短消息程序,日历,地图,浏览器,联系人管理程序等。它们一般都是使用Java进行编写。
######2.应用框架层 开发人员也可以完全访问核心应用程序所使用的API框架。该应用程序的架构设计简化了组件的重用;任何一个应用程序都可以发布它的功能块并且任何其它的应用程序都可以使用其所发布的功能块(不过得遵循框架的安全性限制)。同样,该应用程序重用机制也使用户可以方便的替换程序组件。 隐藏在每个应用后面的是一系列的服务和系统,其中包括:
- 视图(Views),可以用来构建应用程序,它包括列表(lists),网格(grids),文本框(textBoxes),按钮(buttons),甚至可嵌入的web浏览器。
- 内容提供器(ContentProviders)使得应用程序可以访问另一个应用程序的数据(如联系人数据库),或者共享它们自己的数据
- 资源管理器(ResourceManager)提供非代码资源的访问,如本地字符串,图形,和布局文件(layoutfiles)。
- 通知管理器(NotificationManager)使得应用程序可以在状态栏中显示自定义的提示信息。
- 活动管理器(ActivityManager)用来管理应用程序生命周期并提供常用的导航回退功能。
######3.系统运行库层
程序库 Android包含一些C/C++库,这些库能被Android系统中不同的组件使用。它们通过Android应用程序框架为开发者提供服务。以下是一些核心库:
系统C库——一个从BSD继承来的标准C系统函数库(libc),它是专门为基于embeddedlinux的设备定制的。 媒体库——基于PacketVideoopencore;该库支持多种常用的音频、视频格式回放和录制,同时支持静态图像文件。编码格式包括MPEG4,H.264,MP3,AAC,AMR,JPG,PNG。 SurfaceManager——对显示子系统的管理,并且为多个应用程序提供了2D和3D图层的无缝融合。 LibWebCore——一个最新的web浏览器引擎用,支持Android浏览器和一个可嵌入的web视图。 SGL——底层的2D图形引擎 3Dlibraries——基于OpenGLES1.0APIs实现;该库可以使用硬件3D加速(如果可用)或者使用高度优化的3D软加速。 FreeType——位图(bitmap)和矢量(vector)字体显示。 SQLite——一个对于所有应用程序可用,功能强劲的轻型关系型数据库引擎。
- Android运行库 Android包括了一个核心库,该核心库提供了JAVA编程语言核心库的大多数功能。 每一个Android应用程序都在它自己的进程中运行,都拥有一个独立的Dalvik虚拟机实例。Dalvik被设计成一个设备可以同时高效地运行多个虚拟系统。Dalvik虚拟机执行(.dex)的Dalvik可执行文件,该格式文件针对小内存使用做了优化。同时虚拟机是基于寄存器的,所有的类都经由JAVA编译器编译,然后通过SDK中的“dx”工具转化成.dex格式由虚拟机执行。 Dalvik虚拟机依赖于linux内核的一些功能,比如线程机制和底层内存管理机制。
######4.Linux内核层 Android的核心系统服务依赖于Linux2.6内核,如安全性,内存管理,进程管理,网络协议栈和驱动模型。Linux内核也同时作为硬件和软件栈之间的抽象层。
2、如何进行进程保活
1、提升进程优先级,降低进程被杀死的概率。 2、拉活已经被杀死的进程。
3、如何提升优先级?
1、监控手机锁屏事件 2、锁屏是启动一个像素的Activity,在用户解锁的时候,将Activity销毁掉,前台Activity会将进程变成前台进程,且优先级最高
4、如何拉活已经杀死的进程
1、利用广播拉活Activity 2、手机去监听系统广播:如开机广播,锁屏解锁广播等。
5、什么是序列化
1、序列化就是将对象转化为二进制流,便于存储和传输
6、Serializable和Parcelable的区别
1、Serilizable是java实现的一套序列化方法,会触发频繁的IO操作,效率较低,适合将对象存储到磁盘上的情况。 2、Parcelable是Android提供的序列化方法。Parcelable将序列化后的字节流写入到一个共享内存中,其他对象可以从该共享内存中读出字节流,并反序列化成对象,效率较高,适合对象间和进程间传递信息。
7、64k问题的产生原因和如何解决?
1、产生原因:Dex文件中class、method的索引使用short类型,因此如果方法、类的总数超过了2字节的short-65535就会出问题。 2、解决办法:使用Google的Multidex
8、Android中Intent传递数据的大小限制?如何解决该问题?
1、大小限制大约是1MB:超过该限制可能导致 OOM。 2、解决办法
- 进程内:EventBus、文件缓存
- 进程间:通过ContentProvider进行进程间数据共享和传递。 总结: 不要通过 Intent 在 Android 基础组件之间传递大数据(binder transaction 缓存为1MB)
9、APK的打包流程分为几部分?
1、资源打包 2、代码打包
10、点击应用图标是如何启动APP的?
1、点击应用图标后会去启动应用的LauncherActivity 2、如果LauncherActivity所在进程没有创建,就会创建新进程(以Socket形式通知Zygote进程去fork新进程)。 3、整体的流程就是Activity的启动流程。
11、怎么去除重复代码?
1、对于Activity或者Fragment,抽取基类BaseActivity,BaseFragment,在基类中抽取一些所有子类都需要的方法,比如:initView、initListener、initData、initStatusBarColors、startActivity、showToast、checkNetConnected等方法。 2、对于xml布局文件,在多个页面中同时出现的、可以重复利用的,就单独抽出来,用include引入,比如:标题栏,下一步按钮,等等一些可以抽取出来的公共部分。 3、对于资源文件的引用,比如文字的text、文字大小textSize、文字颜色textColor,全部采用引用,不要全部写死到布局中,对于文字text一律写到string中、对于文字大小,一律写入dimens中,对于文字颜色,一律写入到color中,然后统一引入xml布局文件中。
12、ListView 中图片错位的问题是如何产生的?
1、如果只是简单的展示list中的数据,而没用convertView的复用机制和异步操作,就不会产生图片错位的问题;重用但没有异步,也不会出现这个问题,但程序会很卡。 2、图片错位就是因为convertView复用,同时异步加载图片造成的。
13、屏幕适配的处理技巧都有哪些?
1、布局尽量使用相对布局与线性布局 2、根据不同的分辨率的手机,提供不同的资源 3、限制横竖屏切换。
14、动态加载布局有3种方法
// 第一种
View layoutView = View.inflate(this , R.layout.activity_main , null) ;
// 第2种
View layoutView = LayoutInflater.from(this).inflate(R.layout.activity_main , null) ;
// 第3种
View layoutView = LayoutInflater.from(this).inflate(R.layout.activity_main , null , false) ;
第一种方式内部调用的是第二种方式, 第二种方式内部调用的是第三种方式。 第三种方式分析: 参数一:要加载的布局文件。 参数二:父布局容器。 参数三:false表示不把布局文件添加到容器中,true表示把布局文件添加到容器中。 如果参数三设置了false,但添加了下面的代码,表示和true一样,都可以把布局添加到容器中。
15、Recycleview和ListView的区别
1、ListView:只能在垂直方向滑动。 RecyclerView:支持水平方向滑动,垂直方向滑动,多行多列瀑布流的方式等。 2、ListView:有几个默认的Adapter,分别是ArrayAdapter、CursorAdapter和SimpleCursorAdapter。 RecyclerView:Adapter需要自己实现。 3、ListView:拥有子Item的监听函数:AdapterView.OnItemClickListener。 RecyclerView:需要自己实现接口,来实现子Item的点击事件,虽然比较麻烦,但是扩展性好 4、ListView:并不强制使用ViewHolder,如果要使用,则需要自己定义,如果不使用,ListView每次 getView()的时候都需要去findViewById,会造成性能下降,滑动卡顿等,所以推荐使用 ViewHolder。 RecyclerView:必须使用ViewHolder。 5、ListView:两级缓存。RecyclerView:四级缓存。
ListView 两级缓存
1. mActiveViews 用于屏幕内ItemView快速重用
2. mScrapViews 用于缓存离开屏幕的ItemView
RecyclerView 四级缓存
1. mChangeScrap与 mAttachedScrap 用于屏幕内ItemView快速重用
2. mCachedViews 默认上限为2,即缓存屏幕外2个ItemView
3. mViewCacheExtension 用户自定义,一般不使用
4. RecycledViewPool 默认上限为5
缓存对象不同,RecyclerView缓存的是ViewHolder,ListView缓存的是View。
16、ListView图片加载错乱的原理和解决方案
1、ListView图片加载错乱是因为异步请求和convertView复用造成的。 2、解决方案: 对imageView设置tag,并预设一张图片。
17、动态权限适配方案,权限组的概念
1、对于低于Android 6.0版本的Android系统,没有动态权限的申请问题,动态权限的申请流程对于低于Android 6.0版本的android系统也不再适用。所以适配方案,首先要考虑低于M版本的Android系统,因此对于低于Android 6.0版本的Android系统,在检查权限时,直接返回true;对于高于M版本的系统,可以将动态权限申请进行一次封装。
18、Android系统为什么会设计ContentProvider?
1、Android设计ContentProvider主要是为了实现跨进程通信。 为了应用程序之间交换数据,Android提供了ContentProvider,ContentProvider是不同应用程序之间进行数据交换的标准API,当一个应用程序需要把自己的数据暴露给其他应用程序使用时,该应用程序就可以通过提供ContentProvider来实现,其他应用程序就可以通过ContentProvider来操作ContentProvider暴露出来的数据。
19、下拉状态栏是不是影响activity的生命周期
1、不会影响Activity的生命周期。
20、如果在onStop的时候做了网络请求,onResume的时候怎么恢复?
1、stop的时候被暂停,onStart的时候重新检测恢复请求即可。 2、如果是恢复页面请求后的页面数据,分两种,一、Activity已经销毁,那么使用saveInstanceState存储数据,onRestoreInstanceState()恢复数据;二,Activity没有销毁,那就不需要恢复。
21、Bitmap 使用时候注意什么?
1、要使用合适的图片规格(bitmap类型) 2、降低采样率 3、复用内存。 4、及时回收 5、压缩图片 6、尽量不要使用setImageBitmap或setImageResource或BitmapFactory.decodeResource来设置一张大图,因为这些函数在完成decode后,最终都会通过java层调用createBitmap来完成,需要消耗更多的内存,可以通过BitmapFactory.decodeStream方法,创建出一个Bitmap,再将其设置成ImageView的source。
22、Bitmap的recycler()
1、Android有自己的垃圾回收机制,如果只使用了少量的图片,回收与否关系不大。可是若有大量的bitmap需要垃圾回收,那么垃圾回收的次数过于频繁,会造成系统资源负荷。所以还是自己recycler()比较好。 一定要注意ImageView的图片来源,然后进行相应的recycler。
23、Android中开启摄像头的主要步骤
1、一共有两种方式可以使用Android中的摄像头 (1)、调用Android系统现有的摄像头程序。 (2)、直接使用Android系统提供的摄像头API。
24、ViewPager使用细节,如何设置成每次只初始化当前的Fragment,其他的不初始化?
1、每次只初始化一个页面的时候,就要注意了,需要采用懒加载的方式,因为在页面进入前台的时候,是会调用setUserVisiableHint()这个方法的,通过这个方法,我们可以获得当前页面是否对用户可见,并在对用户可见的时候进行初始化,这时还需要注意一点,setUserVisiableHint()这个方法的调用并不保证View等需要的东西是否已经初始化成功,所以还需要再判断一下。
25、点击事件被拦截,但是想传到下面的View,如何操作?
1、在父控件中加入请求父控件不拦截子控件的触摸事件,自定义重写子控件的dispatchTouchView();
2、就可以阻止父控件对子控件点击事件的拦截,可以为子控件单独设置点击事件的响应
26、Activity之间的通信方式
1、Intent传值。 2、借助类的静态变量。 3、借助全局变量/Application。 4、借助外部工具(SharePreference,SQLLite,File,Android剪切板)。 5、借助Service。
27、四大组件是什么
1、Activity、Service、Content Provider、BroadCast Receiver
28、BroadCast Receiver:
1、动态注册的广播,生命周期仅限于当前注册的Activity,离开Activity时,一定要取消注册,否则会抛出异常,但是该异常不会造成APP崩溃,但会造成内存泄漏。离开Activity后,即使没有取消注册,该广播也不会再接收消息。 2、静态注册广播,相比较动态注册,即使退出app,广播依然可用,通过标签进行静态注册广播,会在执行完onReceive方法后任意时间段内销毁,所以,我们不需要手动进行取消注册。
29、ContentProvider讲解
1、ContentProvider是一个抽象类,如果我们需要开发自己的内容提供者我们就需要继承这个类并复写其方法,需要实现的主要方法如下: public boolean onCreate() 在创建ContentProvider时使用 public Cursor query() 用于查询指定uri的数据返回一个Cursor public Uri insert() 用于向指定uri的ContentProvider中添加数据 public int delete() 用于删除指定uri的数据 public int update() 用户更新指定uri的数据 public String getType() 用于返回指定的Uri中的数据MIME类型 数据访问的方法insert,delete和update可能被多个线程同时调用,此时必须是线程安全的
30、Activity上有Dialog的时候按Home键时的生命周期
1、无论页面上是否有Dialog,按下Home键时都会回调:onPause-->onStop
31、两个Activity 之间跳转时必然会执行的是哪几个方法?
1、当从ActivityA跳转到ActivityB时,A会调用onPause(),然后B调用onCreate(),onStart(),onResume(),然后B此时覆盖在A只是,A调用onStop()方法。 2、如果B是透明窗口,或对话框样式,就不会调用A的onStop()方法。 3、如果B已经存在在Activity栈中,B就不会调用onCreate()方法。
32、Activity的四种启动模式对比
1、Activity四种启动模式:standard、singleTop、singleTask、singleInstance 2、standard:标准模式,这也是系统默认模式。每次启动Activity都会创建一个实例,不管这个实例是否已存在。 3、singleTop:栈顶复用模式。在这种模式下,如果新的Activity已经存在于任务栈的栈顶,那么此Activity的实例不会被重新创建,同时它的onNewIntent方法会被回调。注意:这个Activity的onCreate、onStart方法并不会被系统调用,因为它没有发生改变;如果新的Activity的实例已存在,但并不在栈顶,那么会重新创建新的Activity实例。 4、singleTask:栈内复用模式。这是一种单实例模式,如果任务栈内存在该Activity的实例,那么就将这个实例之上的所有Activity出栈,将这个新的Activity实例置于栈顶。 5、singleInstance:单实例模式。这是一种加强版的singleTask,此模式的Activity只能单独运行在一个任务栈中。
33、Activity状态保存于恢复
1、onSaveInstanceState()方法用来在Activity被强制销毁之前保存数据,onSaveInstanceState()方法携带一个Bundle类型的参数,Bundle提供了一系列方法用于保存数据。 2、onRestoreInstanceState()方法用来取的之前再onSaveInstanceState()方法中保存的值。
34、fragment各种情况下的生命周期
**onAttach()**在Fragment 和 Activity 建立关联是调用(Activity 传递到此方法内) onCreateView() 当Fragment 创建视图时调用 **onActivityCreated()**在相关联的 Activity 的 onCreate() 方法已返回时调用。 **onDestroyView()**当Fragment中的视图被移除时调用 onDetach() 当Fragment 和 Activity 取消关联时调用。
35、如何实现Fragment的滑动?
1、ViewPager嵌套Fragment即可实现滑动。
36、service和activity怎么进行数据交互?
1、binder+回调(listener) 主要思路:Activity将实例传入Service,同时利用回调更新UI。 2、binder+Handler 主要思路:Service持有Activity的Handler对象,Service通过往该Handler send message的方式,达到通信的目的。 3、广播(推荐LocalBroadCastManager) 主要思路:利用系统的LocalBroadCastManager、Service send message,Activity receive message; 4、开源组件(EventBus,otto) 5、AIDL
37、Service的开启方式
1、采用start启动方式 步骤:定义一个类继承Service 在Manifest.xml中配置Service 使用Context的startService(Intent)方法启动Service 不再使用时,使用stopService(Intent)方法停止Service 特点: 一旦服务开启跟调用者(开启者)就没有关系了。 开启者退出,开启者挂了,服务还在后台长期的运行。 开启者不能调用服务里的方法。
2、使用bind启动方式 步骤:定义一个类继承Service 在Manifest.xml中配置Service 使用Context的bindService(Intent,ServiceConnection,int)方法启动该Service 不再使用时,调用unbindService(ServiceConnection)方法停止服务。
38、广播的分类
1、普通广播 2、系统广播 3、有序广播 4、粘性广播 5、App应用内广播
39、本地广播和全局广播有什么差别?
1、全局广播:BroadcastReceiver是针对应用间、应用与系统间、应用内部进行通信的一种方式 2、本地广播:LocalBroadcaseReceiver仅在自身应用内发送接收广播,也就是只有自己的应用能收到,数据更加安全,广播只在这个程序里,而且效率更高
40、AlertDialog,popupWindow,Activity区别
1、AlertDialog:用来提示用户一些信息,用起来也比较简单,设置标题内容和按钮即可。 2、popupWindow:就是一个悬浮在Activity上的窗口,可以用来展示任意布局。 3、activity:Activity是Android四大组件之一,可以用于显示View。Activity是一个与用户交互的模块。 4、AlertDialog是非阻塞式对话框,AlertDialog弹出时,后台还可以做事情;popupWindow是阻塞式对话框,popupWindow弹出时,程序会等待,在popupWindow退出前,程序一致处于等待,只有当我们调用了dismiss方法后,popupWindow退出,程序才会向下执行。
41、LinearLayout、RelativeLayout、FrameLayout的特性及对比,并介绍使用场景。
1、RelativeLayout会让子View调用两次onMeasure,LinearLayout在有weight时,也会调用子View两次onMeasure。 2、RelativeLayout的子View如果高度和RelativeLayout不同,则会引发效率问题,当子View很复杂的时候,这个问题会更加严重。如果可以尽量使用padding代替margin。 3、在不影响层级深度的情况下,使用LinearLayout和FrameLayout而不是RelativeLayout。 4、能用两层LinearLayout,尽量用一个RelativeLayout,在时间上此时RelativeLayout消耗更小。
42、invalidate和postInvalidate的区别及使用
1、Android中实现View的更新有两组方法,一组是invalidate,另外一组是postInvalidate,其中前者是在UI线程自身中使用,而后者是在非UI线程中使用。 2、invalidate是在handler中使用,postInvalidate可以直接在子线程中调用更新View。
43、ActivityThread,AMS,WMS的工作原理
1、AMS:统一调度所有应用程序的Activity。 2、WMS:控制所有的Window的显示与隐藏以及要显示的位置。 3、ActivityThread:Android应用主线程(UI线程)。
44、View刷新机制
1、View更新一共有两个方法:invalidate和postInvalidate,其中前者是在UI线程中使用,而后者是在非UI线程中使用。
45、自定义控件原理
1、View绘制的基本上是由measure(),layout(),draw()三个方法完成的。
46、为什么不能在子线程更新UI?
1、Android的UI访问是没有加锁的,多线程可以同时访问更新操作同一个UI控件。也就是说访问UI的时候,android系统中的控件都不是线程安全的,这将导致在多线程模式下,当多个线程共同访问更新操作同一个控件时容易发生不可控的错误,而这是致命的。所以Android中规定只能在UI线程中更新UI,这相当于从另一个角度给Android的UI访问加了锁,伪锁。
47、ANR产生的原因是什么?
1、主线程执行了耗时操作,比如数据操作或网络请求。 2、其他进程占用CPU导致本进程得不到CPU时间片,比如其他进程的频繁读写操作可能会导致这个问题。
48、什么情况导致oom?
OOM可能的原因:
1、数据库的cursor没有及时关闭 2、构造Adapter没有使用缓存convertView 3、RegisterReceiver()和unRegisterReceiver()没有成对出现 4、未关闭InputStream、OutputStream 5、Bitmap使用后未调用recycle() 6、static等关键字 7、非静态内部类持有外部类的引用,context泄漏
49、有什么解决方法可以避免OOM?
1、针对数据库cursor没有关闭的情况,如果查询数据量少是不会造成内存溢出的,但是数据量太大容易造成OOM,所以用完Cursor后应该手动调用close方法关闭cursor。 2、针对adapter没有复用convertView的情况,除了要在getView方法里边对convertView进行判断后复用,还应该使用ViewHolder类来保存通过findViewById获取的子控件地址值。 3、在Activity中注册了广播,但在Activity退出时没有取消注册的话可能会造成内存溢出,需要手动在相应的位置进行反注册。 4、不关闭输入输出流的话就相当于在内存和硬盘一直存在着连接占用着资源,当其他操作需要资源时,就会造成内存溢出。 5、位图在Android中占用的内存是很大的,使用后如不及时回收的话会占用大量空间,所以针对位图一般有以下几种处理:
- 及时的调用recycle方法来手动回收;
- 设置采样率,有时候我们不需要把图片完全显示出来,这时候就要按照比例来进行缩放,在我们得到采样率后就可以将图片缩小后再进行加载,节省大量内存;
一般而言,回收bitmap内存可以用到以下代码
if(bitmap != null && !bitmap.isRecycled()){
bitmap.recycle();
bitmap = null;
}
System.gc();
bitmap.recycle()方法用于回收该bitmap所占用的内存,接着将bitmap置空,最后,别忘了用System.gc()调用一下系统的垃圾回收器。
6、使用软引用 应该尽量避免static成员变量引用资源耗费过多实例,比如Context Context尽量使用Application Context,因为Application Context生命周期比较长,引用它不会出现内存泄漏的问题 使用WeakReference代替强引用。 7、非静态内部类,上下文泄漏。
50、内存泄漏和内存溢出区别?
1、内存泄漏的堆积就会导致内存溢出。 2、内存泄漏是指申请内存后无法释放已申请的内存空间,内存溢出是没有足够的内存供申请者使用。
51、LruCache默认缓存大小
1、手机内存的1/8
52、广播是否可以请求网络?
1、子线程可以,主线程超过10s引起anr
53、广播引起anr的时间限制是多少?
1、10s
54、Android线程有没有上限?
1、在Android中,线程的数量是有上限的。Android系统为每个应用程序分配了一定数量的线程资源,这个数量是有限的。具体的上限取决于设备的硬件性能和系统配置。 2、一般来说,Android系统会为每个应用程序分配一定数量的线程资源,但是如果应用程序创建过多的线程,可能会导致系统资源不足,从而影响应用程序的性能和稳定性。 3、因此,在开发Android应用程序时,应该合理管理和控制线程的数量,避免创建过多的线程。
55、线程池有没有上限?
1、有,跟内存挂钩。
56、ListView重用的是什么?
1、ListView重用的是View
57、Volley中使用的设计模式?
1、策略模式 2、模板方法模式
58、OkHttp 中使用的设计模式?
1、建造者模式 2、工厂模式 3、责任链模式 4、单例模式 5、观察者模式
59、Retrofit中使用的设计模式?
1、适配器模式 2、工厂方式模式 3、装饰模式 4、外观模式
60、Eventbus中使用的设计模式?
1、观察者模式
61、Rxjava中使用的设计模式?
1、适配器模式 2、观察者模式 3、 装饰者模式
62、简述 Java 最常见的两种查找算法:
1、线性查找:这个,对数组进行遍历操作 2、二分法查找:这个算法必须要数组是有序的前提下,取数组中间的值进行比较,如果小于则取左边的数值进行查找(否则向右查找),再获取左边的数值中间的值进行比较,以此类推,直到找到对应的值为止。
63、最常用的三种的图片格式(jpg、png、webp)分别有什么区别
1、jpg:有损压缩格式,体积比较小,不支持透明通道 2、png:无损压缩格式,体积比较大,支持透明通道 3、webp:Google 发布的图片格式,压缩率比 jpg 更好,jpg 和 webp 压缩出来的图片大小相差无几,但是 webp 的图片质量比 jpg 要高
64、Glide 和 Picasso 框架的区别:
1、 Glide 功能比 Picasso 要更加强大(Glide 支持加载 Gif 和视频缩略图,而 Picasso 不支持) 2、Glide 的库体积比 Picasso 要大(Glide 600KB,Picasso 100KB) 3、 Glide 的本地缓存比 Picasso 要大(Glide 缓存的是合适尺寸的图片,而 Picasso 只缓存了原图) 4、Glide 比 Picasso 加载中更省内存(Glide 是直接加载本地缓存的图片,而 Picasso 要经过尺寸压缩才会进行加载)
65、混合开发的方式?说出它们的优缺点和各自使用场景
1、H5、React Native、Weex、 Flutter、小程序等
2、H5的优点
1、h5开发速度快,一端开发多端运行
2、如果APP用户常见页面频换,如(淘宝首页各种不同活动),那么用H5,维护起来更容易。
3、如果app中出现大量文字且格式比较丰富(比如加粗、字体大小,图文展示)等用H5比较方便
4、迭代版本时,不需要打包便可以发布(实时更新、快速迭代),与云端实现实时数据交互。
3、APP原生的优点
1、原生的响应速度快
2、对于有无网络操作时,譬如离线操作基本选用原生开发
3、需要调用系统硬件的功能(摄像头、方向传感器、重力传感器、拨号、GPS、语音、短信、蓝牙等功能)
4、在无网络或者若网的情况下体验好。
4、ReactNative的优点
//优点
1、垮平台开发 。相比原生的ios 和 android app各自维护一套业务逻辑大同小异的代码,React Native 只需要同一套javascript 代码就可以运行于ios 和 android 两个平台,在开发、测试和维护的成本上要低很多。
2、快速编译 。相比Xcode中原生代码需要较长时间的编译,React Native 采用热加载的即时编译方式,使得App UI的开发体验得到改善,几乎做到了和网页开发一样随时更改,随时可见的效果。
3、快速发布。React Native 可以通过 JSBundle 即时更新 App。相比原来冗长的审核和上传过程,发布和测试新功能的效率大幅提高。
4、渲染和布局更高效 React Native 可以直接套用网页开发中的css布局机制。脱了 autolayout 和 frame 布局中繁琐的数学计算,更加直接简便。
5、简单易学。 相比于 iOS 和 Android 的一整套复杂的知识体系,React Native 从本质上来讲就是状态机,对于开发者来讲理解不难,且实际操作可谓入门容易、上手轻松。如果是前端开发者,那么对于 Javascript 本来就有相应了解,用 React Native 开发手机应用更是水到渠成。
//缺点
1、动画性能。React Native 在动画效率和性能的支持还存在一些问题,性能上不如原生Api。
2、第三方依赖。React Native 严重依赖于 Facebook 的维护。苹果在 iOS 上每次技术的更新、政策的改变都会让原来使用了 React Native 代码库受到影响,等待 Facebook 和社区的修复会妨碍 App 的更新和用户体验。前段时间,百度和开发者们弃用React Native 而迫使的 Facebook 修改开发者权限(License)事件,证明了开发依赖于第三方的风险确实存在。
3、逻辑上的额外开销。直到今天, React Native 依然只是0.52版本,仅仅支持简单的 UI 制作,其不成熟的 API 连复杂的动画都难以实现,更别提 iOS 的底层优化和兼容操作。同时因为操作系统和设备的不同,React Native 得分别进行针对性处理,这对代码库的维护又是一个挑战。
4、调试的困难。对于原生的 iOS 和 Android App 引入 React Native,会增加整个代码库的复杂度,在深入底层原生代码进行 debug 时也是困难重重,可以说是在开发和维护上的成本都有所增加。
5、不能完全屏蔽原生平台。 就目前的React Native 官方文档中可以发现仍有部分组件和API都区分了Android 和 IOS 版本,即便是共享组件,也会有平台独享的函数。也就是说仍不能真正实现严格意义上的“一套代码,多平台使用”。另外,因为仍对ios 和android的原生细节有所依赖,所以需要开发者若不了解原生平台,可能会遇到一些坑。
5、Weex的优点
1、Weex 更加轻量
在Native端,两者的最大的区别可能就是在对JSBundle是否分包。React Native官方只允许将React Native基础JS库和业务JS一起打成一个JS bundle,没有提供分包的功能,所以如果想节约流量就必须制作分包打包工具。而Weex默认打的JS bundle只包含业务JS代码,体积小很多,基础JS库包含在Weex SDK中,这一点Weex与Facebook的React Native和微软的Cordova相比,Weex更加轻量,体积小巧。
由于 Weex 采用了 Vue 作为上层框架,相较于 React 更加轻量,Vue 的官网宣传就是非常轻量,体积小巧,语法简单。
2、跨平台 支持web端
Weex从出生那天起,就被给予了一统三端的厚望。React Native可以支持iOS、Android, 需要自己扩展去支持web. 而Weex可以支持iOS、Android、web
React Native宣称Learn once, write anywhere,而Weex宣称Write Once, Run Everywhere. Weex不需要像RN那样不同平台写不同的代码(虽然很多可以重用), 写一份代码 iOS、Android、 H5都能够适用
3、资料少,社区活跃度不够, 成熟的组件少,坑相对较多
6、Flutter的优点
//优点
1、性能强大,流畅
Flutter对比weex和react native相比,性能的强大是有目共睹的。基于dom树渲染原生组件,很难与直接在原生视图上绘图比肩性能,Google作为一个轮子大厂,直接在两个平台上重写了各自的UIKit,对接到平台底层,减少UI层的多层转换,UI性能可以比肩原生,这个优势在滑动和播放动画时尤为明显。
2、路由设计优秀
Flutter的路由传值非常方便,push一个路由,会返回一个Future对象(也就是Promise对象),使用await或者.then就可以在目标路由pop,回到当前页面时收到返回值。这个反向传值的设计基本是甩了微信小程序一条街了。弹出dialog等一些操作也是使用的路由方法,几乎不用担心出现传值困难
3、单例模式
Flutter支持单例模式,单例模式的实现也非常简单。单例模式很好的解决了一些问题。相比之下,js的单例则并不是一个真正的单例,或者说不是一个简单的单例,这也是受限于js所运行的环境。单例模式并不总是合理的,容易被滥用。但是在App的初期开发中,往往一个容易实现的单例可以帮助我们快速完成一些逻辑的搭建。
4、优秀的动画设计
Flutter的动画简单到不可思议,动画对象会根据屏幕刷新率每秒产生很多个(一般是60个)浮点数,只需要将一个组件属性通过补间(Tween)关联到动画对象上,Flutter会确保在每一帧渲染正确的组件,从而形成连贯的动画。这种十分暴力的操作在Flutter上却看不到明显的卡顿,这也是Flutter的一个魔力所在。相比之下其他跨平台框架几乎不能设计动画……往往会遭遇非常严重的性能问题。
5、UI跨平台稳定
Google直接在两个平台上在底层重写了UIKit,不依赖于Css等外部解释器,几乎不存在UI表达不理想,渲染不正常的情况,可以获得非常稳定的UI表达效果。Css换个浏览器就有不同的表现,基于Css的跨平台框架很难获得稳定的UI表现。
6、可选静态的语言,语言特性优秀
Dart是一个静态语言,这也是相对于js的一个优势。Dart可以被编译成js,但是看起来更像java。静态语言可以避免错误,获得更多的编辑器提示词,极大的增加可维护性。很多js库也已经用ts重写了,Vue3.0的底层也将全部使用ts编写,静态语言的优势不言而喻。
//缺点
1、假装跨平台,躲不开原生代码
2、组合而不是继承的思路
3、Widget的类型难以选择
4、糟糕的UI控件API
7、小程序的优点
//小程序的优点:
1、不用安装,即开即用,用完zhi就走。省流量,省dao安装时间,不占用zhuan桌面。
2、对于小程拥有者来说,开发成本更低,他们可以更多财力,人力,精力放在如何运营好产品,做好内容本身。
3、对于用户来说,相较于各种APP,微信小程序UI和操作流程会更统一。这也会降低用户的使用难度。
4、对于小程序拥有者来说,相较于原生APP,推广更容易更简单,更省成本。
//小程序的缺点:
1、太轻,因为太轻所以很多APP上面的功能在小程序上面是无法展现的,小程序只能展现一部分的核心功能。目前随着小程序技术的不断成熟,小程序的功能也在不断完善。
2、小程序功能不够全面,解决不了复杂的行业问题,做不到多功能,虽然与微信对接但是附近用户量少,无法有效的获取用户,对比于行业系统,小程序更适用于前端展示。
66、常用数据结构简介
1、数据结构(也称为集合类)大致分类如下: 2、Map图接口(包含HashMap和TreeMap); 3、Collection集合接口(包含List接口和Set接口):
- List线性表接口(包含ArrayList和LinkedList);
- Set集合接口(包含HashSet和TreeSet);
67、Android动画介绍
1、Tween(补间动画):这种实现方式可以使视图组件移动、放大、缩小以及透明度的变化(假的,点击效果没有变) 2、Frame(帧动画):通过顺序的播放图片来实现,类似电影 3、属性动画:补间动画只是显示位置的改变,点击事件仍在原处,而属性动画控件移动后事件相应就在就在移动后的本身处理。
68、JVM 内存管理指的是什么?
1、内存分配; 2、垃圾回收;
69、JVM 的运行时数据区?
1、JVM在运行过程中就会把它管理的内存划分成若干不同的数据区域。 2、线程私有:程序计数器、本地方法栈、虚拟机栈; 3、线程共享:堆、方法区;
70、程序计数器
1、指向当前线程正在执行的字节码指令的地址(行号);
71、为什么需要程序计数器?
1、Java 是多线程的,意味着线程切换; 2、确保多线程情况下的程序正常执行;
72、虚拟机栈
1、存储当前线程运行方法所需的数据、指令、返回地址;
73、 直接内存
1、 非虚拟机运行时数据区的部分
74、什么时候回收?
1、垃圾收集器在对堆进行回收前,第一件事就是要确定这些对象之中哪些还“存活”着,哪些已经“死去”,对于这些已经“死去”的对象我们需要进行回收。判断对象是否存活的算法: (1)引用计数算法 (2)可达性分析算法
75、回收方法区
1、在堆中,尤其是在新生代中,一次垃圾回收一般可以回收 70% ~ 95% 的空间,而永久代的垃圾收集效率远低于此。 2、永久代垃圾回收主要两部分内容:废弃的常量和无用的类。
76、垃圾回收算法
1、标记 —— 清除算法 直接标记清除就可。
两个不足:
1、效率不高
2、空间会产生大量碎片
2、复制算法 把空间分成两块,每次只对其中一块进行 GC。当这块内存使用完时,就将还存活的对象复制到另一块上面。
解决前一种方法的不足,但是会造成空间利用率低下。因为大多数新生
代对象都不会熬过第一次 GC。所以没必要 1 : 1 划分空间。可以分一块
较大的 Eden 空间和两块较小的 Survivor 空间,每次使用 Eden 空间和其中一块 Survivor。 当回收时,将 Eden 和 Survivor 中还存活的对象一次性复制到另一块 Survivor 上,最后清理 Eden 和 Survivor 空间。大小比例一般是 8 : 1 : 1,每次浪费 10% 的 Survivor 空间。但是这里有一个问题就是如果存活的大于 10% 怎么办?这里采用一种分配担保策略:多出来的对象直接进入老年代。
3、标记-整理算法 不同于针对新生代的复制算法,针对老年代的特点,创建该算法。主要是把存活对象移到内存的一端。
4、分代回收 根据存活对象划分几块内存区,一般是分为新生代和老年代。然后根据各个年代的特点制定相应的回收算法。
1、新生代
每次垃圾回收都有大量对象死去,只有少量存活,选用复制算法比较合理。
2、老年代
老年代中对象存活率较高、没有额外的空间分配对它进行担保。所以必须使用 标记 —— 清除 或者 标记 —— 整理算法回收。
77、Java 线程调度
1、协同式线程调度 线程执行时间由线程自身控制,实现简单,切换线程自己可知,所以基本没有线程同步问题。坏处是执行时间不可控,容易阻塞。 2、抢占式线程调度 每个线程由系统来分配执行时间。
78、虚拟机类加载机制
1、虚拟机把描述类的数据从 Class 文件加载到内存,并对数据进行校验、装换解析和初始化,最终形成可以被虚拟机直接使用的 Java 类型。 2、在 Java 语言中,类型的加载、连接和初始化过程都是在程序运行期间完成的。
79、实体类中使用set/get与直接调用变量相比有什么区别,有哪些好处?
1、set/get比较灵活 2、set/get安全性(只读或只写的权限) 3、get方法是给私有成员变量取值的,set方法是赋值的,而成员变量的值只能在本类中被使用
80、线程的sleep()和wait()有什么区别,举两个简单的使用场景。
1、sleep 方法:是 Thread 类的静态方法,当前线程将睡眠 n 毫秒,线程进入阻塞状态。当睡眠时间到了,会接触阻塞,进入可运行状态,等待 CPU 的到来。睡眠不释放锁(如果有的话) 2、wait 方法:是 Object 的方法,必须与 synchronized 关键字一起使用,线程进入阻塞状态,当 notify 或者 notifyall 被调用后,会接触阻塞。但是,只有重新占用互斥锁之后才会进入可运行状态。睡眠时,释放互斥锁。
| 特点/方法 | 如何唤醒? | 如何进入可运行状态? | 是否释放锁? |
|---|---|---|---|
| sleep() | 睡眠时间结束则接触阻塞 | 接触阻塞后进入可运行状态 | 不释放锁 |
| wait() | 被notify或notifyAll调用后接触阻塞 | 只有重新占用互斥锁之后才会进入可运行状态 | 释放互斥锁 |
81、字节流和字符流使用场景的区别
1、InputStream 和OutputStream,两个是为字节流设计的,主要用来处理字节或二进制对象, 2、Reader和 Writer.两个是为字符流(一个字符占两个字节)设计的,主要用来处理字符或字符串. 3、字符流处理的单元为2个字节的Unicode字符,操作字符、字符数组或字符串, 4、字节流处理单元为1个字节,操作字节和字节数组。 5、所以字符流是由Java虚拟机将字节转化为2个字节的Unicode字符为单位的字符而成的,所以它对多国语言支持性比较好! 6、如果是音频文件、图片、歌曲,就用字节流好点, 7、如果是关系到中文(文本)的,用字符流好点
82、请尽可能详细描述自定义view的步骤
1、自定义View的属性 编写attr.xml文件 2、在layout布局文件中引用,同时引用命名空间 3、在View的构造方法中获得我们自定义的属性 ,在自定义控件中进行读取(构造方法拿到attr.xml文件值) 4、重写onMesure 5、重写onLayout 6、重写onDraw
83、开发过程中如何快速的定位造成UI卡顿的原因?
1、Android只有主线程才能更新UI。如果界面1秒钟刷新少于60次,即FPS小于60,用户就会产生卡顿感觉。
1.主线程做了阻塞 UI 的耗时操作; 2.同一时刻动画执行多次导致 GPU 和 CPU 过度绘制; 3.View 过度绘制导致 GPU 和 CPU 过度绘制; 4.频繁地进行布局绘制、文本计算等操作导致 View 需要重新渲染; 5.频繁的对象创建和销毁; 6.过度复杂的业务逻辑,耗时函数。
84、导致频繁GC有两个原因:
1、内存抖动(Memory Churn), 即大量的对象被创建又在短时间内马上被释放. 2、瞬间产生大量的对象会严重占用Young Generation的内存区域, 当达到阀值, 剩余空间不够的时候, 也会触发GC. 即使每次分配的对象需要占用很少的内存,但是他们叠加在一起会增加Heap的压力, 从而触发更多的GC.
85、UI卡顿检测的两种方法
1、首先,我们看看是否是我们的界面是否过度绘制 手机开发者选项打开,我们看看里面有个显示边界布局的选项,打开它
2、卡顿如果是发生在代码部分,那么怎么定位 blog.csdn.net/qq_39037047… 1.通过打印日志来查看卡顿;dispatchMessage()是在Looper.loop()里调用; 2.如果“>>>>> Dispatching to”信号发生了,我们就假定发生了卡顿(这里我们设定1秒钟的卡顿判定阈值),并且发送一个延迟1秒钟的任务,这个任务就用于在子线程打印出造成卡顿的UI线程里的堆栈信息。而如果没有卡顿,即在1秒钟之内我们检测到了“<<<<< Finished to”信号,就会移除这个延迟1秒的任务。
86、UI优化方案:
1、Overdraw的检测 手机里面就能打开测试,设置 -> 开发者选项 -> 调试GPU过度绘制 -> 显示GPU过度绘制,从字面意思就可以看到,它是查看绘制过程中过度绘制严重程度。 (1)布局程度的调整,如果在布局中重复设置 background,就会出现过度绘制,例如,在设置列表listview背景为白色,background=“white”,但是想让条目也为白色,设置background为白色,这样就造成了过度绘制 (2)使用中设置background,例如在设置imageview的时候先设置一个预显示background,然后再设置 (3)自定义View中有些图片要叠加使用,就会造成过度绘制,使用clipRect能解决这类型问题。 2、Hierarchy Viewer 减少不必要的嵌套 3、Android标签的优化 a. 如果在一个项目中需要用到相同的布局设计,可以通过 标签来重用layout代码, 这样可以多次引用一个布局片段而不用重复的复制、粘贴。通过include标签也可以覆写一些属性的值, b. 标签在UI的结构优化中起着非常重要的作用,它可以删减多余的层级,优化UI。多用于替换FrameLayout或者当一个布局包含另一个时,标签消除视图层次结构中多余的视图组。例如你的主布局文件是垂直布局,引入了一个垂直布局的include,这是如果include布局使用的LinearLayout就没意义了,使用的话反而减慢你的UI表现。这时可以使用标签优化。 c. 标签最大的优点是当你需要时才会加载,使用他并不会影响UI初始化时的性能。各种不常用的布局想进度条、显示错误消息等可以使用标签,以减少内存使用量,加快渲染速度。是一个不可见的,大小为0的View。
87、怎么实现跨进程访问?
1、startActivity sendBroadcast startService Messenger AIDL Provider 2、startActivity, sendBroadcast,startService 使用都比较简单。通常使用在传递简单消息,通知另外一个进程。异步并且得不到反馈。AIDL是android推荐使用的,但是客户端调用稍微复杂,不利于接口封装(客户端必须先bind,然后才可以调用)。Messenger实际上是在AIDL的基础上进行了封装。可以更好的结合handler来使用,相对较为简单,但是也存在不利于接口封装的问题。
88、为什么会有事件分发机制
1、安卓上面的View是树形结构的,View可能会重叠在一起,当点击的地方有多个View可以响应的时候,这个点击事件应该给谁呢?为了解决这个问题,就有了事件分发机制。 2、PhoneWindow:是抽象类Window的实现类,抽象类Window是所有视图最顶层的容器,包括View视图的外观和行为都归Window管。 DecorView:PhoneWindow的内部类,通过DecorView传递信息给下面的View,下面的View也通过DecorView返回消息给PhoneWindow。
89、事件分发流程:
1、Activity——>PhoneWindow——>DecorView——>ViewGroup——>...——>View 2、事件分发机制使用的是责任链设计模式,从Activity如果传到最下层的View都没有组件处理该事件,该事件会依次回传到Activity。
90、Android事件三个重要方法:
91、四个触摸事件
1、Down,move,up,cancel
92、View中为什么会有dispatchTouchEvent方法,它存在的意义是什么?
1、我们知道View可以注册很多监听事件(下文有详细),比如,触摸事件,单击事件,长按事件等,而且view也有自己的onTouchEvent方法,那么这么多事件应该由谁来调度管理呢?这就是是View中dispatchTouchEvent方法存在的意义。
93、View中为什么没有onInterceptTouchEvent事件拦截方法?
1、View最为事件传递的最末端,要么消费掉事件,要么不处理进行回传,根本没必要进行事件拦截
94、ViewGroup 和 View 同时注册了事件监听器(onClick等),哪个会执行?
1、事件优先给View,会被View消费掉,ViewGroup 不会响应。
95、当俩个或多个View重叠时,事件该如何分配?
1、当 View 重叠时,一般会分配给显示在最上面的 View,也就是后加载的View。
96、dispatchTouchEvent每次都会被调用吗?
1、是的,onInterceptTouchEvent则不会。
97、一旦有事件传递给view,view的onTouchEvent一定会被调用吗?
1、View没有onInterceptTouchEvent方法,一旦有事件传递给它,他的onTouchEvent就一定会被调用。
98、ViewGroup 默认拦截事件吗?
1、ViewGroup默认不拦截任何事件;看源码可以知道ViewGroup的onInterceptTouchEvent方法中只有一行代码:return false;
99、事件分为几个步骤?
1、down事件开头,up事件结尾,中间可能会有数目不定的move事件。
100、点击事件的传递过程?
1、Activity-Window-View。 从上到下依次传递,当然了如果你最低的那个view onTouchEvent返回false 那就说明他不想处理 那就再往上抛,都不处理的话最终就还是让Activity自己处理了。
101、如果某个view 处理事件的时候 没有消耗down事件 会有什么结果?
1、假如一个view,在down事件来的时候 他的onTouchEvent返回false, 那么这个down事件 所属的事件序列 就是他后续的move 和up 都不会给他处理了,全部都给他的父view处理。
102、如果view 不消耗move或者up事件 会有什么结果?
1、那这个事件所属的事件序列就消失了,父view也不会处理的,最终都给activity 去处理了。
103、enable是否影响view的onTouchEvent返回值?
1、不影响,只要clickable和longClickable有一个为真,那么onTouchEvent就返回true。
104、滑动冲突解决方式?
1、外部拦截法 —— 即点击事件先经过父容器的拦截处理,如果父容器需要此事件就拦截,不需要就不拦截,需要重写父容器的onInterceptTouchEvent方法;在onInterceptTouchEvent方法中,首先ACTION_DOWN这个事件,父容器必须返回false,即不拦截ACTION_DOWN事件,因为一旦父容器拦截了ACTION_DOWN,那么后续的ACTION_MOVE/ACTION_UP都会直接交给父容器处理;其次是ACTION_MOVE,根据需求来决定是否要拦截;最后ACTION_UP事件,这里必须要返回false,在这里没有多大意义。 2、内部拦截法 —— 所有事件都传递给子元素,如果子元素需要就消耗掉,不需要就交给父元素处理,需要子元素配合requestDisallowInterceptTouchEvent方法才能正常工作;父元素需要默认拦截除ACTION_DOWN以外的事件,这样子元素调用parent.requestDisallowInterceptTouchEvent(false)方法时,父元素才能继续拦截需要的事件。(ACTION_DOWN事件不受requestDisallowInterceptTouchEvent方法影响,所以一旦父元素拦截ACTION_DOWN事件,那么所有元素都无法传递到子元素去)。
105、equestDisallowInterceptTouchEvent 可以在子元素中干扰父元素的事件分发吗?如果可以,是全部都可以干扰吗?
1、答:肯定可以,但是down事件干扰不了。