存储沙箱化, 每一个应用访问本身沙箱内的文件。访问别的沙箱解决办法相似于FileUriExposedException,用FileProvider将file转换为content传递java
设备惟一id获取,谷歌开放了新的设备id获取方式,目前不一样手机获取的方式不一样之前的 READ_PHONE_STATE
方式变为了READ_PRIVILEGED_PHONE_STATE
android
非SDK接口的限制,设置禁止对非sdk接口的依赖,主要是一些第三方的热修复,加固方案使用了这些被限制的SDK接口git
限制了明文流量,只有使用https才能够访问github
Android 6.0(M) ,完整的权限控制,危险权限须要动态获取。 API 检测是否有受权,申请受权,权限失败解释面试
Android7.0 (N) , 删除了三种静态广播 网络状态新照片和新视频算法
Android8.0(P),自适应的图标类型,推送和通知的管理数据库
Retrofit使用Retrofit.create(Class)
方法建立出Service 接口对象,使retrofit能够在Service中进行参数配置编程
然而在Retrofit.create()
方法中,是使用Proxy.newProxyInstance()
方法来建立Service接口实例,这个实例实现了全部的接口方法,调用实例的InvocationHandler
成员变量的invoke()
方法,InvocationHandler
对象就会代理接口中的是设定。设计模式
invoke()
中的逻辑:api
loadServiceMethod(method)
将interface中的方法信息读取并初步分析生成ServiceMethod
OkHttpCall<Object> okHttpCall = new OkhttpCall<>(serviceMethod,args)
负责将ServiceMethod封装到retrofit2.call
对象,该对象在enqueue等的时候会调用okhttp.call
对象,由它来进行网络请求的发起
在serviceMethod.adapt(okHttpCall)
中,serviceMethod里面的的callAdapter对象把okHttpCall
转为新的retrofit.call
类型对象。这个call中,后台线程发起的请求的返回中,调用主线程回调方法。还能够生成rxjava的Obervable等
首先创造出一个OkhttpClient进行网络配置,而后建立一个Request传入client,client建立一个call开始发起请求。
Dispatcher dispatcher
:调度器,调度后台发起的网络请求,可设置主机请求数和后台请求数
List<Protocol> protocols
:支持的应用层协议版本
List<ConnectionSpec> connectionSpecs
:应用层支持的Socket设置,即便用明文传输 仍是TLS
List<Interceptor> interceptors
大多数的Interceptor都会配置在这里
List<Interceptor> networkInterceptors
:直接和网络请求交互的Interceptor配置到这里
CookieJar cookieJar
:管理Cookie的控制器,提供了基础的存取判断,剩下的须要本身实现
Cache cache
:Cache 存储的配置。默认是没有,若是须要⽤,得⾃⼰配置出 Cache 存储的⽂件位置以及存储空间上限。
HostnameVerifier hostnameVerifier
:⽤于验证 HTTPS 握⼿过程当中下载到的证书所属者是否和⾃⼰要访问的主机名⼀致。
Authenticator[ɔːˈθɛntɪkeɪtə] authenticator
:用于自动从新认证。配置后收到401时会直接调用authenticator,从新发起请求
OKHttp3经过拦截链的设计,让请求分红5个拦截器去处理,拦截器各司其职,扩展性很是高。拦截链是从自定义的拦截器开始,而后再到默认的5个拦截器。通常状况下咱们想打印网络请求日志,因此能够自定义Log拦截器,若是要给全部请求添加Header,一样能够自定义Header拦截器。
步骤: 步骤一:主线程匿名内部类建立Handler对象 步骤二:建立消息对象 经过Message message=Message.obtain()
建立一个message 步骤三:发送消息mHandler.sendMessage(msg);
UI线程建立一个Handler对象,而后在子线程中sendMessage发送到在主线程的MessageQueue中,最后经过Lopper(消息泵)对象去除MessageQueue中的消息,分发回Handler的handleMessage()
中
线程池用于线程的调度、复用;handler用于异步通讯
内部有一个SerialExecutor任务队列线程池(任务调度)
和THREAD_POOL_EXECUTOR执行线程池(真正执行任务的线程池)
和内部handler(异步通讯+消息传递)
,
AsynTask属于抽象类需实现子类 execute(Params... params)
:触发执行异步线程任务,必需在UI线程中调用 onPreExecute()
:执行线程任务前的操做执行任务前调用,如显示进度条等操做 doInBackground(Params params)
:接受输入参数,执行任务中的耗时操做,返回执行结果。 onPostExecute(Resule result)
:接收线程任务执行结果,显示到UI组件 onCancelled
:将异步任务设置为取消状态,doInBackground()
中判断终止任务 点击查看AsynTask原理具体说明
同步锁修饰execute()
从而保证AsyncTask中的任务是串行执行的
首先用户触摸View层(好比控件xml啥的都算view)
Controller层(Activity,Fragment)
作出反应去请求 Model层(http, 数据库,sp)
的数据,而后返回数据给C层,C层收到数据后通知View层进行更新
首先用户触摸View层(Activity,Fragment)
如点击请求网络 而后view层调用Presenter(桥梁层)
层去Model层(网络请求数据,数据库数据,sp数据,contentProvider)
拿对应的数据 最后P层经过初始化时持有的View层引用将view的更新通知给V层
将app拆分红不少块,每一个模块都是一个apk,最终打包的时候讲宿主apk和插件apk分开打包,插件apk经过动态下发到宿主apk。 用的是VirtualAPK
1.宿主Module中的build.gradle中添加配置,apply plugin
2.application中进行初始化 3.适当位置加载插件
PluginManager pluginManager = PluginManager.getInstance(base);
File apk = new File(Environment.getExternalStorageDirectory(), "plugin.apk");
if (apk.exists()) {
try {
pluginManager.loadPlugin(apk);
} catch (Exception e) {
e.printStackTrace();
}
} else {
Toast.makeText(getApplicationContext(),"SDcard根目录未检测到plugin.apk插件", Toast.LENGTH_SHORT).show();
}
复制代码
4.加载插件
public void click(View view){
Intent intent = new Intent();
intent.setClassName("com.emm.plugin","com.emm.plugin.Main2Activity");
tartActivity(intent);
}
复制代码
原生apk就可做为插件加载,插件工程编译生成apk后,便可经过宿主app加载,并在宿主中建立LoadedPlugin对象。再次启动就会变得流畅 插件apk须要在宿主Apk中提早占坑,经过Hook Activity的启动过程,“欺上瞒下”启动插件Apk中的Activity,其余三大组件都是经过代理的方式。
应用层 HTTP 、FTP 传输层 TCP、UDP 网络层 IP、ICMP、ARP 数据链路层 FDDI、IEEE 802.1A
Cookie是由服务器端生成,服务器须要客户端保存的内容,放在Set-Cookie
headers里返回,客户端会自动保存 客户端保存的Cookie会在以后的全部请求里携带进Cookie
header里发回给服务器 客户端保存Cookie是按照服务器域名来分类的
简单的说就是Cookies追踪,利用第三方cookie来实现这一的机制 不少第三方做为跨域提供了用户的token
工厂模式:宝马和奔驰类都实现car接口,用CarFactory
返回实例化接口car,至关于一个工厂能够生产不一样类型的实例 模板模式:抽象模板角色类,实现了父类所声明的基本方法。子类实现须要强制实现的逻辑 观察者模式: 1.抽象被观察者接口,声明添加通知删除观察者方法
public interface Observerable {
public void registerObserver(Observer o);
public void removeObserver(Observer o);
public void notifyObserver();
}
复制代码
2.定义一个抽象观察者接口
public interface Observer {
public void update(String message);
}
复制代码
3.定义被观察者,实现了Observerable接口,对接口方法进行了具体实现
public class WechatServer implements Observerable {
//注意到这个List集合的泛型参数为Observer接口,设计原则:面向接口编程而不是面向实现编程
private List<Observer> list;
private String message;
public WechatServer() {
list = new ArrayList<Observer>();
}
@Override
public void registerObserver(Observer o) {
list.add(o);
}
@Override
public void removeObserver(Observer o) {
if(!list.isEmpty())
list.remove(o);
}
//遍历
@Override
public void notifyObserver() {
for(int i = 0; i < list.size(); i++) {
Observer oserver = list.get(i);
oserver.update(message);
}
}
public void setInfomation(String s) {
this.message = s;
System.out.println("微信服务更新消息: " + s);
//消息更新,通知全部观察者
notifyObserver();
}
}
复制代码
4.定义具体观察者,微信公众号具体观察者为用户User
public class User implements Observer {
private String name;
private String message;
public User(String name) {
this.name = name;
}
@Override
public void update(String message) {
this.message = message;
read();
}
public void read() {
System.out.println(name + " 收到推送消息: " + message);
}
}
复制代码
5.编写一个测试类,首先注册了三个用户,ZhangSan、LiSi、WangWu。公众号发布了一条消息"PHP是世界上最好用的语言!",三个用户都收到了消息。 用户ZhangSan看到消息后颇为震惊,果断取消订阅,这时公众号又推送了一条消息,此时用户ZhangSan已经收不到消息,其余用户
public class Test {
public static void main(String[] args) {
WechatServer server = new WechatServer();
Observer userZhang = new User("ZhangSan");
Observer userLi = new User("LiSi");
Observer userWang = new User("WangWu");
server.registerObserver(userZhang);
server.registerObserver(userLi);
server.registerObserver(userWang);
server.setInfomation("PHP是世界上最好用的语言!");
System.out.println("----------------------------------------------");
server.removeObserver(userZhang);
server.setInfomation("JAVA是世界上最好用的语言!");
}
}
复制代码
适配器模式:
ViewStub:宽高都为 0 的不可见 View. 经过延迟加载布局的方式优化布局提高渲染性能,经过setVisibility或者直接调用inflate都会渲染布局文件 ViewPager2:核心为RecyclerView
+LinerLayoutManager
,因此支持横向和竖向的滚动,viewpager2
能够承载fragment,须要继承它提供的FragmentStateAdapter
,还能够完整支持notifyDataSetChanged()
CoordinatorLayout: 1.CoordinatorLayout继承自viewgroup,可是使用相似于framLayout,只有CoordinatorLayout的直接子布局才能响应。 2.是须要CoordinateLayout
+AppBarLayout
+CollapingToolbarLayout
结合才有效果。
<android.support.design.widget.CoordinatorLayout
android:id="@+id/main_content"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.design.widget.AppBarLayout
android:id="@+id/appbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:layout_scrollFlags="scroll|enterAlways"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light"/>
</android.support.design.widget.AppBarLayout>
<android.support.v7.widget.RecyclerView
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior"/>
<android.support.design.widget.FloatingActionButton
android:id="@+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end|bottom"
android:layout_margin="15dp"
android:src="@drawable/add_2"/>
</android.support.design.widget.CoordinatorLayout>
复制代码
scroll|exitUntilCollapsed
,子控件能够向上滚动出NestedScrollView父布局时会折叠到顶端scroll|enterAlways
:只要向下滚动该布局就会显示出来,向上滚动该布局就会收缩scroll|enterAlwaysCollapsed
:向下滚动到最低端时,该布局才会显示出来使用CMake
进行ndk开发,它是一种比nake更高级的编译配置工具,经过CMakeLists.txt,能够控制生成的Makefile,从而控制编译过程、生成源码包、生成当前平台安装包。
.h
文件.so
文件PercentRelativeLayout
、PercentFrameLayout
android:layout_width="0dp"
android:layout_height="0dp"
android:background="#ff0000"
app:layout_heightPercent="30%"
app:layout_widthPercent="70%"
复制代码
ConstraintLayout layout_constraintHorizontal_chainStyle
Guideline
layout_constraintHorizontal_bias layout_constraintVertical_bias
px=dp*density
,动态修改设备的density值,在不一样分辨率下达到相同的像素密度补间动画: 主要经过xml中定义具备旋转、缩放、平移、透明度的动画
Animation animation = AnimationUtils.loadAnimation(MainActivity.this,R.anim.viewanimation);
textView.startAnimation(animation);
复制代码
属性动画: 补间动画只能定义两个关键帧在透明(alpha)、旋转(rorate)、位移(translate)和缩放(scale)这四个属性的变换,可是属性动画能够定义任何属性的变化。 补间动画只能对 UI 组件执行动画,但属性动画能够对任何对象执行动画。
Animator
: 提供建立属性动画的基类,基本不会直接使用这个类。 ValueAnimator
:属性动画用到的主要的时间引擎,负责计算各个帧的属性值。 ObjectAnimator
: ValueAnimator 的子类,对指定对象的属性执行动画。 AnimatorSet
:Animator 的子类,用于组合多个 Animator。
定义:给HTTP增长一个安全层,用于保障HTTP的加密传输,能够接受的对称加密,非对称加密,hash算法 Https在与服务器进行数据交互以前,会与服务器进行一次通讯(握手)
一、浏览器将自身支持的加密算法发送给服务端
二、服务端筛选出一套加密算法,以证书的形式发给浏览器
三、浏览器根验证证书的合法性,据拿到的证书里的公钥加密一串消息发给服务端
四、服务端使用私钥解密信息,验证哈希,并加密响应消息给浏览器
五、浏览器解密响应消息,并对消息进行验证,若是验证经过,则能够进行加密数据交互
解决触摸事件冲突:
外部拦截。ViewGroup重写onInterceptTouchEvent方法,默认不拦截,事件往下分发给子View,若返回true,则拦截这次事件,将事件传给ViewGroup的onTouchEvent处理。
内部拦截。重写子View的dispatchTouchEvent方法,方法中调用getParent().requestDisallowInterceptTouchEvent(true)方法,传true则表明不但愿ViewGroup拦截事件,传false则表明但愿ViewGroup拦截事件。
内部拦截。子View重写onTouchEvent方法,返回true,则子View消费该次事件,返回false,该次事件返回给ViewGroup的onTouchEvent处理。