文章目录
他面试题知识点
数据库相关面试题
-
左链接和右链接的区别
左连接where只影向右表,右连接where只影响左表。select * from tbl1 Left Join tbl2 where tbl1.ID = tbl2.ID
左连接后的检索结果是显示tbl1的所有数据和tbl2中满足where 条件的数据。简言之 Left Join影响到的是右边的表select * from tbl1 Right Join tbl2 where tbl1.ID = tbl2.ID
检索结果是tbl2的所有数据和tbl1中满足where 条件的数据。简言之 Right Join影响到的是左边的表 -
SQL语句中对表或者字段取别名有什么好处?
(1)区别同名列的名称
(2)非法的表达式合法化
(3)按照你的意愿显示列的名称 -
索引的种类。
主键索引、普通索引、唯一索引和全文索引
数据库调优教程(五) 索引的作用和索引的种类 -
主键和唯一键的区别,回答是否能为空,是否能做外键
主键是不能重复且不能为空,唯一键是不能重复但可以为空的;一张表可以有多个唯一键但是只能有一个主键;主键可以做外键,唯一键也可以 -
如何做SQLite升级?
(1)让用户卸载老版本再安装新的程序; 缺点:可操作性低,软件卸载会造成老数据的丢失
(2)软件自行更新数据库结构。 可取:作为开发者必须妥善处理数据库的升级问题 -
Statement与PreparedStatement的区别,什么是SQL注入,如何防止SQL注入
Statement与PreparedStatement的区别:
关系:PreparedStatement继承自Statement,都是接口
区别:PreparedStatement可以使用占位符,是预编译的,表示预编译的 SQL 语句的对象,批处理比Statement效率高什么是SQL注入:
所谓SQL注入式攻击,就是攻击者把SQL命令插入到Web表单的输入域或页面请求的查询字符串,欺骗服务器执行恶意的SQL命令。在某些表单中,用户输入的内容直接用来构造(或者影响)动态SQL命令,或作为存储过程的输入参数,这类表单特别容易受到SQL注入式攻击如何防止SQL注入:
⑴ 对于动态构造SQL查询的场合,可以使用下面的技术:第一:替换单引号,即把所有单独出现的单引号改成两个单引号,防止攻击者修改SQL命令的含义 第二:删除用户输入内容中的所有连字符,防止攻击者构造出类如“SELECT * from Users WHERE login= ’mas’ —— AND password=’’”之类的查询,因为这类查询的后半部分已经被注释掉,不再有效,攻击者只要知道一个合法的用户登录名称,根本不需要知道用户的密码就可以顺利获得访问权限 第三:对于用来执行查询的数据库帐户,限制其权限。用不同的用户帐户执行查询、插入、更新、删除操作。由于隔离了不同帐户可执行的操作,因而也就防止了原本用于执行SELECT命令的地方却被用于执行INSERT、UPDATE或DELETE命令
(2)用存储过程来执行所有的查询。SQL参数的传递方式将防止攻击者利用单引号和连字符实施攻击。此外,它还使得数据库权限可以限制到只允许特定的存储过程执行,所有的用户输入必须遵从被调用的存储过程的安全上下文,这样就很难再发生注入式攻击了
(3)限制表单或查询字符串输入的长度。如果用户的登录名字最多只有10个字符,那么不要认可表单中输入的10个以上的字符,这将大大增加攻击者在SQL命令中插入有害代码的难度
(4)检查用户输入的合法性,确信输入的内容只包含合法的数据。数据检查应当在客户端和服务器端都执行——之所以要执行服务器端验证,是为了弥补客户端验证机制脆弱的安全性
(5)将用户登录名称、密码等数据加密保存。加密用户输入的数据,然后再将它与数据库中保存的数据比较,这相当于对用户输入的数据进行了“消毒”处理,用户输入的数据不再对数据库有任何特殊的意义,从而也就防止了攻击者注入SQL命令
(6) 检查提取数据的查询所返回的记录数量。如果程序只要求返回一个记录,但实际返回的记录却超过一行,那就当作出错处理 -
Tomcat,Apache,JBoss的区别?
Apache:http服务器(web服务器),类似IIS可以用于建立虚拟站点,编译处理静态页面;可以支持SSL技术,支持多个虚拟主机等功能;Tomcat:servlet容器,用于解析jsp,servlet的Servlet容器,是高效,轻量级的容器;缺点: 不支持EJB,只能用于java应用;
Jboss:应用服务器,运行EJB的J2EE应用服务器,遵循J2EE规范,能够提供更多平台的支持和更多集成功能,如数据库连接,JCA等;其对servlet的支持是通过集成其他servlet容器来实现的,如tomcat和jetty;
WebView
-
混合开发,RN,weex,H5,小程序(做Android的了解一些前端js等还是很有好处的)
rexxar-android 是豆瓣的混合开发框架 -
有没有用过第三方WebView组件?讲一讲优势
Crosswalk:据说各种流畅、强大,且Cordova在新的版本当中也将默认支持Crosswalk。TBS服务:由腾讯QQ浏览器团队出品。支持“共享X5内核模式”和“独立下载X5内核模式”
1)速度快:相比系统WebView的网页加载速度有近30%的提升;
2)省流量:云端优化技术使流量节省20%;
3)更安全:24小时安全问题解决机制;
4)更稳定:经过亿级用户的使用考验,CRASH率0.15%;
5)集成强大的视频播放器,支持各种视频格式直接打开;
6)适屏排版、字体设置等浏览增强功能的提供;
7)HTML5更完整支持;
8)无系统碎片化问题、更少的兼容性问题 -
WebView与js交互(调用哪些API)
对于Android调用JS代码的方法有2种:
(1)通过WebView的loadUrl()
(2)通过WebView的evaluateJavascript()webview.evaluateJavascript("javascript:sendMsg()", new ValueCallback<String>() { @Override public void onReceiveValue(String value) { if (value != null) { Toast.makeText(MainActivity.this, value, Toast.LENGTH_SHORT).show(); } } });
(3)webview提供的两个方法:setWebViewClient和setWebChromeClient解决进度条问题;前者主要用于处理webView的控制问题,如加载、关闭、错误处理等;后者主要处理js对话框、图标、页面标题等
(4)单独构建一个接口,作为处理js与java的数据交互的桥梁对于JS调用Android代码的方法有3种:
(1)通过WebView的addJavascriptInterface()进行对象映射
(2)通过 WebViewClient 的shouldOverrideUrlLoading ()方法回调拦截 url
(3)通过 WebChromeClient 的onJsAlert()、onJsConfirm()、onJsPrompt()方法回调拦截JS对话框alert()、confirm()、prompt() 消息
(4)给JS可以调用的方法加上@JavascriptInterface的注解 -
关于WebView的优化你知道哪些
(1)内核初始化:第一次打开 Web 页面 , 使用 WebView 加载页面的时候特别慢 ,第二次打开就能明显的感觉到速度有提升 ,为什么 ? 是因为在你第一次加载页面的时候 WebView 内核并没有初始化 , 所以在第一次加载页面的时候需要耗时去初始化 WebView 内核 。提前初始化 WebView 内核
(2)复用 WebView
(3)验证复用 WebView 和提前初始化 WebView 必要性
(4)WebView 独立进程 , 进程预加载
(5)提前显示进度条
(6)开启软硬件加速 -
描述一下WebView的缓存机制
WebView中存在着两种缓存:网页数据缓存(存储打开过的页面及资源)、H5缓存(即AppCache)
网页缓存:
浏览器缓存机制是通过HTTP协议Header里的Cache-Control(或Expires)和Last-Modified(或 Etag)等字段来控制文件缓存的机制。关于这几个字段的作用和浏览器的缓存更新机制LOAD_CACHE_ONLY: 不使用网络,只读取本地缓存数据
LOAD_DEFAULT: 根据cache-control决定是否从网络上取数据。
LOAD_CACHE_NORMAL: API level 17中已经废弃, 从API level 11开始作用同LOAD_DEFAULT模式
LOAD_NO_CACHE: 不使用缓存,只从网络获取数据.
LOAD_CACHE_ELSE_NETWORK,只要本地有,无论是否过期,或者no-cache,都使用缓存中的数据。建议缓存策略为,判断是否有网络,有的话,使用LOAD_DEFAULT,无网络时,使用LOAD_CACHE_ELSE_NETWORK。
H5缓存:
H5缓存主要包括了App Cache、DOM Storage、Local Storage、Web SQL Database 存储机制
根据setAppCachePath(String appCachePath)提供的路径,在H5使用缓存过程中生成的缓存文件。
无模式选择,通过setAppCacheEnabled(boolean flag)设置是否打开。默认关闭,即,H5的缓存无法使用。AppCache工作的原理:当一个设置了manifest文件的html页面被加载时,CACHE MANIFEST指定的文件就会被缓存到浏览器的App Cache目录下面。当下次加载这个页面时,会首先应用通过manifest已经缓存过的文件,然后发起一个加载xxx.appcache文件的请求到服务器,如果xxx.appcache文件没有被修改过,那么服务器会返回304 Not Modified给到浏览器,如果xxx.appcache文件被修改过,那么服务器会返回200 OK,并返回新的xxx.appcache文件的内容给浏览器,浏览器收到之后,再把新的xxx.appcache文件中指定的内容加载过来进行缓存。
-
WebView的内核是什么
在Android 4.4以下(不包含4.4)系统WebView底层实现是采用WebKit内核(一个开源的浏览器引擎),而在Android 4.4及其以上Google 采用了chromium(Chromium 是 Google 的chrome浏览器背后的引擎,其目的是为了创建一个安全、稳定和快速的通用浏览器)作为系统WebView的底层内核支持 -
描述一下Webview的作用
WebView 是一个用来显示 Web 网页的控件,继承自 AbsoluteLayout,和使用系统其他控件没什么区别,它是一个微型浏览器,包含一个浏览器该有的基本功能
(1)可以打开远程URL页面,也可以加载本地HTML数据
(2)可以无缝的在java和javascript之间进行交互操作
(3)高度的定制性,可根据开发者的需要进行多样性定制 -
Java和JS的相互调用怎么实现,有做过什么优化吗?
对于Android调用JS代码的方法有2种:
(1)通过WebView的loadUrl()
(2)通过WebView的evaluateJavascript()对于JS调用Android代码的方法有3种:
(1)通过WebView的addJavascriptInterface()进行对象映射
(2)通过 WebViewClient 的shouldOverrideUrlLoading ()方法回调拦截 url
(3)通过 WebChromeClient 的onJsAlert()、onJsConfirm()、onJsPrompt()方法回调拦截JS对话框alert()、confirm()、prompt() 消
Application、AndroidManifest、Context
-
Application 和 Activity 的 context 对象的区别
(1)生命周期不一样
(2)Application 不能showDialog
(3)Application startActivity时必须new一个Task
(4)Application layoutInflate直接使用默认主题,可能与当前主题不一样 -
AndroidManifest的作用与理解
包括的信息:
(1)manifest:根节点,描述了包名,版本号等。
(2)application:包含package中application级别组件声明的根节点。
(3)activity:Activity是用来与用户交互的主要工具。
(4)receiver:IntentReceiver能使的application获得数据的改变或者发生的操作,即使它当前不在运行。
(5)service:Service是能在后台运行任意时间的组件。
(6)provider:ContentProvider是用来管理持久化数据并发布给其他应用程序使用的组件。
(7)uses-permission:请求你的package正常运作所需赋予的安全许可。
(8)permission: 声明了安全许可来限制哪些程序能你package中的组件和功能。
(9)uses-feature:使用到的硬件信息,如nfc
(10)upports-screens:支持的屏幕类型
(11)meta-data:data数据
(12)instrumentation:声明了用来测试此package或其他package指令组件的代码。 -
讲解一下Context
Context是一个抽象基类,我们通过它访问当前包的资源(getResources、getAssets)和启动其他组件(Activity、Service、Broadcast)以及得到各种服务(getSystemService),当然,通过Context能得到的不仅仅只有上述这些内容。对Context的理解可以来说:Context提供了一个应用的运行环境,在Context的大环境里,应用才可以访问资源,才能完成和其他组件、服务的交互,Context定义了一套基本的功能接口,我们可以理解为一套规范,而Activity和Service是实现这套规范的子类,这么说也许并不准确,因为这套规范实际是被ContextImpl类统一实现的,Activity和Service只是继承并有选择性地重写了某些规范的实现。 -
Application类的作用
(1)Application是一个基类,这个基类的作用是获取整个App的状态,我们需要自己定义一个类来继承这个基类。
(2)定义一些全局的和一些上下文都要用到的变量和方法
(3)数据传递、数据共享和数据缓存
(4)初始化一些资源 -
Android应用里有几种Context对象,
Application、Activity、Service、ContentProvider、BroadcastReceiver这几种的Context,前三种是Context的实现类 -
进程和 Application 的生命周期;
大多数情况下,每个Android的Application都运行在它自己的Linux进程里。这个过程是为应用程序在某些代码需要运行时创建的,并且将一直运行,直到不再需要它,系统需要回收内存供其他应用程序使用为止
Android的一个不同寻常的基本特性是应用程序过程的生命周期不受应用程序本身的直接控制。
相反,系统需要通过系统了解应用程序的运行部分的组合、这些东西对用户的重要性以及系统中可用的总内存数量
混淆、反编译、
-
Android反编译与混淆
反编译:
(1)首先需要下载工具:dex2jar(这个工具用于将dex文件转换成jar文件)、jd-gui(这个工具用于将jar文件转换成java代码)、apktool(用于最大幅度地还原APK文件中的9-patch图片、布局、字符串等等一系列的资源,主要下载apktool.bat和apktool.jar文件)
(2)解压dex2jar,将apk解压手的classes.dex文件复制到dex2jar的解压目录下
(3)通过cmd命令进入到该目录,执行d2j-dexjar classes.dex
,成功后就会转换出一个jar文件
(4)接着用jd-gui打开这个jar文件(此时代码的解析就成功了)
(5)接着反编译资源文件,将apk复制到与apktool相同的目录下
(6)然后通过cmd在该目录下执行apktool d Demo.apk
,然后目录下就会出现项目工程文件夹混淆:
(1)使用AS自带的混淆:build.gradle中minifyEnabled的值设为true
(2)自己实现混淆规则:proguard-android.txt文件 -
代码混淆是干嘛的
将计算机程序的代码,转换成一种功能上等价,但是难于阅读和理解的形式
代码混淆的主要目的是为了保护源代码,阻止反向工程。反向工程会带来许多问题,诸如知识产权泄露,程序弱点暴露易受攻击等。使用即时编译技术的语言,如Java、C#所编写的程序更容易受到反向工程的威胁
APP启动过程、apk安装过程、apk打包过程、系统启动过程
-
App启动流程,从点击桌面开始
①点击桌面App图标,Launcher进程采用Binder IPC向system_server进程发起startActivity请求;
②system_server进程接收到请求后,向zygote进程发送创建进程的请求;
③Zygote进程fork出新的子进程,即App进程;
④App进程,通过Binder IPC向sytem_server进程发起attachApplication请求
⑤system_server进程在收到请求后,进行一系列准备工作后,再通过binder IPC向App进程发送scheduleLaunchActivity请求;
⑥App进程的binder线程(ApplicationThread)在收到请求后,通过handler向主线程发送LAUNCH_ACTIVITY消息;
⑦主线程在收到Message后,通过发射机制创建目标Activity,并回调Activity.onCreate()等方法。
⑧到此,App便正式启动,开始进入Activity生命周期,执行完onCreate/onStart/onResume方法,UI渲染结束后便可以看到App的主界面。 -
描述清点击 Android Studio 的 build 按钮后发生了什么
build过程即执行gradle task 打包生成apk的过程:
(1)通过appt工具,将资源文件生成R.java文件;将aild文件转换成对应的java文件
(2)编译java文件,生成.class文件
(3)将.class文件转换成Android虚拟机支持的.dex文件
(4)通过apkbuilder将dex文件和编译后的资源文件生成apk文件
(5)对apk进行签名和对齐 -
大体说清一个应用程序安装到手机上时发生了什么
(1) 拷贝apk文件到指定目录
在Android系统中,apk安装文件是会被保存起来的,默认情况下,用户安装的apk首先会被拷贝到 /data/app 目录下。
/data/app目录是用户有权限访问的目录,在安装apk的时候会自动选择该目录存放用户安装的文件,而系统出厂的apk文件则被放到了 /system 分区下,包括 /system/app,/system/vendor/app,以及 /system/priv-app 等等,该分区只有Root权限的用户才能访问,这也就是为什么在没有Root手机之前,我们无法删除系统出厂的app的原因了。(2) 解压apk,拷贝文件,创建应用的数据目录
为了加快app的启动速度,apk在安装的时候,会首先将app的可执行文件(dex)拷贝到 /data/dalvik-cache 目录,缓存起来。
然后,在/data/data/目录下创建应用程序的数据目录(以应用的包名命名),存放应用的相关数据,如数据库、xml文件、cache、二进制的so动态库等等。(3) 解析apk的AndroidManifinest.xml文件
Android系统中,也有一个类似注册表的东西,用来记录当前所有安装的应用的基本信息,每次系统安装或者卸载了任何apk文件,都会更新这个文件。这个文件位于如下目录:
/data/system/packages.xml
系统在安装apk的过程中,会解析apk的AndroidManifinest.xml文件,提取出这个apk的重要信息写入到packages.xml文件中,这些信息包括:权限、应用包名、APK的安装位置、版本、userID等等。
由此,我们就知道了为啥一些应用市场和软件管理类的app能够很清楚地知道当前手机所安装的所有的app,以及这些app的详细信息了。
另外一件事就是Linux的用户Id和用户组Id,以便他可以获得合适的运行权限。
以上这些都是由PackageServiceManager完成的,下面我们会重点介绍PackageServiceManager。(4) 显示快捷方式
这些应用程序只是相当于在PackageManagerService服务注册好了,如果我们想要在Android桌面上看到这些应用程序,还需要有一个Home应用程序,负责从PackageManagerService服务中把这些安装好的应用程序取出来,并以友好的方式在桌面上展现出来,例如以快捷图标的形式。在Android系统中,负责把系统中已经安装的应用程序在桌面中展现出来的Home应用程序就是Launcher了 -
App 是如何沙箱化,为什么要这么做;
(1)沙箱化可以提升安全性和效率
(2)Android的底层内核为Linux,因此继承了Linux良好的安全性,并对其进行了优化。在Linux中,一个用户对应一个uid,而在Android中,(通常)一个APP对应一个uid,拥有独立的资源和空间,与其他APP互不干扰。如有两个APP A和B,A并不能访问B的资源,A的崩溃也不会对B造成影响,从而保证了安全性和效率 -
系统启动流程
Zygote进程 –> SystemServer进程 –> 各种系统服务 –> 应用进程
(1)Bootloader引导:主要作用是启动Linux内核
(2)Linux kernel启动
(3)Init进程的启动:一个由内核启动的用户级进程,启动过程就是代码init.c中main函数执行过程:system\core\init\init.c,在函数中执行了:文件夹建立,挂载,rc文件解析,属性设置,启动服务,执行动作,socket监听……,在rc文件解析中会启动servicemanager服务和Zygote进程
(4)servicemanager服务:用来管理系统中所有的binder service,最主要的管理就是,注册添加服务,获取服务。所有的Service使用前都必须先在servicemanager中进行注册
(5)Zygote进程的启动:这个进程起来才会建立起真正的Android运行空间
(6)Android启动,Zygote启动
(7)SystemServer启动
(8)ActivityManagerService启动总结:
当Android系统第一次启动时,和Windows系统一样都有一个类似于引导系统启动的程序,引导系统启动。Android系统第一个启动的进程是Zygote(孵化的意思)进程,由他负责再启动其他进程,随之而来的是创建各种需要的文件夹,初始化各种硬件设备和服务,硬件设备包括传感器,显示设备,声音设备等等,服务就是我们平时用的WindowServiceManager,ActivityServiceManager,他们都在SystemServer的一个内部类ServerThread(是一个线程)的run方法中被初始化,保存在Map中。之后调用ActivityManagerService的resumeTopActivityLocked方法打开第一个Activty应用,这个应用便是我们的桌面应用,至此Android系统启动完毕。Android内核解读-Android系统的开机启动过程
Android系统启动流程(四)Launcher启动过程与系统启动流程 -
应用安装过程
APK的安装流程
(1)解压文件到data/app目录下
(2)资源管理器加载资源文件
(3)解析解析AndroidManifest文件,并在/data/data/目录下创建对应的应用数据目录。
(4)然后对dex文件进行优化,并保存在dalvik-cache目录下。
(5)将AndroidManifest文件解析出的四大组件信息注册到PackageManagerService中。
(6)安装完成后,发送广播。 -
对于应用更新这块是如何做的?(灰度,强制更新,分区域更新)
灰度:
(1)找单一渠道投放特别版本。
(2)做升级平台的改造,允许针对部分用户推送升级通知甚至版本强制升级。
(3)开放单独的下载入口。
(4)是两个版本的代码都打到app包里,然后在app端植入测试框架,用来控制显示哪个版本。测试框架负责与服务器端api通信,由服务器端控制app上A/B版本的分布,可以实现指定的一组用户看到A版本,其它用户看到B版本。服务端会有相应的报表来显示A/B版本的数量和效果对比。最后可以由服务端的后台来控制,全部用户在线切换到A或者B版本~无论哪种方法都需要做好版本管理工作,分配特别的版本号以示区别。灰度版最好有收回的能力,一般就是强制升级下一个正式版
强制更新:
一般的处理就是进入应用就弹窗通知用户有版本更新,弹窗可以没有取消按钮并不能取消。这样用户就只能选择更新或者关闭应用了,当然也可以添加取消按钮,但是如果用户选择取消则直接退出应用。增量更新:
bsdiff:二进制差分工具bspatch是相应的补丁合成工具,根据两个不同版本的二进制文件,生成补丁文件.patch文件。通过bspatch使旧的apk文件与不定文件合成新的apk。 不足:要区分版本,内置及版本相同破解版apk无法增量更新,最好进行sha1sum校验,保证基础包的一致性 -
Zygote和System进程的启动过程
Zygote:
(1)注册Zygote的socket监听端口,应用接收启动应用程序的消息
(2)调用preload()方法加载系统资源,包括预加载类,Framework资源等
(3)调用startSystemServer()方法启动SystemServer进程
(4)调用runSelectLoop()方法进入监听和接收消息循环 -
为什么Zygote死掉之后会重启呢?
init进程启动后将进入无限循环以监听init.rc中启动的service状态,如发现有service退出则会重新启动该service,在init解析init.rc时,Zygote进程作为一个服务被定义,且被声明为自动重启。因此一旦Zygote进程退出,则init会收到子进程退出信号从而重新启动zygote服务,进而Zygote启动System Server。同样,在System server被Zygote作为子进程启动后,Zygote通过信号监听该子进程状态,一旦退出Zygote将会杀死自身等待init再次运行。另外system server进程将监听service manager进程,如service manager退出则杀掉自身从而导致zygote被重启 -
了解APK的打包流程吗,描述一下?
(1)编译器将您的源代码转换成 DEX(Dalvik Executable) 文件(其中包括运行在 Android 设备上的字节码),将所有其他内容转换成已编译资源
(2)APK 打包器将 DEX 文件和已编译资源合并成单个 APK。不过,必须先签署 APK,才能将应用安装并部署到 Android 设备上
(3)APK 打包器使用调试或发布密钥库签署您的 APK
(4)在生成最终 APK 之前,打包器会使用 zipalign 工具对应用进行优化,减少其在设备上运行时的内存占用。 -
Android的多渠道打包你了解吗
渠道包就是要在安装包中添加渠道信息,也就是channel,对应不同的渠道,例如:小米市场、360市场、应用宝市场等
产品在不同的应用市场可能有不同的统计需求,需要为每个应用市场的Android包设定一个可以区分应用市场的标识,这个为Android包设定应用市场标识的过程就是多渠道打包。 -
Android的apk加固你有了解吗
对源Apk进行加密,然后在套上一层壳:我们拿到需要加密的Apk和自己的壳程序Apk,然后用加密算法对源Apk进行加密在将壳Apk进行合并得到新的Dex文件,最后替换壳程序中的dex文件即可,得到新的Apk,那么这个新的Apk我们也叫作脱壳程序Apk.他已经不是一个完整意义上的Apk程序了,他的主要工作是:负责解密源Apk.然后加载Apk,让其正常运行起来。加固方式:
(1)proguard混淆
(2)签名比对验证
(3)ndk编译.so动态库
(4)代码动态加载APK反逆向之二:四种基本加固方式
Android中的Apk的加固(加壳)原理解析和实现
Android APK加固完善篇 -
打包签名流程,keystore是用来干嘛的,二次打包。包名一样,签名不一样可以同时安装吗;
Keytool 是一个有效的安全钥匙和证书的管理工具.
Java 中的 keytool.exe (位于 JDK\Bin 目录下)可以用来创建数字证书,所有的数字证书是以一条一条(采用别名区别)的形式存入证书库的中,证书库中的一条证书包含该条证书的私钥,公钥和对应的数字证书的信息。证书库中的一条证书可以导出数字证书文件,数字证书文件只包括主体信息和对应的公钥。
Keytool 把钥匙和证书储存到一个keystore.默任的实现keystore的是一个文件.它用一个密码保护钥匙.Keystore可理解为一个容器,存放开发者信息、私钥、公钥的容器不可以同时安装,包名一样代表同一个应用,签名不一样只是代表了不同的开发人员
其他
-
Asset目录与res目录的区别
(1)res目录下的资源文件会在R文件中生成对应的id,asset不会
(2)res目录下的文件在生成apk时,除raw(即res/raw)目录下文件不进行编译外,都会被编译成二进制文件;asset目录下的文件不会进行编译
(3)asset目录允许有子目录 -
Android中assets文件夹与raw文件夹的区别
(1)两者目录下的文件在打包后会原封不动的保存在apk包中,不会被编译成二进制
(2)res/raw中的文件会被映射到R.java文件中,访问的时候直接使用资源ID即R.id.filename;assets文件夹下的文件不会被映射到R.java中,访问的时候需要AssetManager类
(3)res/raw不可以有目录结构,而assets则可以有目录结构,也就是assets目录下可以再建立文件夹
(4)读取res/raw下的文件资源,通过InputStream is = getResources().openRawResource(R.id.filename);
进行写操作
(5)读取assets下的文件资源,通过以下方式获取输入流来进行写操作AssetManager am = null; am = getAssets(); InputStream is = am.open("filename");
-
如何一键更换主题(答出两种)
(1)将主题包(图片与配置)存到SD卡上(可通过下载或手动放入指定目录),在代码里强制从本地文件创建图片与配置文字大小、颜色等信息
(2)Android平台独有的主题设置功能,在values文件夹中定义若干种style,在Activity的onCreate中使用setTheme方法设置主题
(3)将主题包做成APK的形式,使用远程Context的方式访问主题包中的资源
(4)类似小米的深度主题,修改framework中Resources类获取资源的流程,将资源重定向到主题包中 -
Android中开启摄像头的主要步骤
调用系统的摄像头:
(1)创建一个File对象用于存储拍照后的照片
(2)通过Intent,启动系统自带的相机Intent intent = new Intent("android.media.action.IMAGE_CAPTURE"); intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri); startActivityForResult(intent, 11);
(3)onActivityResult中处理回调的结果
自定义Camera:
(1)打开相机,即实例化Camera对象,Camera camera = Camera.open();
(2)设置Camera的相关参数,Camera.Parameters parameters = camera.getParameters();
(3)打开预览,camera.setPreviewDisplay(surfaceholder); camera.startPreview();
(4)获取图片,这里只是从预览中获取因此使用,camera.setPreviewCallback(new Camera.PreviewCallback(){……..});
(5)停止预览,释放相机,camera.stopPreview();camera.release(); -
统计启动时长,标准
(1)物理统计:通过高速相机,从点击launcher上面的图标开始,到MainActivity的第一个可见帧,算作启动时间。
(2)adb 统计:adb shell am start -w pageage/activityname
(3)线上版本统计:applicaiton 创建,可以从attachBaseContext()开始,得到startTime。MainActivity的第一个可视画面,onResume其实还没有看到画面,最合适的回调是onWindowFocusChanged,也就是获得焦点。但是这个回调需要做适当的过滤,就能获得endTime。所以冷启动就是两个时间差。热启动的startTime 就是MainActivity的onRestart。 -
画出 Android 的大体架构图
-
MediaPlayer的生命周期图画一下
(1)Idle 状态:当使用new()方法创建一个MediaPlayer对象或者调用了其reset()方法时,该MediaPlayer对象处于idle状态。这两种方法的一个重要差别就是:如果在这个状态下调用了getDuration()等方法(相当于调用时机不正确),通过reset()方法进入idle状态的话会触发OnErrorListener.onError(),并且MediaPlayer会进入Error状态;如果是新创建的MediaPlayer对象,则并不会触发onError(),也不会进入Error状态。(2)End 状态:通过release()方法可以进入End状态,只要MediaPlayer对象不再被使用,就应当尽快将其通过release()方法释放掉,以释放相关的软硬件组件资源,这其中有些资源是只有一份的(相当于临界资源)。如果MediaPlayer对象进入了End状态,则不会在进入任何其他状态了。
(3)Initialized 状态:这个状态比较简单,MediaPlayer调用setDataSource()方法就进入Initialized状态,表示此时要播放的文件已经设置好了。
(4)Prepared 状态:初始化完成之后还需要通过调用prepare()或prepareAsync()方法,这两个方法一个是同步的一个是异步的,只有进入Prepared状态,才表明MediaPlayer到目前为止都没有错误,可以进行文件播放。
(5)Preparing 状态:这个状态比较好理解,主要是和prepareAsync()配合,如果异步准备完成,会触发OnPreparedListener.onPrepared(),进而进入Prepared状态。
(6)Started 状态:显然,MediaPlayer一旦准备好,就可以调用start()方法,这样MediaPlayer就处于Started状态,这表明MediaPlayer正在播放文件过程中。可以使用isPlaying()测试MediaPlayer是否处于了Started状态。如果播放完毕,而又设置了循环播放,则MediaPlayer仍然会处于Started状态,类似的,如果在该状态下MediaPlayer调用了seekTo()或者start()方法均可以让MediaPlayer停留在Started状态。
(7)Paused 状态:Started状态下MediaPlayer调用pause()方法可以暂停MediaPlayer,从而进入Paused状态,MediaPlayer暂停后再次调用start()则可以继续MediaPlayer的播放,转到Started状态,暂停状态时可以调用seekTo()方法,这是不会改变状态的。
(8)Stop 状态:Started或者Paused状态下均可调用stop()停止MediaPlayer,而处于Stop状态的MediaPlayer要想重新播放,需要通过prepareAsync()和prepare()回到先前的Prepared状态重新开始才可以。
(9)PlaybackCompleted状态:文件正常播放完毕,而又没有设置循环播放的话就进入该状态,并会触发OnCompletionListener的onCompletion()方法。此时可以调用start()方法重新从头播放文件,也可以stop()停止MediaPlayer,或者也可以seekTo()来重新定位播放位置。
(10)Error状态:如果由于某种原因MediaPlayer出现了错误,会触发OnErrorListener.onError()事件,此时MediaPlayer即进入Error状态,及时捕捉并妥善处理这些错误是很重要的,可以帮助我们及时释放相关的软硬件资源,也可以改善用户体验。通过setOnErrorListener(android.media.MediaPlayer.OnErrorListener)可以设置该监听器。如果MediaPlayer进入了Error状态,可以通过调用reset()来恢复,使得MediaPlayer重新返回到Idle状态。
-
Android新特性有哪些(5.0 6.0 7.0)
5.0:
(1)全新 Material Design 设计风格
(2)支持多种设备(手机、平板电脑、笔记本电脑、智能电视、汽车、智能手表甚至是各种家用电子产品)
(3)全新的通知中心设计(在锁屏界面也可以直接查看通知消息了,用户还可以直接在锁屏的情况下就行回复或进入应用。)
(4)支持 64 位 ART 虚拟机
(5)Project Volta 电池续航改进计划: 增加了 Battery Saver 模式,在低电量的时候系统会自动降低屏幕亮度、限制自动更换背景等功能
(6)全新的“最近应用程序”:除了界面风格设计的改变之外,新的最近应用界面还借鉴了 Chrome 浏览器的理念,采用单独的标签展示方式。更重要的是,谷歌已经向开发者开放了 API,所以第三方开发人员可以利用这个改进为特定的应用增加全新的功能
(7)新的 API 支持,蓝牙 4.1、USB Audio、多人分享等其它特性
(8)改进搜索6.0:
(1)大量漂亮流畅的动画:安卓6.0系统增加了大量漂亮的过度动画,可以从视觉上减少卡顿感,给用户带来流畅的体验
(2)动态权限管理
(3)指纹识别(Fingerprint Support)
(3)APP关联(App Links)
(4)Android pay
(5)电源管理、全新的电源键菜单:一般来说,安卓的电源键菜单都是关机/重启/飞行,安卓6.0变成了关机/重启/紧急,关机和重启就不用赘述了,这个紧急模式是为了手机快没电的时候设计的,相当于飞行模式的高级版,可以关闭一切耗电应用,尽最大可能节省电量。
(6)相机新增专业模式:一直以来,原生的安卓相机都长被吐槽太过简单甚至简陋了,在此次的安卓6.0中,相机中新增了Pro专业模式,增加了快门速度调节和曝光度调节等新功能
(7)可自定义锁界面样式:支持电话、信息、相机等快捷方式在锁屏界面的定制,用户可以根据自己的喜好调整这些图标的位置,或者开启或关闭这些快捷方式
(8)全新的快速设置风格:不但是锁屏界面可以定制,安卓6.0还采用了全新的快速面板的色彩方案,用户可以通过更换主题换颜色
(9)支持快速充电的切换
(10)支持文件夹拖拽应用
(11)Now on Tap功能:“Now on Tap ”功能,是指将Google Now(一种语音助手)作为底层植入到安卓6.0系统中,用户只要只要双击home键启动Google Now,“这意味着用户随时都能启动搜索功能,目前暂时不知道这个功能进入国内会不会阉割掉
(12)支持RAW格式照片7.0(N):
(1)分屏多任务支持
(2)画中画
(3)通知栏快速回复
(4)OpenJDK替换Java API
(5)采用了一项具有实时代码剖析功能的ARI JIT编译器,它能够在安卓应用程序在运行时不断提高自身的性能
(6)夜间深色主题模式
(7)流量保护模式
(8)改进的Doze休眠机制
(9)改进的Doze休眠机制
(10)系统级电话黑名单功能:Android7.0将电话拦截功能变成了一个系统级功能。其它应用可以调用这个拦截名单,但只有个别应用可以写入,包括拨号应用、默认的短信应用等。被拦截号码将不会出现在来电记录中,也不会出现通知。另外用户也可以通过账户体系备份和恢复这个拦截名单,以便快速导入其它设备或账号
(11)菜单键快速应用切换android 8.0 有哪些新特性:
(1)后台执行限制
(2)Android 后台位置限制
(3)Notification channels
(4)自适应icon
(5)键盘导航(Keyboard navigation)
(6)Java8语言API和运行时(runtime)优化
(7)WebView增强android 9.0:
(1)WiFi RTT功能——复杂地形精确导航
(2)显示剪切——支持刘海屏
(3)通知优化——操作更多样,内容更丰富
(4)支持多摄像机和相机共享
(5)支持图像媒体后期处理
(6)支持HDR VP9和HEIF
(7)神经网络API 1.1
(8)改进表单自动填充
(9)安全增强:Android P引入了许多新的安全功能,包括统一的指纹验证对话框和敏感交易的高确信度的用户确认。应用程序内的指纹认证UI也将会更加一致
(10)支持客户端侧Android备份加密
(11)Accessibility优化
(12)新的Rotation方案 -
在你平时写 App 代码时有没有什么经验可以减少方法数?谈谈其原理?
(1)执行Proguard:可以从应用中剔除无用的代码,但通常只在发布构建时执行它来节省宝贵的构建时间。如果对你不是问题,你也可以在调试版本中启动Proguard
(2)选择合适的库
(3)替换已存在的库
(4)减少库大小:只使用需要部分的库
(5)避免在内部类中访问外部类的私有方法/变量:当在Java内部类(包括内部匿名类)中访问外部类的私有方法/变量时,编译器会生成额外的方法,这也会增加方法数,建议编码时尽量避免。
(6)避免调用派生类中的未被覆盖(override)的方法 -
有没有遇到64k问题,为什么会出现这个问题,如何解决?
随着功能的增加,方法数增多,就会出现所谓的64k方法数问题,Android APK文件本质上是一个压缩文件,它包含的classes.dex文件是Dalvik字节码文件,这个dex文件中存放的就是编译后的Java代码。Dalvik可执行文件规范限制了单个.dex文件最多引用的方法数是65536个。解决:MultiDex解决方案解决方法数超限问题
-
如何提高代码质量?
(1)命名规范
(2)代码规范
(3)注释位置、内容规范
(4)break语句要有。覆写时添加@Override
(5)显式指明操作符的优先级 -
Android系统的有哪些安全机制
两种安全机制模型:
(1)使用显示定义,经用户授权的应用权限控制机制。系统规范并强制各类应用程序的行为准则与权限许可。
(2)提供了应用程序的签名机制,实现了应用程序之间的信息信任和资源共享。- 内存管理 – LMK(低内存清理)
(1)Android内存管理机制基于Linux的OOM(out of memory killer)机制,实现了LMK(low memory killer)机制
(2)引入Android独有的共享内存机制Ashmen,该机制具有清理不在使用的共享内存区域的能力 - 访问控制 – DAC(自主访问控制)
(1)Linux系统默认采用ACM(访问控制机制)为DAC(自主访问控制)
(2)Android直接继承了Linux的访问控制机制。确保系统同文件与用户数据不受非法访问 - 沙箱隔离
- 权限声明
- 进程通信机制
- 内存管理 – LMK(低内存清理)
-
Android 应用中验证码登陆都有哪些实现方案
从服务器端获取图片,
通过短信服务,将验证码发送给客户端这两种。 -
定位项目中,如何选取定位方案,如何平衡耗电与实时位置的精度
(1)初始定位,Application 持有一个全局的公共位置对象,然后隔一定时间自动刷新位置,每次刷新成功都把新的位置信息赋值到全局的位置对象, 然后每个需要使用位置请求的地方都使用全局的位置信息进行请求。
该方案好处:请求的时候无需再反复定位,每次请求都使用全局的位置对象,节省时间。
该方案弊端:耗电,每隔一定时间自动刷新位置,对电量的消耗比较大
(2)按需定位,每次请求前都进行定位。这样做的好处是比较省电,而且节省资源,但是请求时间会变得相对较长 -
andorid 应用第二次登录实现自动登录
(1)第一次登陆getUserInfo里带一个长效token,该长效token用来判断用户是否登录和换取短token
(2)通过sp存储将长效token保存起来。
(3)接口请求用长效的token换取短token,短token服务端可以根据你的接口最后一次请求作为指示,超时时间为一天。
(4)如果短小token失效在用长效token去替换
(5)长效Token失效,提示用户再次登录 -
一条最长的短信息约占多少byte?
手机短信的长度是由编码决定的,根据国际标准,每条短信最多发送1120位。
如果发送纯英文字符,由于英文ASCII采用7位编码,所以1120位的限额可以传送1120÷7=160个字符。一旦传送的字符中包含中文、日文、韩文等双字节字符,不论中文还是西文,不论全角还是半角,都必须采用2个字节的8位编码,因此1120÷8÷2=70个字符,即最多传送70个字
-
即时通讯是是怎么做的?
在服务端与客户端之间建立一个长连接,使用心跳包 -
MD5是加密方法么,Base64呢
MD5:是一种不可逆的摘要算法,用于生成摘要,无法逆破解到原文。常用的是生成32位摘要,用于验证数据的有效性。比如,在网络请求接口中,通过将所有的参数生成摘要,客户端和服务端采用同样的规则生成摘要,这样可以防止篡改。又如,下载文件时,通过生成文件的摘要,用于验证文件是否损坏。Base64:属于加密算法,是可逆的,经过encode后,可以将decode得到原文。在开发中,有的公司上传图片采用的是将图片转换成Base64字符串,再上传。在做加密相关的功能时,通常会将数据进行Base64加密/解密。
-
Android 桌面的小部件是什么
AppWidget,AppWidgetProvider是Android中提供的用于实现桌面小工具的类 -
两个应用能使用同一个任务栈么?
可以,相同包名,指定同一个进程,Activity指定用一个任务栈 -
子线程中更新UI的方式
(1)用Handler,子线程发消息,通知Handler完成UI更新
(2)用Activity对象的runOnUiThread方法更新
(3)View.post(Runnable r) -
Toast 只能在主线程使用吗
并不一定在主线程,只要 Toast show 的线程有可用 Looper 对象即可(即 Hanlder 可用),主线程默认有 Looper,其他线程默认没有 -
音频合成的具体步骤,以及遇到的一些问题和细节处理。
将输入的每段音频的某个时间点的采样点数值进行相加,即可将声音信号加入到输出的音频中。
流程图注意事项:
(1)需要确保A音频和B音频的采样位数一致。
例如A音频是16位采样位数,B音频是8位采样位数,那么这时是不能直接拼接的,需要转换成相同的采样位数,才能做后续操作。(2)需要确保A音频和B音频的采样率一致。
这个在录音和歌曲拼接时要特别注意,假如录音的音频频率是16000,歌曲的音频是44100,那么两者也是不能直接拼接的,需要转换成相同的采样率,转换采样率可以使用resample库。(3)需要确保A音频和B音频的声道数一致。
当然这个并不是指单声道和双声道的音频不能合成了,事实上录音音频通常是单声道的,而歌曲通常是双声道的。单声道和双声道音频合成,一般是按双声道为基准,需要将单声道音频转换成双声道音频,转换原理也简单,将单声道的采样点数据多复制一份,比如将单声道的ABCD数据转换成双声道的AABBCCDD数据 -
Scroller用过吗,了解它的原理吗?
-
Scroller有什么方法,怎么使用的。
//构造函数 public Scroller (Context context) public Scroller (Context context, Interpolator interpolator) //公共方法 public void abortAnimation () //停止动画。 public boolean computeScrollOffset () //当想要知道新的位置时,调用此函数。如果返回true,表示动画还没有结束。位置改变以提供一个新的位置 public void extendDuration (int extend) //长滚动动画时间。此函数允许当使用setFinalX(int) or setFinalY(int) 时,卷动动作持续更长时间并且卷动更长距离。 public void fling (int startX, int startY, int velocityX, int velocityY, int minX, int maxX, int minY, int maxY) //在fling(译者注:快滑,用户按下触摸屏、快速移动后松开)手势基础上开始滚动。滚动的距离取决于fling的初速度。 public final void forceFinished (boolean finished) //强制终止的字段到特定值 public final int getCurrX () //返回当前滚动X方向的偏移 public final int getCurrY () //返回当前滚动Y方向的偏移 public final int getDuration () //返回滚动事件的持续时间,以毫秒计算。 public final int getFinalX () //返回滚动结束位置。仅针对“fling”手势有效 public final int getFinalY () //返回滚动结束位置。仅针对“fling”操作有效 public final int getStartX () //返回滚动起始点的X方向的偏移 public final int getStartY () //返回滚动起始点的Y方向的偏移 public final boolean isFinished () //返回scroller是否已完成滚动。 public void setFinalX (int newX) //设置scroller的X方向终止位置 public void setFinalY (int newY) //设置scroller的Y方向终止位置 public void startScroll (int startX, int startY, int dx, int dy) //以提供的起始点和将要滑动的距离开始滚动。滚动会使用缺省值250ms作为持续时间。 public void startScroll (int startX, int startY, int dx, int dy, int duration) //以提供的起始点和将要滑动的距离开始滚动。 public int timePassed () //返回自滚动开始经过的时间
-
聊一聊安卓中特有的集合
SparseArray:SparseArray比HashMap更省内存,在某些条件下性能更好,主要是因为它避免了对key的自动装箱(int转为Integer类型),它内部则是通过两个数组来进行数据存储的,一个存储key,另外一个存储value,为了优化性能,它内部对数据还采取了压缩的方式来表示稀疏数组的数据,从而节约内存空间ArrayMap:是一个< key,value >映射的数据结构,它设计上更多的是考虑内存的优化,内部是使用两个数组进行数据存储,一个数组记录key的hash值,另外一个数组记录Value值,它和SparseArray一样,也会对key使用二分法进行从小到大排序,在添加、删除、查找数据的时候都是先使用二分查找法得到相应的index,然后通过index来进行添加、查找、删除等操作,所以,应用场景和SparseArray的一样,如果在数据量比较大的情况下,那么它的性能将退化至少50%
-
如何将Activity设置为窗口模式
为窗口的activity中添加属性:android:theme=”@android:style/Theme.Dialog” -
两个不同的 app 之间如何交互
(1)广播
(2)AIDL
(3)文件共享
(4)SharedPreference
(5)ContentProvider
(6)Messenger
(7)Socket
(8)Intent